router

package
v1.1.20 Latest Latest
Warning

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

Go to latest
Published: Mar 21, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package router provides a lightweight, JSON-centric wrapper around Go's native http.ServeMux.

It simplifies building JSON APIs by offering a consolidated "Exchange" object for handling requests and responses, standardized error formatting, and a middleware chaining mechanism.

Basic Usage:

// 1. Setup the router with options
logger := log.New()
r := router.New(
	router.WithLogger(logger),
	router.WithMiddleware(middleware.Log(logger)),
)

// 2. Define a handler
// You can use a closure, or a struct that satisfies the Handler interface.
r.HandleFunc("POST /users", func(e *router.Exchange) error {
	var req CreateUserRequest

	// BindJSON enforces Content-Type and parses the body.
	// It returns a specific *router.Error type if validation fails.
	if err := e.BindJSON(&req); err != nil {
		return err
	}

	// ... Logic to save user ...

	// Return JSON response
	return e.JSON(http.StatusCreated, UserResponse{ID: "123"})
})

// 3. Start the server
http.ListenAndServe(":8080", r)

Index

Constants

View Source
const (
	// ReasonWrongType indicates that the request had an unsupported content type.
	ReasonWrongType = "wrong_type"
	// ReasonEmptyBody indicates that the request body was empty.
	ReasonEmptyBody = "empty_body"
	// ReasonParseJSON indicates that there was an error parsing the JSON body.
	ReasonParseJSON = "parse_json"
	// ReasonParseForm indicates that there was an error parsing form data.
	ReasonParseForm = "parse_form"
	// ReasonServerError indicates that an unexpected internal error occurred.
	ReasonServerError = "server_error"
)

Standard error reasons used for machine-readable error codes.

View Source
const (
	// MediaTypeJSON is the media type for JSON content.
	MediaTypeJSON = "application/json"
	// MediaTypeForm is the media type for URL-encoded form data.
	MediaTypeForm = "application/x-www-form-urlencoded"
)

Standard media types used in the Content-Type header.

Variables

This section is empty.

Functions

This section is empty.

Types

type Error

type Error struct {
	// Status is the HTTP status code (e.g., 400, 404, 500).
	Status int `json:"status"`
	// Reason is a short string identifying the error type (e.g.,
	// "invalid_input").
	Reason string `json:"reason"`
	// Description is a human-readable explanation of the error cause.
	Description string `json:"description"`
	// ID is a unique identifier of the specific occurrence for tracing purposes
	// (optional).
	ID string `json:"id,omitempty"`
	// Context contains arbitrary additional data about the error, such as
	// validation fields.
	Context map[string]any `json:"context,omitempty"`
	// Cause is the underlying error that triggered this error (if any).
	// It is excluded from JSON serialization to prevent leaking internal details.
	Cause error `json:"-"`
}

Error describes the standardized shape of API errors returned to clients.

Handlers can return this struct directly to control the HTTP status code and error details. If a handler returns a standard Go error, the Router will wrap it in a generic internal server error.

func (*Error) Error

func (e *Error) Error() string

Error implements the standard [error] interface.

type ErrorHandler added in v1.1.8

type ErrorHandler func(e *Exchange, err error)

ErrorHandler defines a function that handles errors returned by routes.

type Exchange

type Exchange struct {
	// R is the incoming HTTP request.
	R *http.Request
	// W is a writer for the outgoing HTTP response.
	W ResponseWriter
	// contains filtered or unexported fields
}

Exchange acts as a context object for a single HTTP request/response cycle.

It wraps the underlying *http.Request and http.ResponseWriter to provide convenient helper methods for common API tasks, such as parsing JSON, reading parameters, and writing structured responses.

func (*Exchange) BindJSON

func (e *Exchange) BindJSON(v any) *Error

BindJSON decodes the request body into v.

This method enforces strict API hygiene: 1. It verifies that the media type is "application/json". 2. It checks that the payload is not empty. 3. It unmarshals the JSON.

If any of these checks fail, it returns a structured error that handlers can return directly.

func (*Exchange) Context

func (e *Exchange) Context() context.Context

Context returns the request's context. This is commonly used for cancellation signals and request scoping.

func (*Exchange) Form added in v1.1.0

func (e *Exchange) Form(code int, v url.Values) error

Form writes the values as URL-encoded form data with the given status code.

It automatically sets the Content-Type header to MediaTypeForm if it has not already been set. When encoding fails, an error is returned.

func (*Exchange) GetHeader

func (e *Exchange) GetHeader(key string) string

GetHeader retrieves a specific header value from the request.

func (*Exchange) Header

func (e *Exchange) Header() http.Header

Header returns the HTTP headers of the request.

func (*Exchange) JSON

func (e *Exchange) JSON(code int, v any) error

JSON encodes v as JSON and writes it to the response with the given HTTP status code.

It automatically sets the Content-Type header to MediaTypeJSON if it has not already been set. When encoding fails, an error is returned.

func (*Exchange) Method

func (e *Exchange) Method() string

Method returns the HTTP method (GET, POST, etc.) of the request.

func (*Exchange) NoContent added in v1.1.8

func (e *Exchange) NoContent()

NoContent sends a HTTP 204 No Content response.

func (*Exchange) Param

func (e *Exchange) Param(name string) string

Param retrieves a path parameter by name.

This relies on the routing pattern (e.g., "GET /users/{id}"). If the parameter does not exist, it returns an empty string.

func (*Exchange) Path

func (e *Exchange) Path() string

Path returns the URL path of the request.

func (*Exchange) Query

func (e *Exchange) Query() url.Values

Query parses the URL query parameters of the request. Malformed pairs will be silently discarded.

func (*Exchange) ReadForm added in v1.1.0

func (e *Exchange) ReadForm() (url.Values, *Error)

ReadForm parses the request body as URL-encoded form data and returns the values.

Unlike the standard http.Request.FormValue, this strictly accesses the PostForm (body) only, ignoring URL query parameters. This is crucial for security protocols like OAuth to prevent query parameter injection.

func (*Exchange) Redirect

func (e *Exchange) Redirect(url string, code int) error

Redirect replies to the request with a redirect to url, which may be a path relative to the request path.

Any non-ASCII characters in url will be percent-encoded, but existing percent encodings will not be changed. The provided code should be in the 3xx range.

func (*Exchange) RedirectTo added in v1.1.0

func (e *Exchange) RedirectTo(base string, params url.Values, code int) error

RedirectTo constructs a URL by merging the base URL with the provided query parameters and redirects the client.

This is particularly useful for callbacks.

func (*Exchange) SetHeader

func (e *Exchange) SetHeader(key, value string)

SetHeader sets a specific header value in the response.

func (*Exchange) Status

func (e *Exchange) Status(code int)

Status sends an HTTP response header with the provided status code.

Note: Calling this method commits the response headers. You should not call this method directly if you intend to write a body later (e.g., using JSON() or Form()), as those methods will set the status code themselves. It is primarily used for empty responses like HTTP 204 (No Content).

func (*Exchange) URL

func (e *Exchange) URL() *url.URL

URL returns the full URL of the request.

type Handler

type Handler interface {
	// ServeHTTP processes an HTTP request encapsulated in the Exchange object.
	ServeHTTP(e *Exchange) error
}

Handler defines the interface for HTTP request handlers used by the Router.

This interface allows using struct-based handlers (useful for dependency injection) in addition to simple functions.

type HandlerFunc

type HandlerFunc func(e *Exchange) error

HandlerFunc defines the function signature for HTTP request handlers.

func (HandlerFunc) ServeHTTP

func (f HandlerFunc) ServeHTTP(e *Exchange) error

ServeHTTP satisfies the Handler interface, allowing HandlerFunc to be used wherever a Handler is expected.

type Option

type Option func(*Router)

Option defines a functional configuration option for the Router.

func WithErrorHandler added in v1.1.8

func WithErrorHandler(h ErrorHandler) Option

WithErrorHandler sets a custom error handler. This allows you to override the default JSON error formatting.

func WithJSONOptions added in v1.1.8

func WithJSONOptions(opts ...json.Options) Option

WithJSONOptions sets custom JSON options for the Router. They configure both, marshaling and unmarshaling operations.

func WithLogger

func WithLogger(log *slog.Logger) Option

WithLogger updates the default error handler to use the given logger. If not set, the Router defaults to using slog.Default(). A nil value will be ignored.

func WithMaxBodySize added in v1.1.8

func WithMaxBodySize(bytes int64) Option

WithMaxBodySize sets the maximum allowed size for request bodies. Defaults to 0 (unlimited), but typically should be set (e.g., 1MB).

func WithMiddleware

func WithMiddleware(pipes ...middleware.Pipe) Option

WithMiddleware adds global middleware pipes to the Router. These pipes are applied to every route registered with the Router.

type ResponseWriter added in v1.1.8

type ResponseWriter interface {
	http.ResponseWriter
	// Status returns the HTTP status code written, or 0 if not written yet.
	Status() int
	// Closed reports whether the headers have already been written.
	// This indicates that the response is committed.
	Closed() bool
	// Unwrap returns the underlying http.ResponseWriter.
	// This allows [http.ResponseController] to access features like Flush(),
	// Hijack(), and SetReadDeadline().
	Unwrap() http.ResponseWriter
}

ResponseWriter extends the standard http.ResponseWriter with introspection capabilities.

It allows handlers and middleware to check if the response headers have already been written, which is crucial for robust error handling.

func NewResponseWriter added in v1.1.8

func NewResponseWriter(w http.ResponseWriter) ResponseWriter

NewResponseWriter wraps an http.ResponseWriter into a ResponseWriter.

type Router

type Router struct {
	// Mux is the underlying [http.ServeMux]. It is exposed to allow direct
	// usage with [http.ListenAndServe].
	Mux *http.ServeMux
	// contains filtered or unexported fields
}

Router represents an HTTP request router with middleware support.

func New

func New(opts ...Option) *Router

New creates a new Router instance with the provided options.

func (*Router) Handle

func (r *Router) Handle(
	pattern string,
	handler Handler,
	mws ...middleware.Pipe,
)

Handle registers a new route with the given pattern, handler, and optional middleware pipes.

The pattern string must follow Go 1.22+ syntax (e.g., "GET /users/{id}").

The handler is wrapped with the Router's global middleware and any local middleware provided for this specific route.

func (*Router) HandleFunc

func (r *Router) HandleFunc(
	pattern string,
	fn func(*Exchange) error,
	mws ...middleware.Pipe,
)

HandleFunc is a convenience wrapper for Handle that accepts a function instead of a Handler interface.

func (*Router) Mount

func (r *Router) Mount(pattern string, handler http.Handler)

Mount registers a standard http.Handler (like http.FileServer) under a pattern.

The handler will still be wrapped by the Router's global middleware, ensuring logging/auth logic applies to these routes as well.

func (*Router) ServeHTTP

func (r *Router) ServeHTTP(res http.ResponseWriter, req *http.Request)

ServeHTTP satisfies the http.Handler interface, allowing the Router to be used directly with HTTP servers. It delegates request handling to the underlying http.ServeMux.

Jump to

Keyboard shortcuts

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