mirror of
https://github.com/ggicci/httpin.git
synced 2024-11-24 08:32:45 +02:00
🍡 HTTP Input for Go - Decode an HTTP request into a custom struct 📢 the encoding feature will come soon, see branch feat/encoder
https://ggicci.github.io/httpin/
.github | ||
core | ||
integration | ||
internal | ||
patch | ||
.gitignore | ||
go.mod | ||
go.sum | ||
httpin_test.go | ||
httpin.go | ||
LICENSE | ||
Makefile | ||
README.md |
httpin - HTTP Input for Go
HTTP Request from/to Go Struct
Core Features
httpin helps you easily decode data from an HTTP request, including:
- Query parameters, e.g.
?name=john&is_member=true
- Headers, e.g.
Authorization: xxx
- Form data, e.g.
username=john&password=******
- JSON/XML Body, e.g.
POST {"name":"john"}
- Path variables, e.g.
/users/{username}
- File uploads
You only need to define a struct to receive/bind data from an HTTP request, without writing any parsing stuff code by yourself.
Since v0.15.0, httpin also supports creating an HTTP request (http.Request
) from a Go struct instance.
httpin is:
- well documented: at https://ggicci.github.io/httpin/
- open integrated: with net/http, go-chi/chi, gorilla/mux, gin-gonic/gin, etc.
- extensible (advanced feature): by adding your custom directives. Read httpin - custom directives for more details.
How to decode an HTTP request to Go struct?
type ListUsersInput struct {
Token string `in:"query=access_token;header=x-access-token"`
Page int `in:"query=page;default=1"`
PerPage int `in:"query=per_page;default=20"`
IsMember bool `in:"query=is_member"`
Search *string `in:"query=search;omitempty"`
}
func ListUsers(rw http.ResponseWriter, r *http.Request) {
input := r.Context().Value(httpin.Input).(*ListUsersInput)
if input.IsMember {
// Do sth.
}
// Do sth.
}
How to encode a Go struct to HTTP request?
type ListUsersInput struct {
Token string `in:"query=access_token;header=x-access-token"`
Page int `in:"query=page;default=1"`
PerPage int `in:"query=per_page;default=20"`
IsMember bool `in:"query=is_member"`
}
func SDKListUsers() {
payload := &ListUsersInput{
Token: os.Getenv("MY_APP_ACCESS_TOKEN"),
Page: 2,
IsMember: true,
}
// Easy to remember, http.NewRequest -> httpin.NewRequest
req, err := httpin.NewRequest("GET", "/users", payload)
// ...
}
Why this package?
Compared with using net/http
package
func ListUsers(rw http.ResponseWriter, r *http.Request) {
page, err := strconv.ParseInt(r.FormValue("page"), 10, 64)
if err != nil {
// Invalid parameter: page.
return
}
perPage, err := strconv.ParseInt(r.FormValue("per_page"), 10, 64)
if err != nil {
// Invalid parameter: per_page.
return
}
isMember, err := strconv.ParseBool(r.FormValue("is_member"))
if err != nil {
// Invalid parameter: is_member.
return
}
// Do sth.
}
Benefits | Before (use net/http package) | After (use ggicci/httpin package) |
---|---|---|
⌛️ Developer Time | 😫 Expensive (too much parsing stuff code) | 🚀 Faster (define the struct for receiving input data and leave the parsing job to httpin) |
♻️ Code Repetition Rate | 😞 High | 😍 Lower |
📖 Code Readability | 😟 Poor | 🤩 Highly readable |
🔨 Maintainability | 😡 Poor | 🥰 Highly maintainable |
Alternatives and Similars
- gorilla/schema: converts structs to and from form values
- google/go-querystring: encoding structs into URL query parameters