zen

package module
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Jul 10, 2026 License: MIT Imports: 25 Imported by: 0

README

Zen

Go Reference

A lightweight, high-performance HTTP microframework for Go built on net/http. Zero-allocation radix tree routing, batteries-included middleware, and a minimal API.

Features

  • Radix tree router - per-method radix tree with zero-alloc path params, 405 detection, trailing-slash redirect
  • Request binding - bind JSON, XML, form, query, headers, and path params via struct tags
  • Pluggable validation - go-playground/validator integration with optional auto-validation
  • OpenAPI generation - auto-generated 3.0.3 spec + Swagger UI, zero cost when unused
  • Auth - JWT, Basic, API Key, Session, OAuth2, OIDC with RBAC/PBAC (separate auth package)
  • 8 built-in middleware - Recover, Logger, CORS, CSRF, Compress, Rate Limit, Body Limit, Pprof
  • Structured logger - colored output, slog levels (FATAL/ERROR/WARN/INFO/DEBUG/TRACE), NO_COLOR support
  • Zero external router dependencies - pure net/http + slog

Installation

go get github.com/Pavan-Silva/go-zen

Quick Start

package main

import (
    "github.com/Pavan-Silva/go-zen"
    "github.com/Pavan-Silva/go-zen/middleware"
)

func main() {
    r := zen.New(":8080")
    r.Use(middleware.Recover, middleware.Logger)

    r.GET("/hello", func(c *zen.Ctx) {
        c.String(200, "Hello, World!")
    })

    r.GET("/users/:id", func(c *zen.Ctx) {
        id := c.Param("id")
        c.JSON(200, map[string]string{"id": id})
    })

    r.Run()
}

Documentation

Full docs at zen-docs-steel.vercel.app.

License

MIT

Documentation

Overview

Package zen is a lightweight, high-performance HTTP microframework built on net/http with a custom radix tree router.

Quick Start

r := zen.New(":8080")
r.GET("/hello", func(c *zen.Ctx) {
    c.String(200, "Hello, World!")
})
r.Run()

Middleware

Zen supports both global and per-route middleware:

r.Use(middleware.Recover)
r.Use(middleware.Logger)

Routing

Routes use Go 1.22+ patterns with path parameters:

r.GET("/users/{id}", getUser)
r.POST("/users", createUser)
r.PUT("/users/{id}", updateUser)
r.DELETE("/users/{id}", deleteUser)

Route Groups

api := r.Group("/api")
api.HandleRaw("GET /health", healthCheck)

Binding and Validation

var req CreateUserRequest
if err := c.BindJSON(&req); err != nil {
    c.Error(400, "invalid request")
    return
}
if err := zen.Validate(&req); err != nil {
    c.Error(400, err.Error())
    return
}

Context and Lifecycle

A zen.Ctx is created per request via sync.Pool and released back after the request completes. The hot path avoids context.WithValue entirely; FromRequest is only needed for interop with standard http.Handler patterns.

Performance

Zen is designed for zero-allocation middleware chains, pooled Ctx and streaming JSON/XML encoding.

Index

Constants

This section is empty.

Variables

View Source
var ErrFlusherUnsupported = errors.New("sse: SSE requires http.Flusher")

ErrFlusherUnsupported is returned by SSEvent when the ResponseWriter does not implement http.Flusher.

View Source
var ErrInvalidBindTarget = errors.New("http: BindForm dest must be a pointer to a struct")

ErrInvalidBindTarget is returned by BindForm when dest is not a pointer to a struct.

Functions

func BytesToString added in v1.2.0

func BytesToString(b []byte) string

BytesToString converts a byte slice to a string without allocations.

func DefaultValidator added in v1.2.0

func DefaultValidator() *validator.Validate

DefaultValidator returns the underlying go-playground/validator/v10 instance when using the default built-in validator, or nil if a custom validator is set. Use this to register custom validation tags:

zen.DefaultValidator().RegisterValidation("is-even", func(fl validator.FieldLevel) bool {
    return fl.Field().Int()%2 == 0
})

func EnableAutoValidation added in v1.3.0

func EnableAutoValidation()

EnableAutoValidation enables automatic Validate() calls after BindJSON, BindXML, and BindForm.

func SetValidator added in v1.2.0

func SetValidator(v Validator)

SetValidator sets a custom validator for request validation. Pass nil to disable validation entirely.

func StringToBytes added in v1.2.0

func StringToBytes(s string) []byte

StringToBytes converts a string to a byte slice without allocations. The returned bytes MUST NOT be modified.

func Validate added in v1.2.0

func Validate(dest any) error

Validate runs struct validation on dest using the configured Validator. Call this explicitly after BindJSON, BindXML, or BindForm.

Types

type Config added in v1.2.0

type Config struct {
	ReadTimeout       time.Duration
	WriteTimeout      time.Duration
	IdleTimeout       time.Duration
	ReadHeaderTimeout time.Duration
	MaxHeaderBytes    int
	ShutdownTimeout   time.Duration
}

Config holds server-level timeout and header size settings. Use DefaultConfig to obtain sensible defaults, then override fields as needed.

func DefaultConfig added in v1.2.0

func DefaultConfig() Config

DefaultConfig returns a Config with standard timeout and buffer values. Timeouts and MaxHeaderBytes default to 0 to bypass the Go standard library's tracking loops, matching raw net/http performance baselines.

type Ctx added in v1.2.0

type Ctx struct {
	Response http.ResponseWriter
	Request  *http.Request
	// contains filtered or unexported fields
}

Ctx is the per-request context container for zen handlers and middleware components. Valid ONLY for the explicit lifetime of the request—never preserve references beyond handler returns.

func FromContext added in v1.2.0

func FromContext(ctx context.Context) (*Ctx, bool)

FromContext extracts a Ctx from a context.Context.

func FromRequest

func FromRequest(r *http.Request) (*Ctx, bool)

FromRequest extracts a Ctx from an http.Request.

func (*Ctx) Attachment added in v1.2.0

func (c *Ctx) Attachment(filePath, attachmentName string)

Attachment sends the requested file as a downloadable attachment. The Content-Disposition header is set with the provided attachment name. If attachmentName is empty, the file base name is used.

Example:

c.Attachment("/tmp/report.pdf", "monthly-report.pdf")

func (*Ctx) Bind added in v1.2.0

func (c *Ctx) Bind(dest any) error

Bind auto-detects the request content type and decodes the payload into dest. For GET, DELETE, and HEAD requests, it automatically populates query parameters first.

func (*Ctx) BindBody added in v1.2.0

func (c *Ctx) BindBody(dest any) error

BindBody parses the request body into dest based on the Content-Type header, completely skipping path and query parameters.

func (*Ctx) BindForm added in v1.2.0

func (c *Ctx) BindForm(dest any) error

BindForm parses URL-encoded or multipart form data into a struct.

Automatically runs struct validation after binding unless validation was explicitly disabled via the setup configuration.

Example:

type LoginForm struct {
    Email    string `form:"email" validate:"required,email"`
    Password string `form:"password" validate:"required,min=8"`
}

func (*Ctx) BindHeader added in v1.2.0

func (c *Ctx) BindHeader(dest any) error

BindHeader binds HTTP request headers to a struct using `header` or `json` tags. Header names are canonicalized via http.CanonicalHeaderKey at compile time.

Example:

type Headers struct {
    UserID string `header:"X-User-Id"`
    APIKey string `header:"X-Api-Key"`
    Rate   int    `header:"X-Rate-Limit"`
}

func (*Ctx) BindJSON added in v1.2.0

func (c *Ctx) BindJSON(dest any) error

BindJSON parses the request body as JSON and decodes it into dest. Uses json.NewDecoder which streams directly from the request body, avoiding intermediate byte slice allocations.

Automatically runs struct validation after decode if a Validator is configured.

func (*Ctx) BindPathParams added in v1.2.0

func (c *Ctx) BindPathParams(dest any) error

BindPathParams extracts route wildcards using native Go 1.22+ request context maps.

func (*Ctx) BindQueryParams added in v1.2.0

func (c *Ctx) BindQueryParams(dest any) error

BindQueryParams parses query parameters into dest struct fields.

func (*Ctx) BindXML added in v1.2.0

func (c *Ctx) BindXML(dest any) error

BindXML parses the request body as XML and decodes it into dest. Uses xml.NewDecoder which streams directly from the request body.

Automatically runs struct validation after decode if a Validator is configured.

Returns an error if the body is not valid XML, cannot be decoded, or struct validation fails.

Example:

var req CreateUserRequest
if err := c.BindXML(&req); err != nil {
    c.Error(http.StatusBadRequest, err.Error())
    return
}

func (*Ctx) Blob added in v1.2.0

func (c *Ctx) Blob(status int, contentType string, data []byte)

Blob writes a byte slice as the response body with the given content type. The response Content-Type is set to the provided MIME type. Write errors are logged but not returned (they indicate connection issues).

Example:

data := []byte("id,name\n1,John Doe")
c.Blob(http.StatusOK, "text/csv", data)

func (*Ctx) Body added in v1.2.0

func (c *Ctx) Body() ([]byte, error)

Body reads and returns the complete raw request body as a byte slice. It is the caller's responsibility to interpret the bytes.

func (*Ctx) Copy added in v1.2.0

func (c *Ctx) Copy() *Ctx

Copy returns a new Ctx with a deep copy of the store.

func (*Ctx) Error added in v1.2.0

func (c *Ctx) Error(status int, message string)

Error writes a plain text error message to the response with the given HTTP status. Unlike JSON(), this sends plain text without JSON encoding, similar to http.Error(). The response Content-Type header is set to "text/plain; charset=utf-8".

This is the preferred method for simple error responses where JSON structure is not needed. For structured error responses, use JSON() with a plain map or custom struct.

Example:

c.Error(http.StatusBadRequest, "invalid email format")

func (*Ctx) File added in v1.2.0

func (c *Ctx) File(filePath string)

File sends the requested file as the HTTP response body. The content type is inferred automatically and errors are handled by http.ServeFile.

Example:

c.File("/tmp/report.pdf")

func (*Ctx) FormFile added in v1.2.0

func (c *Ctx) FormFile(fieldName string) (*multipart.FileHeader, multipart.File, error)

FormFile retrieves a single file from a multipart form upload. Returns the file header and a file handle for streaming. The caller is responsible for closing the file.

Example:

header, file, err := c.FormFile("avatar")
if err != nil {
    c.Error(http.StatusBadRequest, err.Error())
    return
}
defer file.Close()

func (*Ctx) FormFiles added in v1.2.0

func (c *Ctx) FormFiles(fieldName string) ([]*multipart.FileHeader, error)

FormFiles retrieves all file headers for a multipart form field. The caller opens each file individually for streaming access.

Example:

headers, err := c.FormFiles("attachments")
if err != nil {
    c.Error(http.StatusBadRequest, err.Error())
    return
}
for _, h := range headers {
    file, _ := h.Open()
    defer file.Close()
}

func (*Ctx) Get added in v1.2.0

func (c *Ctx) Get(key string) (any, bool)

Get retrieves a value from the context store.

func (*Ctx) HTML added in v1.2.0

func (c *Ctx) HTML(status int, html string)

HTML writes an HTML string directly to the response with the given HTTP status. The response Content-Type header is automatically set to "text/html; charset=utf-8".

Write errors are logged but not returned (they indicate connection issues).

Example:

c.HTML(http.StatusOK, "<h1>Hello World</h1>")

func (*Ctx) Header added in v1.2.0

func (c *Ctx) Header(key string) string

Header returns the value of a request header by key. Returns an empty string if the header is not present.

Example:

token := c.Header("Authorization")  // "Bearer <token>"

func (*Ctx) Inline added in v1.2.0

func (c *Ctx) Inline(filePath string)

Inline sends the requested file to be displayed inline by the browser. The Content-Disposition header is set to inline.

Example:

c.Inline("/tmp/image.png")

func (*Ctx) JSON added in v1.2.0

func (c *Ctx) JSON(status int, data any)

JSON encodes data as JSON and streams it straight to the response writer.

Sets the "Content-Type" header to "application/json" automatically. Write errors are handled and logged safely via internal system loggers.

func (*Ctx) Keys added in v1.2.0

func (c *Ctx) Keys() map[string]any

Keys returns a copy of all key-value entries in the store.

func (*Ctx) Next added in v1.2.0

func (c *Ctx) Next()

Next calls the next handler in the chain.

func (*Ctx) Param added in v1.2.0

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

Param returns the URL path parameter for the given key.

Given a route registered as "GET /users/{id}", the handler can retrieve the captured segment with:

id := c.Param("id")  // GET /users/42 -> "42"

func (*Ctx) QueryParam added in v1.2.0

func (c *Ctx) QueryParam(key string) string

QueryParam returns the first value of a query parameter from the request URL. Returns an empty string if the parameter is not present.

Example:

page := c.QueryParam("page")      // GET /posts?page=2 -> "2"
search := c.QueryParam("q")       // GET /posts?q=golang-> "golang"

func (*Ctx) ReadFile added in v1.2.0

func (c *Ctx) ReadFile(fieldName string) (header *multipart.FileHeader, content []byte, err error)

ReadFile is a convenience method that reads a single uploaded file into memory. For large files, use FormFile() and stream the content instead.

func (*Ctx) Redirect added in v1.2.0

func (c *Ctx) Redirect(status int, location string)

Redirect sends an HTTP redirect to the specified location. It sets the Location header and writes the provided redirect status.

Example:

c.Redirect(http.StatusMovedPermanently, "https://example.com/new")

func (*Ctx) SSEvent added in v1.2.0

func (c *Ctx) SSEvent(event string, data any) error

SSEvent writes a Server-Sent Event to the client. It sets required SSE headers and flushes the response.

func (*Ctx) Set added in v1.2.0

func (c *Ctx) Set(key string, val any)

Set stores a value in the context. The internal map is allocated on first use.

func (*Ctx) Status added in v1.2.0

func (c *Ctx) Status(status int)

Status writes a response header with no-body and the given HTTP status.

Example:

c.Status(http.StatusNoContent)

func (*Ctx) Stream added in v1.2.0

func (c *Ctx) Stream(status int, contentType string, body io.Reader) error

Stream copies data from an io.Reader to the response body with the given content type. The response Content-Type is set to the provided MIME type.

Example:

f, err := os.Open("/tmp/image.png")
if err != nil {
    return err
}
defer f.Close()
return c.Stream(http.StatusOK, "image/png", f)

func (*Ctx) String added in v1.2.0

func (c *Ctx) String(status int, text string)

String writes a plain text string directly to the response with the given HTTP status.

Write errors are logged but not returned (they indicate connection issues).

Example:

c.String(http.StatusOK, "Hello World")

func (*Ctx) XML added in v1.2.0

func (c *Ctx) XML(status int, data any)

XML encodes data as XML and writes it to the response with the given HTTP status code. Uses xml.NewEncoder which streams directly to the response writer.

The response Content-Type header is automatically set to "application/xml". Write errors are logged but not returned (they indicate connection issues).

Example:

type Response struct {
    XMLName xml.Name `xml:"response"`
    Message string   `xml:"message"`
}
c.XML(http.StatusOK, Response{Message: "hello"})

type Engine added in v1.2.0

type Engine struct {
	RouterGroup
	// contains filtered or unexported fields
}

Engine is the top-level application container. It embeds a root RouterGroup and owns the radix tree router and the http.Server.

func New

func New(addr string, config ...Config) *Engine

New creates an Engine with the given listen address and optional custom Config.

func (*Engine) File added in v1.2.0

func (e *Engine) File(pattern, filePath string)

File serves a single file at the given path pattern via http.ServeFile.

func (*Engine) Run added in v1.2.0

func (e *Engine) Run()

Run starts the HTTP server and blocks until a shutdown signal is received.

func (*Engine) RunTLS added in v1.2.0

func (e *Engine) RunTLS(certFile, keyFile string)

RunTLS starts the HTTPS server with the given certificate and key files, and blocks until a shutdown signal is received.

func (*Engine) ServeHTTP added in v1.2.0

func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements the http.Handler interface using the radix tree router.

func (*Engine) Static added in v1.2.0

func (e *Engine) Static(prefix, root string)

Static serves static files from the given OS directory under the specified path prefix.

func (*Engine) StaticFS added in v1.2.0

func (e *Engine) StaticFS(prefix string, filesystem fs.FS)

StaticFS serves static files from any fs.FS under the specified path prefix.

type FormError

type FormError struct {
	Field string
	Err   error
}

FormError is returned by BindForm when a form value cannot be parsed into the target field's type (e.g., "abc" into an int field).

func (*FormError) Error

func (e *FormError) Error() string

Error implements the error interface.

func (*FormError) Unwrap

func (e *FormError) Unwrap() error

Unwrap returns the underlying cause error.

type HandlerFunc added in v1.2.0

type HandlerFunc func(*Ctx)

HandlerFunc is the universal type for both route handlers and middleware.

type RouterGroup added in v1.2.0

type RouterGroup struct {
	// contains filtered or unexported fields
}

RouterGroup groups routes under a common prefix with optional shared middleware. An Engine embeds a root RouterGroup; Group creates child groups.

func (*RouterGroup) DELETE added in v1.2.0

func (g *RouterGroup) DELETE(path string, handlers ...HandlerFunc)

DELETE registers a handler for the DELETE method.

func (*RouterGroup) GET added in v1.2.0

func (g *RouterGroup) GET(path string, handlers ...HandlerFunc)

GET registers a handler for the GET method. The final element in handlers is the main handler; preceding elements are middleware.

func (*RouterGroup) Group added in v1.2.0

func (g *RouterGroup) Group(prefix string, middleware ...HandlerFunc) *RouterGroup

Group creates a child group with an additional path prefix and optional middleware. The child group inherits all parent middleware and appends the new middleware after it. Uses a single upfront allocation to prevent double-allocation slice resizes.

func (*RouterGroup) HEAD added in v1.2.0

func (g *RouterGroup) HEAD(path string, handlers ...HandlerFunc)

HEAD registers a handler for the HEAD method.

func (*RouterGroup) HandleRaw added in v1.2.0

func (g *RouterGroup) HandleRaw(pattern string, handler http.Handler)

HandleRaw registers a raw http.Handler on the router using the zen handler chain. The pattern uses Go 1.22+ ServeMux syntax ({param}, {path...}) which is automatically converted to the router's native syntax (:param, *path). The group prefix is prepended to the path automatically.

func (*RouterGroup) OPTIONS added in v1.2.0

func (g *RouterGroup) OPTIONS(path string, handlers ...HandlerFunc)

OPTIONS registers a handler for the OPTIONS method.

func (*RouterGroup) PATCH added in v1.2.0

func (g *RouterGroup) PATCH(path string, handlers ...HandlerFunc)

PATCH registers a handler for the PATCH method.

func (*RouterGroup) POST added in v1.2.0

func (g *RouterGroup) POST(path string, handlers ...HandlerFunc)

POST registers a handler for the POST method.

func (*RouterGroup) PUT added in v1.2.0

func (g *RouterGroup) PUT(path string, handlers ...HandlerFunc)

PUT registers a handler for the PUT method.

func (*RouterGroup) Prefix added in v1.2.0

func (g *RouterGroup) Prefix() string

Prefix returns the full path prefix of this group.

func (*RouterGroup) Use added in v1.2.0

func (g *RouterGroup) Use(middleware ...HandlerFunc)

Use appends middleware to the group. Middleware runs for every route registered on this group.

type SkipFunc added in v1.2.0

type SkipFunc func(*http.Request) bool

SkipFunc decides whether a request should bypass middleware (auth, body limit, etc). It receives the current request and returns true for routes to skip.

type Validator added in v1.2.0

type Validator interface {
	Validate(i any) error
}

Validator is the interface for request validation. Implement this to plug in any validation library.

Example:

type CustomValidator struct {
    validator *validator.Validate
}

func (cv *CustomValidator) Validate(i any) error {
    return cv.validator.Struct(i)
}

Directories

Path Synopsis
Package auth provides authentication and authorization middleware (JWT, OAuth2, OIDC, Basic, RBAC, ABAC, PBAC, session).
Package auth provides authentication and authorization middleware (JWT, OAuth2, OIDC, Basic, RBAC, ABAC, PBAC, session).
Package env provides helpers for reading configuration from environment variables.
Package env provides helpers for reading configuration from environment variables.
Package logger provides a structured logging facade with slog backend and colored console output.
Package logger provides a structured logging facade with slog backend and colored console output.
Package middleware provides built-in HTTP middleware for zen (recovery, logging, CORS, CSRF, compression, rate limiting, body limit, pprof).
Package middleware provides built-in HTTP middleware for zen (recovery, logging, CORS, CSRF, compression, rate limiting, body limit, pprof).
Package openapi generates OpenAPI 3.0.3 specifications and serves the Swagger UI for zen routes.
Package openapi generates OpenAPI 3.0.3 specifications and serves the Swagger UI for zen routes.
Package system provides build-time metadata (version, banner) for the zen framework.
Package system provides build-time metadata (version, banner) for the zen framework.

Jump to

Keyboard shortcuts

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