Go url parameters mapping

What about trying using regex, and find a named group in your url, like playground:

package main

import (
    "fmt"
    "net/url"
    "regexp"
)

var myExp = regexp.MustCompile(`/blob/(?P<id>\d+)/test`) // use (?P<id>[a-zA-Z]+) if the id is alphapatic

func main() {

    s := "http://localhost:8080/blob/123/test"

    u, err := url.Parse(s)
    if err != nil {
        panic(err)
    }

    fmt.Println(u.Path)

    match := myExp.FindStringSubmatch(s) // or match := myExp.FindStringSubmatch(u.Path)
    result := make(map[string]string)
    for i, name := range myExp.SubexpNames() {
        if i != 0 && name != "" {
            result[name] = match[i]
        }
    }
    fmt.Printf("id: %s\n", result["id"])

}

output

/blob/123/test
id: 123

Below full code to use it with url, that is receiving http://localhost:8000/hello/John/58 and returning http://localhost:8000/hello/John/58:

package main

import (
    "fmt"
    "net/http"
    "regexp"
    "strconv"
)

var helloExp = regexp.MustCompile(`/hello/(?P<name>[a-zA-Z]+)/(?P<age>\d+)`)

func hello(w http.ResponseWriter, req *http.Request) {
    match := helloExp.FindStringSubmatch(req.URL.Path)
    if len(match) > 0 {
        result := make(map[string]string)
        for i, name := range helloExp.SubexpNames() {
            if i != 0 && name != "" {
                result[name] = match[i]
            }
        }
        if _, err := strconv.Atoi(result["age"]); err == nil {
            fmt.Fprintf(w, "Hello, %v year old named %s!", result["age"], result["name"])
        } else {
            fmt.Fprintf(w, "Sorry, not accepted age!")
        }
    } else {
        fmt.Fprintf(w, "Wrong url\n")
    }
}

func main() {

    http.HandleFunc("/hello/", hello)

    http.ListenAndServe(":8090", nil)
}

There is no built in simple way to do this, however, it is not hard to do.

This is how I do it, without adding a particular library. It is placed in a function so that you can invoke a simple getCode() function within your request handler.

Basically you just split the r.URL.Path into parts, and then analyse the parts.

// Extract a code from a URL. Return the default code if code
// is missing or code is not a valid number.
func getCode(r *http.Request, defaultCode int) (int, string) {
        p := strings.Split(r.URL.Path, "/")
        if len(p) == 1 {
                return defaultCode, p[0]
        } else if len(p) > 1 {
                code, err := strconv.Atoi(p[0])
                if err == nil {
                        return code, p[1]
                } else {
                        return defaultCode, p[1]
                }
        } else {
                return defaultCode, ""
        }
}

Well, without external libraries you can't, but may I recommend two excellent ones:

  1. httprouter - https://github.com/julienschmidt/httprouter - is extremely fast and very lightweight. It's faster than the standard library's router, and it creates 0 allocations per call, which is great in a GCed language.

  2. Gorilla Mux - http://www.gorillatoolkit.org/pkg/mux - Very popular, nice interface, nice community.

Example usage of httprouter:

func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
    fmt.Fprintf(w, "hello, %s!\n", ps.ByName("name"))
}

func main() {
    router := httprouter.New()
    router.GET("/hello/:name", Hello)

    log.Fatal(http.ListenAndServe(":8080", router))
}