Skip to content

Request Handling

Input Parsing

The req package provides functions for parsing request data into Go structs.

ParseInput

Parses request bodies from JSON, form data, or query parameters based on the Content-Type header:

func MyHandler(c app.Context) error {
    var input CreateUserInput
    err := c.ParseInput(&input)
    if err != nil {
        return c.BadRequest(err)
    }
    return c.JSON(app.M{"input": input})
}

ParseInput automatically:

  • Decodes JSON bodies (for application/json requests)
  • Decodes form/query parameters (for form submissions)

Input Structs and Validation

Define input structs with a Validate() method:

type CreateUserInput struct {
    Name  string `json:"name"`
    Email string `json:"email"`
}

func (i *CreateUserInput) Validate() error {
    v := app.NewValidator()
    v.Field("name", i.Name).Required().Max(255)
    v.Field("email", i.Email).Required().Email()
    return v.Validate()
}

func NewCreateUserInput(c app.Context) (*CreateUserInput, error) {
    input := &CreateUserInput{}
    if err := c.ParseInput(input); err != nil {
        return nil, err
    }
    return input, input.Validate()
}

Use with the handler:

func Store(c app.Context) error {
    input, err := NewCreateUserInput(c)
    if err != nil {
        return c.UnprocessableEntity(err)
    }
    // input is validated and ready to use
}

Input Middleware

The router supports an Input middleware that decodes and validates before the handler runs:

r.Post("/users", router.Input(&CreateUserInput{}), handlers.UserStore)

The decoded input is available in the handler via c.Input():

func UserStore(c app.Context) error {
    input := c.Input().(*CreateUserInput)
    // input is already validated
}

JSON Body Decoding

For direct JSON decoding without struct binding:

func MyHandler(c app.Context) error {
    var data map[string]any
    err := c.DecodeJSON(&data)
    if err != nil {
        return c.BadRequest(err)
    }
    return c.JSON(data)
}

The low-level DecodeJSONBody function enforces:

  • 1MB maximum body size
  • Rejection of unknown fields
  • Single JSON object enforcement
  • Detailed error messages

Content-Type Detection

Check what format a client expects:

if c.WantsJSON() {
    // Return JSON response
}
if c.WantsHTML() {
    // Return HTML response
}
if c.WantsXML() {
    // Return XML response
}

Check what format the client sent:

if c.HasJSONRequest() { /* JSON body */ }
if c.HasFormDataRequest() { /* multipart form */ }
if c.HasFormURLEncodedRequest() { /* URL-encoded form */ }

File Uploads

Handle file uploads with c.Upload():

func Upload(c app.Context) error {
    file, err := c.Upload("avatar", "avatars")
    if err != nil {
        return c.BadRequest(err)
    }
    return c.JSON(app.M{"path": file.Name()})
}

Parameters: the form field name, target directory, and an optional custom filename.