Skip to content

Guide

Request Data

Read path parameters, query strings, headers, forms, uploaded files, raw bodies, and cancellation from a request.

Everything about the incoming request is available on *zinc.Context. This page covers reading values one at a time. To decode many values into a struct at once, use binding.

app.Get("/users/{id}", func(c *zinc.Context) error {
id := c.Param("id")
return c.String(id)
})

c.ParamOr("id", "me") returns a fallback when a parameter is empty, which is useful with wildcards.

// GET /search?q=zinc&tag=go&tag=http&page=2
app.Get("/search", func(c *zinc.Context) error {
q := c.Query("q") // "zinc"
page := c.QueryOr("page", "1") // "2", or "1" when missing
tags := c.QueryArray("tag") // ["go", "http"]
return c.JSON(zinc.Map{"q": q, "page": page, "tags": tags})
})

For bracket-style keys such as ?filter[status]=open&filter[owner]=me, c.QueryMap("filter") returns map[string]string{"status": "open", "owner": "me"}.

token := c.GetHeader(zinc.HeaderAuthorization)
contentType := c.ContentType() // media type without parameters, such as "application/json"

Zinc defines constants for common header names, such as zinc.HeaderAuthorization and zinc.HeaderContentType.

app.Post("/profile", func(c *zinc.Context) error {
name := c.PostForm("name")
roles := c.PostFormArray("roles")
return c.JSON(zinc.Map{"name": name, "roles": roles})
})

PostForm reads URL-encoded and multipart bodies. PostFormOr and PostFormMap mirror their query counterparts.

app.Post("/documents", func(c *zinc.Context) error {
file, err := c.FormFile("document")
if err != nil {
return zinc.ErrBadRequest.WithMessage("document is required")
}
// Never trust the client's filename. Keep only its base name, or generate your own.
name := filepath.Base(file.Filename)
if err := c.SaveFile(file, filepath.Join("uploads", name)); err != nil {
return err
}
return c.Status(zinc.StatusCreated).JSON(zinc.Map{"saved": name})
})

Use c.FormFiles("documents") for several files under one field, and c.MultipartForm() for full access to every value and file. The File Upload recipe shows a complete program.

body, err := c.BodyBytes()
if err != nil {
return err
}

BodyBytes and BodyString cache the body, so middleware can read it and binding still works afterwards.

The request’s context.Context is cancelled when the client disconnects or a deadline passes. Pass it to anything that can block:

app.Get("/report", func(c *zinc.Context) error {
rows, err := db.QueryContext(c.Context(), reportSQL)
if err != nil {
return err
}
defer rows.Close()
// ...
return c.JSON(report)
})

Middleware can attach values or a tighter deadline with c.SetContext(ctx). Context Timeout does exactly that.

Zinc never hides the standard request. c.Request() returns the *http.Request, so anything in the standard library works:

agent := c.Request().UserAgent()
host := c.Request().Host