ada

package module
v0.4.7 Latest Latest
Warning

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

Go to latest
Published: Jul 15, 2026 License: MIT Imports: 18 Imported by: 1

README

ada

License Coverage GitHub Workflow Status Go Report Card Go PKG Web

Simple, flexible go web framework.

go get github.com/rakunlabs/ada

Usage

Check out the guide for more details.

package main

import (
	"net/http"

	"github.com/rakunlabs/ada"
)

func main() {
	server := ada.New()
	server.GET("/hello/{user}", SayHello)

	server.Start(":8080")
}

// /////////////////////

func SayHello(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Hello, " + r.PathValue("user")))
}

Runtime Middleware Reload

Replace, disable, or add middlewares at runtime without restarting:

auth := ada.NewSlot(forwardauth.Middleware(
    forwardauth.WithAddress("http://auth:8080/verify"),
))
server.Use(auth.Middleware())

// Hot-swap at runtime
auth.Replace(forwardauth.Middleware(forwardauth.WithAddress("http://auth-v2:8080")))
auth.Disable()  // bypass
auth.Enable()   // restore

// Or manage multiple middlewares by key
stack := ada.NewPipeline()
stack.Set("cors", cors.Middleware(...))
stack.Set("auth", forwardauth.Middleware(...))
server.Use(stack.Middleware())

stack.Set("ratelimit", ratelimit.Middleware(...))  // add at runtime
stack.Remove("auth")                                // remove at runtime

See the Runtime Reload guide for full details.

Documentation

Index

Constants

View Source
const (
	MIMEApplicationJSON                  = "application/json"
	MIMEApplicationJSONCharsetUTF8       = MIMEApplicationJSON + "; " + charsetUTF8
	MIMEApplicationJavaScript            = "application/javascript"
	MIMEApplicationJavaScriptCharsetUTF8 = MIMEApplicationJavaScript + "; " + charsetUTF8
	MIMEApplicationXML                   = "application/xml"
	MIMEApplicationXMLCharsetUTF8        = MIMEApplicationXML + "; " + charsetUTF8
	MIMETextXML                          = "text/xml"
	MIMETextXMLCharsetUTF8               = MIMETextXML + "; " + charsetUTF8
	MIMEApplicationForm                  = "application/x-www-form-urlencoded"
	MIMEApplicationProtobuf              = "application/protobuf"
	MIMEApplicationMsgpack               = "application/msgpack"
	MIMETextHTML                         = "text/html"
	MIMETextHTMLCharsetUTF8              = MIMETextHTML + "; " + charsetUTF8
	MIMETextPlain                        = "text/plain"
	MIMETextPlainCharsetUTF8             = MIMETextPlain + "; " + charsetUTF8
	MIMEMultipartForm                    = "multipart/form-data"
	MIMEMultipartMixed                   = "multipart/mixed"
	MIMEOctetStream                      = "application/octet-stream"
)
View Source
const (
	HeaderContentType        = "Content-Type"
	HeaderContentDisposition = "Content-Disposition"
	HeaderXRequestID         = "X-Request-Id"
	HeaderVary               = "Vary"
	HeaderOrigin             = "Origin"
	HeaderLocation           = "Location"

	HeaderAccessControlAllowOrigin      = "Access-Control-Allow-Origin"
	HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
	HeaderAccessControlExposeHeaders    = "Access-Control-Expose-Headers"
	HeaderAccessControlRequestMethod    = "Access-Control-Request-Method"
	HeaderAccessControlRequestHeaders   = "Access-Control-Request-Headers"
	HeaderAccessControlAllowMethods     = "Access-Control-Allow-Methods"
	HeaderAccessControlAllowHeaders     = "Access-Control-Allow-Headers"
	HeaderAccessControlMaxAge           = "Access-Control-Max-Age"
)
View Source
const MethodQuery = "QUERY"

MethodQuery is the QUERY HTTP method, a safe and idempotent method that carries the query semantics in the request body. Defined in RFC 10008 "The HTTP QUERY Method"; not yet available as a constant in net/http.

Variables

View Source
var (
	DefaultShutdownTimeout   = 10 * time.Second
	DefaultReadHeaderTimeout = 10 * time.Second
	ErrAlreadyStarted        = errors.New("server started already")
	ErrListen                = errors.New("listen")

	ListenerAddrContextKey = "listener_addr"
)
View Source
var DefaultErrHandler = func(c *Context, err error) {
	c.SendJSON(map[string]string{"message": err.Error()})
}

Functions

func Chain added in v0.1.0

func Chain(middlewares ...func(next http.Handler) http.Handler) func(next http.Handler) http.Handler

Chain is a utility function to chain multiple middleware functions together.

Types

type Context added in v0.1.0

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

func NewContext added in v0.1.0

func NewContext(w http.ResponseWriter, r *http.Request) *Context

func (*Context) Bind added in v0.1.10

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

Bind binds the request data to the provided struct based on content type and struct tags.

  • The obj parameter must be a pointer.

func (*Context) Err added in v0.1.10

func (c *Context) Err(err error) error

func (*Context) SendBlob added in v0.1.14

func (c *Context) SendBlob(reader io.Reader) error

SendBlob streams data from an io.Reader to the response.

  • The caller is responsible for setting appropriate headers (e.g., Content-Type).

func (*Context) SendFile added in v0.1.14

func (c *Context) SendFile(name string, reader io.Reader) error

SendFile sends a single file to the client.

func (*Context) SendJSON added in v0.1.9

func (c *Context) SendJSON(data any) error

SendJSON sends a json response.

func (*Context) SendJSONP added in v0.1.9

func (c *Context) SendJSONP(data any, indent string) error

SendJSONP sends a json pretty-printed response.

func (*Context) SendJSONRaw added in v0.1.10

func (c *Context) SendJSONRaw(data io.Reader) error

func (*Context) SendNoContent added in v0.1.9

func (c *Context) SendNoContent() error

SendNoContent always sends a 204 No Content response without body.

func (*Context) SendString added in v0.1.10

func (c *Context) SendString(s string) error

func (*Context) SendZip added in v0.1.14

func (c *Context) SendZip(name string, files map[string]io.Reader) error

SendZip sends files to the client as a zip file.

  • If name is empty, defaults to "files.zip".

func (*Context) SetHeader added in v0.1.9

func (c *Context) SetHeader(kv ...string) *Context

SetHeader sets a response header.

SetHeader("Content-Type", "application/json", "X-Custom-Header", "value")

func (*Context) SetStatus added in v0.1.9

func (c *Context) SetStatus(code int) *Context

SetStatus sets the response status code.

  • Use http package constants for standard status codes like http.StatusOK

type HandlerFunc added in v0.1.9

type HandlerFunc func(c *Context) error

type Logger added in v0.1.0

type Logger interface {
	Error(msg string, keysAndValues ...any)
	Info(msg string, keysAndValues ...any)
	Debug(msg string, keysAndValues ...any)
	Warn(msg string, keysAndValues ...any)
}

type MiddlewareFunc added in v0.3.0

type MiddlewareFunc = func(next http.Handler) http.Handler

MiddlewareFunc is the canonical middleware signature used by ada.

func NoOp added in v0.3.0

func NoOp() MiddlewareFunc

NoOp returns a middleware that does nothing and passes through to the next handler. Useful as a placeholder for disabled Slots or empty Pipelines.

type Mux added in v0.1.0

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

func NewMux added in v0.1.0

func NewMux() *Mux

func (*Mux) CONNECT added in v0.1.0

func (m *Mux) CONNECT(path string, handler http.HandlerFunc, middlewares ...func(next http.Handler) http.Handler)

func (*Mux) DELETE added in v0.1.0

func (m *Mux) DELETE(path string, handler http.HandlerFunc, middlewares ...func(next http.Handler) http.Handler)

func (*Mux) ErrorHandler added in v0.1.9

func (m *Mux) ErrorHandler(handler func(c *Context, err error))

ErrorHandler sets the handler for 500 Internal Server Error responses.

  • If not set, it defaults to a generic error handler.
  • Only usable for ada.HandlerFunc handlers.

func (*Mux) GET added in v0.1.0

func (m *Mux) GET(path string, handler http.HandlerFunc, middlewares ...func(next http.Handler) http.Handler)

func (Mux) Group added in v0.1.0

func (m Mux) Group(pathGroup string, middlewares ...func(next http.Handler) http.Handler) *Mux

func (*Mux) HEAD added in v0.1.0

func (m *Mux) HEAD(path string, handler http.HandlerFunc, middlewares ...func(next http.Handler) http.Handler)

func (*Mux) Handle added in v0.1.0

func (m *Mux) Handle(path string, handler http.Handler, middlewares ...func(next http.Handler) http.Handler)

func (*Mux) HandleFunc added in v0.1.0

func (m *Mux) HandleFunc(path string, handler http.HandlerFunc, middlewares ...func(next http.Handler) http.Handler)

func (*Mux) HandleFuncWildcard added in v0.2.0

func (m *Mux) HandleFuncWildcard(path string, handler http.HandlerFunc, middlewares ...func(next http.Handler) http.Handler)

HandleFuncWildcard is registering all paths under the given path.

func (*Mux) HandleWildcard added in v0.2.0

func (m *Mux) HandleWildcard(path string, handler http.Handler, middlewares ...func(next http.Handler) http.Handler)

HandleWildcard is registering all paths under the given path.

func (*Mux) HandleWithMethod added in v0.1.2

func (m *Mux) HandleWithMethod(method, path string, handler http.HandlerFunc, middlewares ...func(next http.Handler) http.Handler)

func (*Mux) MethodNotAllowed added in v0.3.0

func (m *Mux) MethodNotAllowed(handler http.HandlerFunc)

MethodNotAllowed sets the handler for 405 Method Not Allowed responses.

  • If not set, it defaults to a standard 405 text response.
  • The Allow header is always set before the handler is called.

func (*Mux) NotFound added in v0.1.0

func (m *Mux) NotFound(handler http.HandlerFunc)

NotFound sets the handler for 404 Not Found responses.

  • If not set, it defaults to http.NotFound.

func (*Mux) OPTIONS added in v0.1.0

func (m *Mux) OPTIONS(path string, handler http.HandlerFunc, middlewares ...func(next http.Handler) http.Handler)

func (*Mux) PATCH added in v0.1.0

func (m *Mux) PATCH(path string, handler http.HandlerFunc, middlewares ...func(next http.Handler) http.Handler)

func (*Mux) POST added in v0.1.0

func (m *Mux) POST(path string, handler http.HandlerFunc, middlewares ...func(next http.Handler) http.Handler)

func (*Mux) PUT added in v0.1.0

func (m *Mux) PUT(path string, handler http.HandlerFunc, middlewares ...func(next http.Handler) http.Handler)

func (*Mux) Prefix added in v0.2.10

func (m *Mux) Prefix() string

Prefix returns the current prefix of the Mux.

  • Useful when giving basepath for sub-routers.

func (*Mux) QUERY added in v0.4.6

func (m *Mux) QUERY(path string, handler http.HandlerFunc, middlewares ...func(next http.Handler) http.Handler)

QUERY registers a handler for the QUERY HTTP method, a safe and idempotent method with a request body carrying the query (RFC 10008).

func (*Mux) ServeHTTP added in v0.1.0

func (m *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements the http.Handler interface for Mux.

func (*Mux) TRACE added in v0.1.0

func (m *Mux) TRACE(path string, handler http.HandlerFunc, middlewares ...func(next http.Handler) http.Handler)

func (*Mux) Use added in v0.1.0

func (m *Mux) Use(middlewares ...func(next http.Handler) http.Handler)

func (*Mux) Wrap added in v0.1.9

func (m *Mux) Wrap(handler HandlerFunc) func(http.ResponseWriter, *http.Request)

Wrap converts ada.HandlerFunc to http.HandlerFunc.

type Option

type Option func(*option)

func WithLogger

func WithLogger(logger Logger) Option

func WithShutdownTimeout added in v0.1.0

func WithShutdownTimeout(timeout time.Duration) Option

WithShutdownTimeout sets the shutdown timeout, default is 10 seconds.

type OptionStart added in v0.1.7

type OptionStart func(*optionStart)

func WithBaseContext added in v0.1.8

func WithBaseContext(ctx context.Context) OptionStart

WithBaseContext sets the base context, default is context.Background().

  • Default is context.Background().

func WithContext added in v0.1.8

func WithContext(ctx context.Context) OptionStart

WithContext sets the context, usable for stopping the server.

  • Same as StartWithContext's ctx

func WithHTTPServerFunc added in v0.1.8

func WithHTTPServerFunc(fn func(server *http.Server) *http.Server) OptionStart

func WithNetwork added in v0.1.1

func WithNetwork(network string) OptionStart

WithNetwork sets the network, default is "tcp".

func WithReadHeaderTimeout added in v0.1.10

func WithReadHeaderTimeout(d time.Duration) OptionStart

WithReadHeaderTimeout sets the ReadHeaderTimeout for the http.Server.

  • Default is 5 seconds.

type Pipeline added in v0.3.0

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

Pipeline is a dynamically-managed ordered set of middlewares keyed by string. Middlewares can be added, replaced, removed, and reordered at runtime without re-registering routes.

The Pipeline is registered once via Pipeline.Middleware(); subsequent Set/Remove/Apply calls take effect on the next request. In-flight requests always observe a consistent snapshot.

Cost: one atomic pointer load per request (chain is pre-built on mutation).

Example:

stack := ada.NewPipeline()
stack.Set("cors", cors.Middleware(...))
stack.Set("auth", forwardauth.Middleware(...))
server.Use(stack.Middleware())

// later:
stack.Set("ratelimit", ratelimit.Middleware(...))  // add new
stack.Remove("auth")                                 // remove
stack.Apply(func(b *ada.PipelineBuilder) {           // batch
    b.Reset()
    b.Set("cors", newCorsMw)
    b.Set("auth", newAuthMw)
})

func NewPipeline added in v0.3.0

func NewPipeline() *Pipeline

NewPipeline creates an empty Pipeline.

func (*Pipeline) Apply added in v0.3.0

func (p *Pipeline) Apply(fn func(b *PipelineBuilder))

Apply runs fn with a PipelineBuilder that buffers mutations. When fn returns, all changes are published as a single atomic swap. In-flight requests continue with the old snapshot; new requests see the new one.

func (*Pipeline) ApplyWithTimeout added in v0.3.0

func (p *Pipeline) ApplyWithTimeout(fn func(b *PipelineBuilder), grace time.Duration)

ApplyWithTimeout runs fn as a batch and cancels in-flight requests through the old pipeline after the grace period.

A grace of 0 cancels immediately.

func (*Pipeline) Has added in v0.3.0

func (p *Pipeline) Has(key string) bool

Has reports whether a middleware is installed under the given key.

func (*Pipeline) Index added in v0.3.0

func (p *Pipeline) Index(key string) int

Index returns the position of the middleware with the given key, or -1 if not found.

func (*Pipeline) Keys added in v0.3.0

func (p *Pipeline) Keys() []string

Keys returns a copy of the current key order.

func (*Pipeline) Len added in v0.3.0

func (p *Pipeline) Len() int

Len reports the number of middlewares currently in the pipeline.

func (*Pipeline) Middleware added in v0.3.0

func (p *Pipeline) Middleware() MiddlewareFunc

Middleware returns a stable middleware closure suitable for registration with server.Use, Group, or route-level middleware arguments.

The returned closure captures `next` at registration time and uses a pre-built chain that is rebuilt only on mutation. Per-request cost is one atomic pointer load (~1 ns).

Calling Middleware multiple times returns independent closures that all observe the same pipeline state.

func (*Pipeline) Remove added in v0.3.0

func (p *Pipeline) Remove(key string) bool

Remove removes the middleware under the given key. Returns true if a middleware was removed.

func (*Pipeline) Reset added in v0.3.0

func (p *Pipeline) Reset()

Reset removes all middlewares atomically.

func (*Pipeline) Set added in v0.3.0

func (p *Pipeline) Set(key string, mw MiddlewareFunc)

Set installs or replaces the middleware under the given key. If the key is new, it is appended to the end of the pipeline. If the key already exists, its middleware is replaced in-place (order preserved).

func (*Pipeline) SetAt added in v0.3.0

func (p *Pipeline) SetAt(index int, key string, mw MiddlewareFunc)

SetAt installs or replaces a middleware at a specific position. If index is out of range, the entry is appended at the end. If the key already exists at a different position, it is moved to the new position.

func (*Pipeline) String added in v0.3.0

func (p *Pipeline) String() string

String returns a human-readable representation of the pipeline's current state. Useful for logging and debugging.

Example output:

Pipeline(3 middlewares):
  [0] cors
  [1] auth
  [2] ratelimit

type PipelineBuilder added in v0.3.0

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

PipelineBuilder buffers mutations for atomic application via Pipeline.Apply. All methods operate on an in-memory copy; no changes are visible until Apply returns.

func (*PipelineBuilder) Has added in v0.3.0

func (b *PipelineBuilder) Has(key string) bool

Has reports whether a middleware is installed under the given key.

func (*PipelineBuilder) Keys added in v0.3.0

func (b *PipelineBuilder) Keys() []string

Keys returns the current key order.

func (*PipelineBuilder) Len added in v0.3.0

func (b *PipelineBuilder) Len() int

Len reports the number of middlewares in the builder.

func (*PipelineBuilder) Remove added in v0.3.0

func (b *PipelineBuilder) Remove(key string) bool

Remove removes the middleware under the given key. Returns true if a middleware was removed.

func (*PipelineBuilder) Reset added in v0.3.0

func (b *PipelineBuilder) Reset()

Reset removes all middlewares from the builder.

func (*PipelineBuilder) Set added in v0.3.0

func (b *PipelineBuilder) Set(key string, mw MiddlewareFunc)

Set installs or replaces a middleware under the given key. New keys are appended; existing keys are replaced in-place.

func (*PipelineBuilder) SetAt added in v0.3.0

func (b *PipelineBuilder) SetAt(index int, key string, mw MiddlewareFunc)

SetAt installs or replaces a middleware at a specific position. If the key already exists at a different position, it is moved. If index is out of range, the entry is appended.

type Server

type Server struct {
	*Mux
	// contains filtered or unexported fields
}

func New

func New(opts ...Option) *Server

func NewWithFunc added in v0.1.0

func NewWithFunc(ctx context.Context, fn func(ctx context.Context, mux *Mux) error, opts ...Option) (*Server, error)

func (*Server) Start

func (s *Server) Start(addr string, opts ...OptionStart) error

Start starts the server with the given address.

  • If the server fails to start, an error will be returned.

func (*Server) StartWithContext added in v0.1.1

func (s *Server) StartWithContext(ctx context.Context, addr string, opts ...OptionStart) error

StartWithContext starts the server with the given context and address.

  • If the context is canceled, the server will be stopped.
  • If the server fails to start, an error will be returned.

func (*Server) Stop

func (s *Server) Stop() error

type Slot added in v0.3.0

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

Slot wraps a middleware in an atomic pointer, allowing it to be replaced, disabled, or re-enabled at runtime without re-registering routes.

A Slot may be registered with server.Use, Group, or as a per-route middleware argument. All registration points share the same underlying state; a single Replace/Disable/Enable call affects every location where the Slot was used.

Cost: two atomic pointer loads per request (~2 ns). When a WithTimeout variant is active, one context derivation is added per request.

Example:

auth := ada.NewSlot(forwardauth.Middleware(
    forwardauth.WithAddress("http://auth:8080/verify"),
))
server.Use(auth.Middleware())
server.GET("/api/me", meHandler)

// later, at runtime:
auth.Replace(forwardauth.Middleware(
    forwardauth.WithAddress("http://auth-v2:8080/verify"),
))
auth.Disable()   // bypass
auth.Enable()    // restore

func NewSlot added in v0.3.0

func NewSlot(mw MiddlewareFunc) *Slot

NewSlot creates a new enabled Slot initialized with the given middleware. If mw is nil, the slot starts with NoOp (pass-through).

No cancel context is created by default. Cancel contexts are only created by WithTimeout variants (ReplaceWithTimeout, DisableWithTimeout), keeping the per-request overhead at zero for the common case.

func (*Slot) Disable added in v0.3.0

func (s *Slot) Disable()

Disable makes the slot a pass-through without discarding the underlying middleware. The previously-set middleware is preserved and can be restored with Enable. In-flight requests using the old middleware finish normally.

func (*Slot) DisableWithTimeout added in v0.3.0

func (s *Slot) DisableWithTimeout(grace time.Duration)

DisableWithTimeout makes the slot a pass-through and cancels in-flight requests through the old middleware after the grace period.

A grace of 0 cancels immediately.

func (*Slot) Enable added in v0.3.0

func (s *Slot) Enable()

Enable restores the slot to its previously-set middleware. If the slot is already enabled, this is a no-op.

func (*Slot) Enabled added in v0.3.0

func (s *Slot) Enabled() bool

Enabled reports whether the slot is currently enabled.

func (*Slot) Middleware added in v0.3.0

func (s *Slot) Middleware() MiddlewareFunc

Middleware returns a stable middleware closure suitable for registration with server.Use, Group, or route-level middleware arguments.

The returned closure uses a pre-built handler chain that is rebuilt only on mutation. Per-request cost is two atomic pointer loads (~2 ns) with zero allocations.

Every call returns a new closure, but all closures read from the same underlying atomic pointer. Registering the same Slot in multiple places is safe; Replace/Disable/Enable propagates to all of them.

Note: if the same Slot is registered in stacked locations (e.g. root Use AND a child Group), the middleware runs once per registration point per request in that group. This matches how non-slotted middlewares behave.

func (*Slot) Replace added in v0.3.0

func (s *Slot) Replace(mw MiddlewareFunc)

Replace atomically swaps the underlying middleware. The slot remains enabled after the swap. In-flight requests using the old middleware finish normally.

func (*Slot) ReplaceWithTimeout added in v0.3.0

func (s *Slot) ReplaceWithTimeout(mw MiddlewareFunc, grace time.Duration)

ReplaceWithTimeout atomically swaps the underlying middleware and cancels in-flight requests through the old middleware after the grace period.

Requests that complete before the grace period expires are unaffected. After the grace period, the old generation's context is cancelled; handlers that respect ctx.Done() will abort, others finish normally (best-effort).

A grace of 0 cancels immediately.

Note: only in-flight requests from a previous WithTimeout generation can be cancelled. Requests from a generation created by NewSlot, Replace, or Enable do not have a cancel context and are unaffected.

Directories

Path Synopsis
handler
folder module
mcp module
swagger module
middleware
auth module
cors module
encoding module
folder module
forwardauth module
log module
log/logzero module
ratelimit module
recover module
requestid module
server module
telemetry module
timeout module
utils
securecookie
Package securecookie encodes and decodes authenticated and optionally encrypted cookie values.
Package securecookie encodes and decodes authenticated and optionally encrypted cookie values.
sessions
Package sessions provides cookie-based session management for ada.
Package sessions provides cookie-based session management for ada.

Jump to

Keyboard shortcuts

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