Golang(11)Web Service - RESTful

Golang(11)Web Service - RESTful

1. Concept
Requests can be matched based on URL host, path, path prefix, schemes, header and query values, HTTP methods or using custom matchers.

URL hosts and paths can have variables with an optional regular expression.

It implements the http.Handler interface so it is compatible with the standard http.ServeMux.
     
router := mux.NewRouter()
router.HandleFunc("/", HomeHandler)
router.HandleFunc("/products", ProductsHandler)

Once the router matches, the handler will be called passing (http.ResponseWriter, http.Requet)as parameters.

Variables in paths follow this pattern, {name} or {name:pattern}.

router.HandleFunc(“/products/{key}”, ProductHandler)
router.HandleFunc(“/articles/{category}/{id:[0-9]+}”, ArticleHandler)

We can fetch all these values from map
vars :=mux.Vars(request)
category := vars[“category"]

Some other matches
router.Host(“www.domain.com”)
router.Host(“{subdomain:[a-z]+}.domain.com”)

router.PathPrefix(“/products/“)

router.Methods(“GET”, “POST”)

router.Schemes(“https”)

router.Headers(“X-Requested-With”, “XMLHttpRequest”)

router.Queries(“key”, “value”)

Example:
router.HandleFunc(“/products”, ProductsHandler).Host(“www.domain.com”).Methods(“GET”).Schemes(“http”)

Work with Sub Router
router := mux.NewRouter()
sub := router.Host(“www.domain.com”).Subrouter()
sub.HandleFunc(“/products/“, ProductsHandler)

Name a Router and Build the URL
router := mux.NewRouter()
router.HandleFunc(“/articles/{category}/{id:[0-9]+}”, ArticleHandler).Name(“article”)

url, err := r.Get(“article”).URL(“category”, “technology”, “id”, “42”)
eg: “/articles/technology/42"

2. Installation
>go get github.com/gorilla/mux

Here is the Whole go implementation Class as follow:

package main

import (
     "encoding/json”    //import the json package to marshal and unmarshal JSON
     "fmt"
     "github.com/gorilla/mux”   //here is the router and dispatcher
     "io/ioutil”           //io util to read/write to io
     "net/http”             //handle the http based request and response
)

type Bug struct {           //my demo object in go
     Id        string
     BugNumber string
     BugName   string
     BugDesn   string
}

type BugResult struct {     //my common REST response object
     Bugs   []Bug
     Status string
}

func getBug(w http.ResponseWriter, r *http.Request) {     //get method
     b1 := Bug{Id: "1", BugNumber: "bug1", BugName: "bug1", BugDesn: "desn1"}
     re := BugResult{Status: "Ok", Bugs: []Bug{b1}}
     b, err := json.Marshal(re)                             //marshal the object to JSON
     if err != nil {
          fmt.Fprint(w, "json err: %s", err)
     }
     fmt.Fprint(w, string(b))                //write to the response
}

func updateBug(w http.ResponseWriter, r *http.Request) {
     var b Bug
     c, err := ioutil.ReadAll(r.Body)        //read the string from body and unmarshal
     fmt.Println("updateBug called with Body=" + string(c))

     json.Unmarshal(c, &b)

     fmt.Println("updateBug called with id=" + b.Id)
     fmt.Println("updateBug called with BugNumber=" + b.BugNumber)
     fmt.Println("updateBug called with Bugname=" + b.BugName)
     fmt.Println("updateBug called with BugDesn=" + b.BugDesn)

     re := BugResult{Status: "OK", Bugs: []Bug{b}}
     re_json, err := json.Marshal(re)
     if err != nil {
          fmt.Fprint(w, "json err: %s", err)
     }
     fmt.Fprint(w, string(re_json))
}

func deleteBug(w http.ResponseWriter, r *http.Request) {
     id := mux.Vars(r)["Id”]                                    //get the param from Path
     fmt.Println("deleteBug called with Id = ", id)

     re := BugResult{Status: "OK"}
     b, err := json.Marshal(re)
     if err != nil {
          fmt.Fprint(w, "json err: %s", err)
     }
     fmt.Fprint(w, string(b))
}

func addBug(w http.ResponseWriter, r *http.Request) {
     var b Bug
     content, err := ioutil.ReadAll(r.Body)
     fmt.Println("addBug called with Body=" + string(content))

     json.Unmarshal(content, &b)
     fmt.Println("addBug called with BugNumber=" + b.BugNumber)
     fmt.Println("addBug called with Bugname=" + b.BugName)
     fmt.Println("addBug called with BugDesn=" + b.BugDesn)

     re := BugResult{Status: "OK", Bugs: []Bug{b}}
     re_json, err := json.Marshal(re)
     if err != nil {
          fmt.Fprint(w, "json err: %s", err)
     }
     fmt.Fprint(w, string(re_json))
}

func listBug(w http.ResponseWriter, r *http.Request) {
     b1 := Bug{Id: "1", BugNumber: "bug1", BugName: "bug1", BugDesn: "desn1"}
     b2 := Bug{Id: "2", BugNumber: "bug2", BugName: "bug2", BugDesn: "desn2"}
     re := BugResult{Status: "Ok", Bugs: []Bug{b1, b2}}
     b, err := json.Marshal(re)
     if err != nil {
          fmt.Fprint(w, "json err: %s", err)
     }
     fmt.Fprint(w, string(b))
}

func main() {
     router := mux.NewRouter()
     router.HandleFunc("/bugs", listBug).Methods("GET")
     router.HandleFunc("/bugs", addBug).Methods("POST")
     router.HandleFunc("/bugs/{Id}", getBug).Methods("GET")
     router.HandleFunc("/bugs/{Id}", updateBug).Methods("PUT")
     router.HandleFunc("/bugs/{Id}", deleteBug).Methods("DELETE")

     http.Handle("/", router)
     http.ListenAndServe(":8088", nil)
}

It is not very nice since there is repeat codes like this.
     b, err := json.Marshal(re)
     if err != nil {
          fmt.Fprint(w, "json err: %s", err)
     }
     fmt.Fprint(w, string(b))
I will check how to avoid that. 


References:
https://github.com/drone/routes

https://github.com/astaxie/build-web-application-with-golang/blob/master/ebook/08.3.md
https://github.com/gorilla/mux
http://www.gorillatoolkit.org/pkg/mux

JSON handle
http://sillycat.iteye.com/blog/2065585

相关推荐