50

I'm developing a REST API with Go, but I don't know how can I do the path mappings and retrieve the path parameters from them.

I want something like this:

func main() {
    http.HandleFunc("/provisions/:id", Provisions) //<-- How can I map "id" parameter in the path?
    http.ListenAndServe(":8080", nil)
}

func Provisions(w http.ResponseWriter, r *http.Request) {
    //I want to retrieve here "id" parameter from request
}

I would like to use just http package instead of web frameworks, if it is possible.

Thanks.

nipuna
  • 3,697
  • 11
  • 24
Héctor
  • 24,444
  • 35
  • 132
  • 243

4 Answers4

70

If you don't want to use any of the multitude of the available routing packages, then you need to parse the path yourself:

Route the /provisions path to your handler

http.HandleFunc("/provisions/", Provisions)

Then split up the path as needed in the handler

id := strings.TrimPrefix(req.URL.Path, "/provisions/")
// or use strings.Split, or use regexp, etc.
JimB
  • 104,193
  • 13
  • 262
  • 255
15

You can use golang gorilla/mux package's router to do the path mappings and retrieve the path parameters from them.

import (
    "fmt"
    "github.com/gorilla/mux"
    "net/http"
)

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/provisions/{id}", Provisions)
    http.ListenAndServe(":8080", r)
}

func Provisions(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    id, ok := vars["id"]
    if !ok {
        fmt.Println("id is missing in parameters")
    }
    fmt.Println(`id := `, id)
    //call http://localhost:8080/provisions/someId in your browser
    //Output : id := someId
}
nipuna
  • 3,697
  • 11
  • 24
3

Golang read value from URL query "/template/get/123".

I used standard gin routing and handling request parameters from context parameters.

Use this in registering your endpoint:

func main() {
    r := gin.Default()
    g := r.Group("/api")
    {
        g.GET("/template/get/:Id", templates.TemplateGetIdHandler)
    }
    r.Run()
}

And use this function in handler

func TemplateGetIdHandler(c *gin.Context) {
    req := getParam(c, "Id")
    //your stuff
}

func getParam(c *gin.Context, paramName string) string {
    return c.Params.ByName(paramName)
}

Golang read value from URL query "/template/get?id=123".

Use this in registering your endpoint:

func main() {
    r := gin.Default()
    g := r.Group("/api")
    {
        g.GET("/template/get", templates.TemplateGetIdHandler)
    }
    r.Run()
}

And use this function in handler

type TemplateRequest struct {
    Id string `form:"id"`
}

func TemplateGetIdHandler(c *gin.Context) {
    var request TemplateRequest
    err := c.Bind(&request)
    if err != nil {
        log.Println(err.Error())
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    }
    //your stuff
}
Leonid Pavlov
  • 671
  • 8
  • 13
  • 1
    Can you add the imports? For example, gin would be in "github.com/gin-gonic/gin" but templates? – Alechan Jul 04 '23 at 14:49
3

You can do this with standard library handlers. Note http.StripPrefix accepts an http.Handler and returns a new one:

func main() {
  mux := http.NewServeMux()
  provisionsPath := "/provisions/"
  mux.Handle(
    provisionsPath,
    http.StripPrefix(provisionsPath, http.HandlerFunc(Provisions)),
  )
}

func Provisions(w http.ResponseWriter, r *http.Request) {
  fmt.Println("Provision ID:", r.URL.Path)
}

See working demo on Go playground.

You can also nest this behavior using submuxes; http.ServeMux implements http.Handler, so you can pass one into http.StripPrefix just the same.