pirca

package module
v1.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 26, 2026 License: MIT Imports: 17 Imported by: 0

README

Pirca

Pirca is a lightweight HTTP middleware for Go that extends net/http with a rich Context, response helpers, request binders, form/file handling, and more — without replacing the standard library or adding external dependencies.

Built on patterns from Gin, Pirca follows the same conventions and logic, adapted to work directly with net/http. Many methods mirror Gin's API, making it familiar if you've used Gin before, but without the framework lock-in.

  • Zero dependencies — only the Go standard library.
  • Based on Gin — same patterns, same feel, no framework.
  • Full controlctx.Request and ctx.Writer are the original *http.Request and http.ResponseWriter. Use them directly whenever you need.
  • Implements context.Context — pass ctx directly to databases, HTTP clients, tracers, etc.
  • Captures status code and bytes written — perfect for logging, metrics, and observability middlewares.
  • Accelerates development — JSON/XML binders, response writers, file uploads, cookies, query params, form values — all ready to use.

Requirements

  • Go 1.22 or later

Installation

go get github.com/loadept/pirca

Quick start

package main

import (
    "log"
    "net/http"

    "github.com/loadept/pirca"
)

func main() {
    mux := http.NewServeMux()
    handler := pirca.New()(mux)

    mux.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) {
        ctx := pirca.Ctx(r)

        _ = ctx.JSON(http.StatusOK, map[string]string{
            "message": "Hello world",
        })
    })

    log.Fatal(http.ListenAndServe(":8080", handler))
}
How it works
  1. pirca.New() returns a middleware that creates a Context per request.
  2. Inside the handler, pirca.Ctx(r) retrieves the Context from the request.
  3. Use ctx to bind bodies, write responses, handle cookies, query params, forms, files, and more.

Core API

New(cfg ...*Config) func(http.Handler) http.Handler

Creates the middleware. Must be the outermost layer in your handler chain. Accepts an optional *Config.

// Defaults
handler := pirca.New()(mux)

// With custom config
handler := pirca.New(&pirca.Config{
    MaxBodySize:        1 << 20,       // 1MB max body
    MaxMultipartMemory: 64 << 20,      // 64MB for multipart
})(mux)
Config
Field Type Default Description
MaxBodySize int64 0 (no limit) Max request body size in bytes
MaxMultipartMemory int64 32 MB Max memory for multipart forms
Ctx(r *http.Request) *Context

Retrieves the Context from the request. Must be called inside a handler wrapped by New().

ctx := pirca.Ctx(r)

API Reference

📦 Body Binding

Read and deserialize the request body.

Method Stream Cache Best for
BindJSON(obj) decoder JSON, single read, efficient
BindJSONStrict(obj) decoder JSON + reject unknown fields
BindXML(obj) decoder XML, single read
Bind(obj, binder) []byte Custom formats (TOML, YAML, etc.)
BindBodyWith(obj, binder) []byte Custom formats + multiple reads
BindJSONWith(obj) []byte JSON + multiple reads
BindJSONStrictWith(obj) []byte JSON strict + multiple reads
BindXMLWith(obj) []byte XML + multiple reads
ctx := pirca.Ctx(r)

// Stream JSON (single read)
var user User
if err := ctx.BindJSON(&user); err != nil { ... }

// Strict JSON — rejects unknown fields
if err := ctx.BindJSONStrict(&user); err != nil { ... }

// Custom format (TOML, YAML, MessagePack, etc.)
var cfg Config
if err := ctx.Bind(&cfg, toml.Unmarshal); err != nil { ... }

// Cached body — can be read again by other middlewares
var product Product
if err := ctx.BindBodyWith(&product, json.Unmarshal); err != nil { ... }
ctx.Set("product", product) // share with other handlers

// Convenience cached variants
ctx.BindJSONWith(&user)       // json.Unmarshal
ctx.BindJSONStrictWith(&user) // json with DisallowUnknownFields
ctx.BindXMLWith(&doc)         // xml.Unmarshal
Raw body access
// Read body as bytes (single read)
body, err := ctx.GetBodyBytes()

// Direct reader access
raw, err := io.ReadAll(ctx.Request.Body)
📤 Response Writers

Write responses in various formats.

Method Content-Type Description
JSON(code, obj) application/json Serializes as JSON
XML(code, obj) application/xml Serializes as XML
String(code, msg) not set Plain text
Data(code, data) not set Raw bytes
Redirect(code, location) HTTP redirect
File(filepath) auto Serves a file
FileFromFS(filepath, fs) auto Serves from http.FileSystem
FileAttachment(filepath, filename) auto Forces download
ctx := pirca.Ctx(r)

ctx.JSON(http.StatusOK, map[string]string{"message": "ok"})
ctx.XML(http.StatusCreated, myStruct)
ctx.String(http.StatusOK, "<h1>Hello</h1>")
ctx.Data(http.StatusOK, pdfBytes)
ctx.Redirect(http.StatusMovedPermanently, "/new-url")

// Files
ctx.File("./static/index.html")
ctx.FileFromFS("static/style.css", http.FS(embedFS))
ctx.FileAttachment("./docs/report.pdf", "report_2026.pdf")
🔗 Query Parameters

Access URL query parameters.

ctx := pirca.Ctx(r)

// GET /search?q=golang&page=1&color=red&color=blue

q := ctx.Query("q")                 // "golang"
page := ctx.DefaultQuery("page", "1") // "1" (default)
limit := ctx.DefaultQuery("limit", "10") // "10" (not in URL)

value, exists := ctx.GetQuery("q")  // ("golang", true)
value, exists := ctx.GetQuery("wtf") // ("", false)

colors := ctx.QueryArray("color")     // ["red", "blue"]
values, ok := ctx.GetQueryArray("color") // (["red", "blue"], true)
Method Returns Description
Query(key) string Value or ""
DefaultQuery(key, default) string Value or default if missing
GetQuery(key) (string, bool) Value + existence check
QueryArray(key) []string All values
GetQueryArray(key) ([]string, bool) All values + existence
📋 Path Parameters (Go 1.22+)
// Pattern: GET /user/{id}
ctx := pirca.Ctx(r)
id := ctx.Param("id") // "123"
📝 Form Values

Access form fields from application/x-www-form-urlencoded and multipart/form-data.

ctx := pirca.Ctx(r)

name := ctx.FormValue("name")                  // "jesus" or ""
name := ctx.DefaultFormValue("name", "guest")   // "jesus" or "guest" if missing
name, exists := ctx.GetFormValue("name")        // ("jesus", true) or ("", false)
Method Returns Description
FormValue(key) string Value or ""
DefaultFormValue(key, default) string Value or default if missing
GetFormValue(key) (string, bool) Value + existence check
📎 File Uploads

Handle multipart file uploads.

ctx := pirca.Ctx(r)

// Single file
file, err := ctx.FormFile("avatar")
if err != nil { ... }
ctx.SaveUploadedFile(file, "./uploads/"+file.Filename)

// Multiple files
form, err := ctx.MultipartForm()
if err != nil { ... }
for _, file := range form.File["images"] {
    ctx.SaveUploadedFile(file, "./uploads/"+file.Filename)
}
Method Description
FormFile(name) Returns the first file for the given field
MultipartForm() Returns the full parsed multipart form
SaveUploadedFile(file, dst, perm...) Saves to disk (creates dirs, optional permissions)
🍪 Cookies
ctx := pirca.Ctx(r)

// Set
ctx.SetSameSite(http.SameSiteLaxMode)
ctx.SetCookie("token", "abc123", 3600, "/", "example.com", true, true)

// Set with pre-built cookie
ctx.SetCookieData(&http.Cookie{
    Name:  "session",
    Value: sessionID,
})

// Get
val, err := ctx.Cookie("token") // http.ErrNoCookie if missing
Method Description
SetSameSite(samesite) Sets SameSite attribute for subsequent cookies
SetCookie(name, value, maxAge, path, domain, secure, httpOnly) Writes a Set-Cookie header
SetCookieData(cookie) Writes using a pre-built *http.Cookie
Cookie(name) Reads a cookie from the request (URL-decoded)
📋 Headers
ctx := pirca.Ctx(r)

ctx.Header("X-Custom", "value")     // set response header
ctx.Header("X-Custom", "")          // delete response header
val := ctx.GetHeader("Content-Type") // read request header
Method Description
Header(key, value) Sets or deletes a response header
GetHeader(key) Returns a request header value
📊 Status & Response Metrics
ctx := pirca.Ctx(r)

ctx.Status(http.StatusCreated)
fmt.Println(ctx.GetStatus())    // 201
fmt.Println(ctx.BytesWritten()) // total bytes written to response body
Method Description
Status(code) Writes the HTTP status code
GetStatus() Returns the written status code
BytesWritten() Returns total bytes written to the body
🔑 Key-Value Store

Share data between middlewares and handlers within the same request.

ctx := pirca.Ctx(r)

// Set
ctx.Set("userID", "123")
ctx.Set("role", "admin")

// Get
if userID, ok := ctx.Get("userID"); ok {
    fmt.Println(userID)
}

// Delete
ctx.Delete("tempData")

All methods are safe for concurrent use.

Method Description
Set(key, value) Stores a value (any type)
Get(key) Retrieves a value + exists bool
Delete(key) Removes a value
🌐 context.Context Implementation

*Context implements context.Context, so it can be passed directly to any function that accepts one.

ctx := pirca.Ctx(r)

// Pass to database, HTTP client, tracer, etc.
user, err := db.FindUser(ctx, id)
resp, err := http.NewRequestWithContext(ctx, "GET", url, nil)
span, _ := tracer.Start(ctx, "handler")
  • Deadline() — delegates to the parent request context
  • Done() — closed when the client disconnects
  • Err() — returns cancellation error
  • Value(key) — string keys search the local store first, then fall back to the parent context

Middleware Integration

Since New() captures the status code and bytes written through an internal responseWriter, you can build middlewares without wrapping the ResponseWriter yourself.

func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        ctx := pirca.Ctx(r)
        start := time.Now()
        next.ServeHTTP(w, r)
        log.Printf(
            "%s %s %d %d %v",
            r.Method, r.URL.Path,
            ctx.GetStatus(), ctx.BytesWritten(),
            time.Since(start),
        )
    })
}

func main() {
    mux := http.NewServeMux()
    handler := pirca.New()(loggingMiddleware(mux))
    http.ListenAndServe(":8080", handler)
}

Flexibility

Because Pirca works directly with net/http, you always have full access to the underlying types:

ctx := pirca.Ctx(r)

// ctx.Request is the original *http.Request
// ctx.Writer is the original http.ResponseWriter (wrapped)
// They are the same references as the handler parameters

fmt.Fprintf(ctx.Writer, "raw write")
ctx.Request.Header.Get("Authorization")
r.Method // also works — r is the same as ctx.Request

You're never locked into the middleware. Use ctx.Request directly, use ctx.Writer directly, or use the original r and w — they're all the same objects.

Complete Example

func handler(w http.ResponseWriter, r *http.Request) {
    ctx := pirca.Ctx(r)

    var payload struct {
        Name string `json:"name"`
        Age  int    `json:"age"`
    }

    if err := ctx.BindJSON(&payload); err != nil {
        ctx.JSON(http.StatusBadRequest, map[string]string{
            "error": "invalid request body",
        })
        return
    }

    page := ctx.DefaultQuery("page", "1")

    if token, err := ctx.Cookie("session"); err == nil {
        ctx.Set("session_token", token)
    }

    ctx.JSON(http.StatusOK, map[string]any{
        "name":  payload.Name,
        "age":   payload.Age,
        "page":  page,
        "agent": ctx.GetHeader("User-Agent"),
    })
}

License

MIT

Documentation

Overview

Package pirca provides a lightweight HTTP middleware that enhances net/http with a rich Context, response helpers, and request utilities without replacing the standard library.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func New

func New(cfg ...*Config) func(http.Handler) http.Handler

New returns an HTTP middleware that initializes a pirca Context for each incoming request and makes it available via Ctx. It must wrap the outermost handler in the middleware chain. Optionally accepts a *Config to override default settings.

Example:

mux := http.NewServeMux()

// With defaults
http.ListenAndServe(":8080", pirca.New()(mux))

// With custom config
http.ListenAndServe(":8080", pirca.New(&pirca.Config{
    MaxBodySize: 1 << 20,
})(mux))

Types

type Config

type Config struct {
	// MaxBodySize sets the maximum size of the request body in bytes.
	// Requests exceeding this limit will return an error on read.
	// Defaults to 0 (no limit).
	MaxBodySize int64

	// MaxMultipartMemory sets the maximum memory used when parsing multipart forms.
	// The rest is written to temporary files on disk.
	// Defaults to 32MB.
	MaxMultipartMemory int64
}

Config holds the configuration for the Pirca middleware. All fields are optional — unset fields use their default values.

Defaults:

MaxBodySize:        0 (no limit)
MaxMultipartMemory: 32MB

type Context

type Context struct {
	// Writer is the underlying http.ResponseWriter, wrapped to capture
	// status code and bytes written. It can be used directly if needed.
	Writer http.ResponseWriter

	// Request is the incoming HTTP request. It can be used directly
	// alongside Context methods interchangeably.
	Request *http.Request
	// contains filtered or unexported fields
}

Context holds the request and response state for a single HTTP request. It implements context.Context, so it can be passed directly to any function that accepts a context, such as database drivers, HTTP clients, or tracers.

Context is created by Wrap for each incoming request and retrieved via Ctx.

func Ctx

func Ctx(r *http.Request) *Context

Ctx retrieves the pirca Context from the request. It must be called within a handler wrapped by Wrap, otherwise it will panic.

Example:

mux.HandleFunc("GET /ip/{ip}", func(w http.ResponseWriter, r *http.Request) {
    ctx := pirca.Ctx(r)
    _ = ctx.JSON(http.StatusOK, map[string]string{"msg": "hello, world!"})
}

func (*Context) Bind

func (c *Context) Bind(obj any, binder func(data []byte, obj any) error) error

Bind reads the entire request body into memory and passes the raw bytes to the provided binder function for deserialization.

Unlike BindJSON or BindXML which stream directly from the request body, Bind loads the full body into a []byte first. This makes it suitable for custom formats (TOML, YAML, MessagePack, etc.) or when you need the raw bytes before deserializing.

The body can only be read once — use BindBodyWith if the body needs to be read multiple times across middlewares and handlers.

For JSON use BindJSON. For XML use BindXML. For cacheable reads use BindBodyWith.

Example:

// Custom format
ctx.Bind(&obj, func(data []byte, obj any) error {
	return toml.Unmarshal(data, obj)
})

// With validation before deserializing
ctx.Bind(&obj, func(data []byte, obj any) error {
	if !json.Valid(data) {
		return errors.New("invalid json")
	}
	return json.Unmarshal(data, obj)
})

func (*Context) BindBodyWith

func (c *Context) BindBodyWith(obj any, binder func(data []byte, obj any) error) error

BindBodyWith reads the request body once and caches it in the Context store, allowing subsequent calls to reuse the same body bytes across middlewares and handlers without hitting EOF.

bind is a function that deserializes the body bytes into obj. Use BindJSONWith or BindXMLWith for the most common cases.

Example:

ctx.BindBodyWith(&obj, func(data []byte, obj any) error {
	return json.Unmarshal(data, obj)
})

func (*Context) BindJSON

func (c *Context) BindJSON(obj any) error

BindJSON decodes the request body as JSON into obj. Returns an error if the body is nil, the JSON is malformed, or the types are incompatible with obj.

The body can only be read once. Use BindJSONWith if the body needs to be read multiple times across middlewares and handlers.

Example:

var payload MyStruct
if err := ctx.BindJSON(&payload); err != nil {
	_ = ctx.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
	return
}

func (*Context) BindJSONStrict

func (c *Context) BindJSONStrict(obj any) error

BindJSONStrict is like BindJSON but returns an error if the request body contains fields that are not present in obj. Useful for strict API validation where unknown fields should be rejected.

Example:

var payload MyStruct
if err := ctx.BindJSONStrict(&payload); err != nil {
	_ = ctx.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
	return
}

func (*Context) BindJSONStrictWith

func (c *Context) BindJSONStrictWith(obj any) error

BindJSONStrictWith is like BindJSONWith but returns an error if the request body contains fields not present in obj. The body is cached for reuse.

Example:

var payload MyStruct
if err := ctx.BindJSONStrictWith(&payload); err != nil {
	_ = ctx.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
	return
}

func (*Context) BindJSONWith

func (c *Context) BindJSONWith(obj any) error

BindJSONWith decodes the request body as JSON into obj, caching the body so it can be read multiple times. See BindBodyWith for details.

Example:

var payload MyStruct
if err := ctx.BindJSONWith(&payload); err != nil {
	_ = ctx.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
	return
}

func (*Context) BindXML

func (c *Context) BindXML(obj any) error

BindXML decodes the request body as XML into obj. Returns an error if the body is nil, the XML is malformed, or the types are incompatible with obj.

The body can only be read once. Use BindXMLWith if the body needs to be read multiple times across middlewares and handlers.

Example:

var payload MyStruct
if err := ctx.BindXML(&payload); err != nil {
	_ = ctx.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
	return
}

func (*Context) BindXMLWith

func (c *Context) BindXMLWith(obj any) error

BindXMLWith decodes the request body as XML into obj, caching the body so it can be read multiple times. See BindBodyWith for details.

Example:

var payload MyStruct
if err := ctx.BindXMLWith(&payload); err != nil {
	_ = ctx.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
	return
}

func (*Context) BytesWritten

func (c *Context) BytesWritten() int

BytesWritten returns the total number of bytes written to the response body.

func (*Context) Cookie

func (c *Context) Cookie(name string) (string, error)

Cookie returns the value of the named cookie from the request. The value is automatically URL-decoded to reverse the encoding applied by SetCookie. Returns http.ErrNoCookie if the cookie is not present.

func (*Context) Data

func (c *Context) Data(code int, data []byte) (err error)

Data writes raw bytes to the response with the given status code. Set the Content-Type header beforehand with Header if needed.

Example:

ctx.Header("Content-Type", "application/pdf")
ctx.Data(http.StatusOK, pdfBytes)

func (*Context) Deadline

func (c *Context) Deadline() (deadline time.Time, ok bool)

Deadline implements context.Context. It delegates to the underlying request context, which is canceled when the client disconnects.

func (*Context) DefaultFormValue

func (c *Context) DefaultFormValue(key, defaultValue string) string

DefaultFormValue returns the value of a form field from the request body, or defaultValue if the key is not present. If the key exists but is empty, returns empty string — not defaultValue. For query params use DefaultQuery instead.

func (*Context) DefaultQuery

func (c *Context) DefaultQuery(key, defaultValue string) string

DefaultQuery returns the value of the URL query param with the given key, or defaultValue if not present.

Example:

// GET /search?q=golang
page := ctx.DefaultQuery("page", "1") // "1" — not in URL, uses default

func (*Context) Delete

func (c *Context) Delete(key string)

func (*Context) Done

func (c *Context) Done() <-chan struct{}

Done implements context.Context. The returned channel is closed when the request context is canceled — typically when the client disconnects.

func (*Context) Err

func (c *Context) Err() error

Err implements context.Context. It returns the error from the underlying request context, or nil if the context has not been canceled.

func (*Context) File

func (c *Context) File(filepath string)

File serves the file at the given filepath using http.ServeFile. It handles Range requests, ETags, and Last-Modified headers automatically.

func (*Context) FileAttachment

func (c *Context) FileAttachment(filepath, filename string)

FileAttachment serves the file at filepath as a downloadable attachment. The filename parameter sets the suggested filename in the browser's save dialog.

ASCII filenames are quoted and escaped per RFC 2183. Non-ASCII filenames are encoded using RFC 5987 (UTF-8 with URL encoding) to support characters such as accents, ñ, or CJK characters.

Example:

ctx.FileAttachment("./files/report.pdf", "reporte_2026.pdf")
ctx.FileAttachment("./files/report.pdf", "reporte_año_2026.pdf")

func (*Context) FileFromFS

func (c *Context) FileFromFS(filepath string, fs http.FileSystem)

FileFromFS serves a file from the given http.FileSystem at the given filepath. Unlike File, it allows serving from any FileSystem implementation, including embedded files via embed.FS.

Example:

//go:embed static
var staticFiles embed.FS

ctx.FileFromFS("static/style.css", http.FS(staticFiles))

func (*Context) FormFile

func (c *Context) FormFile(name string) (*multipart.FileHeader, error)

FormFile returns the first file uploaded with the given form key. Parses the multipart form if not already parsed, using MaxMultipartMemory from Config.

Returns the file metadata only — the internal file handle is closed automatically. Use SaveUploadedFile to save the file to disk, or call file.Open() to read its contents directly.

Note: if reading file contents manually via file.Open(), always close the returned reader after use.

Example:

file, err := ctx.FormFile("avatar")
if err != nil {
	_ = ctx.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
	return
}
ctx.SaveUploadedFile(file, "./uploads/"+file.Filename)

func (*Context) FormValue

func (c *Context) FormValue(key string) (val string)

FormValue returns the value of a form field from the request body. Works with application/x-www-form-urlencoded and multipart/form-data. For query params use Query instead.

func (*Context) Get

func (c *Context) Get(key string) (value any, exists bool)

Get retrieves a value previously stored with Set. Returns the value and true if the key exists, or nil and false otherwise. It is safe for concurrent use.

Example:

if userID, ok := ctx.Get("userID"); ok {
	fmt.Println(userID)
}

func (*Context) GetBodyBytes

func (c *Context) GetBodyBytes() ([]byte, error)

GetBodyBytes reads and returns the raw request body as bytes. The body can only be read once — subsequent calls will return empty bytes. For cacheable reads use BindBodyWith instead.

Returns an error if the body is nil.

Example:

body, err := ctx.GetBodyBytes()
if err != nil {
	_ = ctx.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
	return
}

func (*Context) GetBodyWith added in v1.2.0

func (c *Context) GetBodyWith() ([]byte, error)

GetBodyWith reads the request body and caches it, returning the raw bytes. Subsequent calls return the cached bytes without reading the body again.

It is a convenience wrapper around BindBodyWith for cases where you need the raw bytes without deserializing — for example in HMAC verification or custom parsing middlewares.

Example:

// Middleware
body, err := ctx.GetBodyWith()
if err != nil {
	ctx.String(http.StatusInternalServerError, "internal error")
	return
}
// verify HMAC with body...

// Handler — body already cached
var payload MyStruct
ctx.BindJSONWith(&payload)

func (*Context) GetFormValue

func (c *Context) GetFormValue(key string) (string, bool)

GetFormValue returns the value of a form field plus a bool indicating if the key exists. Unlike FormValue, it distinguishes between an empty value and a missing key.

func (*Context) GetHeader

func (c *Context) GetHeader(key string) string

GetHeader returns the value of the request header with the given key.

func (*Context) GetQuery

func (c *Context) GetQuery(key string) (string, bool)

GetQuery returns the value of the URL query param with the given key, plus a boolean indicating whether the key exists. Unlike Query, it distinguishes between a missing key and an empty value.

Example:

// GET /?name=jesus&empty=
ctx.GetQuery("name")  // ("gopher", true)
ctx.GetQuery("empty") // ("", true)  — exists but empty
ctx.GetQuery("wtf")   // ("", false) — does not exist

func (*Context) GetQueryArray

func (c *Context) GetQueryArray(key string) (values []string, ok bool)

GetQueryArray returns all values for the given query key as a slice, plus a boolean indicating whether the key exists.

Example:

// GET /search?color=red&color=blue
values, ok := ctx.GetQueryArray("color") // (["red", "blue"], true)
values, ok := ctx.GetQueryArray("wtf")   // ([], false)

func (*Context) GetStatus

func (c *Context) GetStatus() int

GetStatus returns the HTTP status code written to the response.

func (*Context) Header

func (c *Context) Header(key, value string)

Header sets a response header key to value. If value is empty, the header is deleted.

func (*Context) JSON

func (c *Context) JSON(code int, obj any) error

JSON serializes obj as JSON and writes it to the response with the given status code. Sets Content-Type to "application/json".

JSON uses encoding/json Marshal, which means it will fail for types that cannot be serialized such as channels, functions, or circular references. For well-defined structs and maps with basic types, it will never fail.

Example:

_ = ctx.JSON(http.StatusOK, map[string]string{"message": "ok"})

func (*Context) MultipartForm

func (c *Context) MultipartForm() (*multipart.Form, error)

MultipartForm parses and returns the full multipart form data, including all fields and uploaded files. Uses MaxMultipartMemory from Config.

Use FormFile for single file uploads. Use MultipartForm when you need access to multiple files or all form fields at once.

Note: if reading file contents manually via file.Open(), always close the returned reader after use.

Example:

form, err := ctx.MultipartForm()
if err != nil {
	_ = ctx.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
	return
}
files := form.File["avatars"]
for _, f := range files {
	ctx.SaveUploadedFile(f, "./uploads/"+f.Filename)
}

func (*Context) Param

func (c *Context) Param(key string) string

Param returns the value of the URL path param with the given key. Requires Go 1.22+ net/http pattern matching.

Example:

// GET /user/{id}
id := ctx.Param("id") // "123"

func (*Context) Query

func (c *Context) Query(key string) (val string)

Query returns the value of the URL query param with the given key. Returns empty string if not present.

Example:

// GET /search?q=golang&page=1
q := ctx.Query("q")       // "golang"
page := ctx.Query("page") // "1"

func (*Context) QueryArray

func (c *Context) QueryArray(key string) (values []string)

QueryArray returns all values for the given query key as a slice. Useful when the same key appears multiple times in the URL.

Example:

// GET /search?color=red&color=blue&color=green
colors := ctx.QueryArray("color") // ["red", "blue", "green"]

func (*Context) Redirect

func (c *Context) Redirect(code int, location string)

Redirect replies to the request with a redirect to the given location. The code must be a valid HTTP redirect status code (301-308) or 201.

Panics if an invalid status code is provided, as this indicates a bug in the caller's code rather than a runtime error.

func (*Context) SaveUploadedFile

func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string, perm ...fs.FileMode) error

SaveUploadedFile saves a multipart file to the given destination path. Creates any necessary parent directories automatically. The optional perm parameter sets the directory permissions, defaulting to 0o750.

The uploaded file is opened and closed internally — the caller does not need to manage the file lifecycle.

Example:

file, _ := ctx.FormFile("avatar")
if err := ctx.SaveUploadedFile(file, "./uploads/"+file.Filename); err != nil {
	_ = ctx.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
	return
}

func (*Context) Set

func (c *Context) Set(key string, value any)

Set stores a key-value pair in the Context, making it available to subsequent handlers and middlewares within the same request lifecycle. It is safe for concurrent use.

Example:

ctx.Set("userID", "123")
ctx.Set("role", "admin")

func (*Context) SetCookie

func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool)

SetCookie writes a Set-Cookie header to the response. The value is automatically URL-encoded and decoded by Cookie. If path is empty, it defaults to "/".

func (*Context) SetCookieData

func (c *Context) SetCookieData(cookie *http.Cookie)

SetCookieData writes a Set-Cookie header using a pre-built http.Cookie. If Path is empty, it defaults to "/". If SameSite is http.SameSiteDefaultMode, it uses the value set by SetSameSite.

func (*Context) SetSameSite

func (c *Context) SetSameSite(samesite http.SameSite)

SetSameSite sets the SameSite attribute used for cookies set via SetCookie. Defaults to http.SameSiteDefaultMode if not called.

func (*Context) Status

func (c *Context) Status(code int)

Status writes the HTTP status code to the response header. Must be called before writing the response body.

func (*Context) String

func (c *Context) String(code int, message string) (err error)

String writes a plain string message to the response with the given status code. Unlike JSON or XML, it does not set a Content-Type header — the caller is responsible for setting it beforehand if needed.

Example:

ctx.Header("Content-Type", "text/html; charset=utf-8")
_ = ctx.String(http.StatusOK, "<h1>Hello</h1>")

func (*Context) Value

func (c *Context) Value(key any) any

Value implements context.Context. It looks up key in the following order:

  1. If key is a string, searches in the keys stored via Set.
  2. Delegates to the underlying request context.

This allows *Context to be passed directly to any function that accepts a context.Context, including database drivers, HTTP clients, and tracers.

Note: only string keys are searched in the local store. Non-string keys are delegated to the request context, where external libraries store their own values.

func (*Context) XML

func (c *Context) XML(code int, obj any) error

XML serializes obj as XML and writes it to the response with the given status code. Sets Content-Type to "application/xml".

Example:

_ = ctx.XML(http.StatusOK, myStruct)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL