Skip to main content

body

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

Definition

Name: "body"
Args: BODY_TYPE

body will read the content of the request body and parses it as BODY_TYPE into the corresponding field of the struct. 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.

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",
}
package main

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

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

type UpdateUserInput struct {
ID string `in:"path=id"` // NOTE: register a path directive before using
Payload struct {
Display string `json:"display"`
Email string `json:"email"`
IsAdmin bool `json:"is_admin"`
} `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.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)
}

Body Annotations

There're two body decoder annotations that can be used to read the body of the request:

  • httpin.JSONBody: parses the body as an JSON object
  • httpin.XMLBody: parses the body as an XML object

You can embed one of them into your struct like the following:

type CreateUserInput struct {
httpin.JSONBody
Login string `json:"login"`
Gender string `json:"gender"`
}

or

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

type CreateUserInput struct {
httpin.JSONBody
*User
}
caution

Body Annotations turns the whole struct into a target to which the request body will be decoded and populated. So it doesn't support a mix of body input and param input. Instead, embedding a struct into the input struct can achieve this. Check the demo code above.

Custom Body Decoders

Use one of the following methods to add/replace a new body decoder to httpin.

  1. RegisterBodyDecoder
  2. ReplaceBodyDecoder

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:

func init() {
httpin.ReplaceBodyDecoder("json", &myJSONDecoder{})
}

You also can register a new body decoder by using the following code:

func init() {
httpin.RegisterBodyDecoder("yaml", &myYAMLDecoder{})
// OR
httpin.ReplaceBodyDecoder("yaml", &myYAMLDecoder{})
}