tinka alpha

Body parser

This guide covers reading request bodies in Tinka. You will learn how to:

Overview

tinka.Decode reads a JSON request body into a value of the type you name, checks it with your validation, and turns every failure into a response the client can act on. It also guards the server: bodies are capped at 1 MiB and must arrive within 30s, so a client cannot exhaust memory or hold a request open.

Decode a body

Name the type you expect and pass the response writer and the request. On failure, return the error: it's already the right response.

posts.go
package main

import (
	"net/http"

	"github.com/mucolabs/tinka"
)

type newPost struct {
	Title string `json:"title"`
	Body  string `json:"body"`
}

func createPost(w http.ResponseWriter, r *http.Request) error {
	in, err := tinka.Decode[newPost](w, r)
	if err != nil {
		return err
	}
	return tinka.JSON(w, http.StatusCreated, in)
}

Decode answers with these statuses, each as problem details:

Validate the input

Give the type a Valid method and Decode calls it after decoding. It returns a problem for each invalid field, keyed by the field's name; an empty map means the input is valid. Add context and strings to the file's imports, then the method:

posts.go
func (p newPost) Valid(ctx context.Context) map[string]string {
	problems := map[string]string{}
	if strings.TrimSpace(p.Title) == "" {
		problems["title"] = "Enter a title."
	}
	if len(p.Body) > 10_000 {
		problems["body"] = "Keep the body under 10,000 characters."
	}
	return problems
}

Every invalid field comes back in one 422 response, so a form can show all its errors at once:

Response
{
  "title": "Unprocessable Entity",
  "status": 422,
  "detail": "Some fields are invalid.",
  "code": "invalid",
  "fields": {
    "title": "Enter a title."
  },
  "request_id": "S5QWQ3DAEXTVZ6M7F4DZEL6EBI"
}

See also: Exception handling, App