godoc go.expect.digital/request
Package request simplifies the decoding of HTTP requests (REST API) into Go structs for easier consumption. It implements decoding based on the OpenAPI 3.1 specification.
In general, it is better to use code generation from the API specification, e.g. OpenAPI spec to a server code in Golang. However, it's not always possible due to certain constraints.
Key Features:
By default, the Decoder reads a path value using request.PathValue.
Declare once and re-use in handlers.
package main
import (
"net/http"
"go.expect.digital/request"
)
func main() {
http.HandleFunc("/{id}", func (w http.ResponseWriter, r *http.Request) {
var req struct {
ID int `path:"id"`
}
if err := request.Decode(r, &req); err != nil {
return
}
})
log.Fatal(http.ListenAndServe(":8080", nil))
}
package main
import (
"log"
"net/http"
"github.com/go-chi/chi/v5"
"go.expect.digital/request"
)
func main() {
decode := request.NewDecoder(
request.PathValue(
func(r *http.Request, name string) string {
return chi.URLParam(r, name)
},
),
).Decode
r := chi.NewRouter()
r.Get("/{id}", func(w http.ResponseWriter, r *http.Request) {
var req struct {
ID int `path:"id"`
}
if err := decode(r, &req); err != nil {
return
}
})
log.Fatal(http.ListenAndServe("127.0.0.1:8080", r))
}
package main
import (
"log"
"net/http"
"github.com/gorilla/mux"
"go.expect.digital/request"
)
func main() {
decode := request.NewDecoder(
request.PathValue(func(r *http.Request, name string) string {
return mux.Vars(r)[name]
}),
).Decode
r := mux.NewRouter()
r.Path("/{id}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var req struct {
ID int `path:"id"`
}
if err := decode(r, &req); err != nil {
return
}
})
log.Fatal(http.ListenAndServe("127.0.0.1:8080", r))
}
We advise using Gin data binding implementation.
Example of using the package in Gin:
package main
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
"go.expect.digital/request"
)
func main() {
r := gin.Default()
r.GET("/:id", func(c *gin.Context) {
decode := request.NewDecoder(
request.PathValue(func(r *http.Request, name string) string {
return c.Param(name)
}),
).Decode
var req struct {
ID int `path:"id"`
}
if err := decode(c.Request, &req); err != nil {
return
}
})
log.Fatal(r.Run())
}