Skip to main content

body

body is a directive executor who decodes/encodes a field from/to the body of the request, i.e. http.Request.Body, JSON and XML formats are supported.

Signature

Name: "body"
Args: BODY_TYPE

Supported BODY_TYPE are:

  • json: parses the body as an JSON object
  • xml: parses the body as an XML object

If BODY_TYPE were not specified, json will be used.

Decoding

body will read the content of the request body and parses it as BODY_TYPE into the corresponding field of the struct.

Usage

type User struct {
Login string `json:"login"`
Gender string `json:"gender"`
}

type CreateUserInput struct {
Payload *User `in:"body=json"` // use "body=xml" for XML formatted body
}
Request (Body)CreateUserInput
POST /users HTTP/1.1
Host: foo.example
Content-Type: application/json

{ "login": "alex", "gender": "female" }
Payload: &User{
Login: "alex",
Gender: "female",
}

Runable Example

package main

import (
"fmt"
"io"
"net/http"
"net/http/httptest"
"strings"

"github.com/ggicci/httpin"
httpin_integration "github.com/ggicci/httpin/integration"
"github.com/go-chi/chi/v5"
)

type UserPatch struct {
Display string `json:"display"`
Email string `json:"email"`
IsAdmin bool `json:"is_admin"`
}

type UpdateUserInput struct {
ID string `in:"path=id"` // NOTE: register a path directive before using
Payload UserPatch `in:"body=json"`
}

func UpdateUserHandler(rw http.ResponseWriter, r *http.Request) {
input := r.Context().Value(httpin.Input).(*UpdateUserInput)
fmt.Printf("input: %#v\n", input)
}

func init() {
httpin_integration.UseGochiURLParam("path", chi.URLParam)
}

func main() {
router := chi.NewRouter()
router.With(
httpin.NewInput(UpdateUserInput{}),
).Put("/users/{id}", UpdateUserHandler)

r, _ := http.NewRequest("PUT", "/users/19911110", nil)
r.Body = io.NopCloser(strings.NewReader(`{
"display": "Ggicci Never Cry",
"email": "secret_@xxx.com",
"is_admin": true
}`))

rw := httptest.NewRecorder()
router.ServeHTTP(rw, r)
}

Output:

input: &main.UpdateUserInput{
ID:"19911110",
Payload:main.UserPatch{
Display:"Ggicci Never Cry",
Email:"secret_@xxx.com", IsAdmin:true
}
}

Encoding

body will encode the corresponding field of the struct into the body of the response, in BODY_TYPE format.

Runable Example

package main

import (
"fmt"
"net/http/httputil"

"github.com/ggicci/httpin"
)

type UserPatch struct {
Display string `json:"display"`
Email string `json:"email"`
IsAdmin bool `json:"is_admin"`
}

type UpdateUserInput struct {
ID string `in:"path=id"`
Payload UserPatch `in:"body=json"`
}

func main() {
input := &UpdateUserInput{
ID: "ggicci",
Payload: UserPatch{
Display: "Ggicci",
Email: "secret_@xxx.com",
IsAdmin: true,
},
}
r, _ := httpin.NewRequest("PATCH", "/users/{id}", input)
data, _ := httputil.DumpRequest(r, true)
fmt.Printf("%s\n", data)
}

Output:

PATCH /users/ggicci HTTP/1.1
Content-Type: application/json

{"display":"Ggicci","email":"secret_@xxx.com","is_admin":true}

Custom Body Format

Call RegisterBodyFormat to register a new body format/serializer to httpin.

For example, the default JSON decoder is borrowed from Go's standard encoding/json package. If you want to use a different JSON decoder, you can replace it by using the following code:

import httpin_core "github.com/ggicci/httpin/core"

func init() {
httpin_core.RegisterBodyFormat("json", &MyPerformanentJSONSerializer{})
}