interceptor

package
v1.27.0 Latest Latest
Warning

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

Go to latest
Published: Sep 11, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Overview

Package interceptor is the contract a third-party request interceptor implements — and nothing else.

Every other extension point in this framework is reached the way database/sql drivers are: a package registers itself in an init function, an application imports it for the side effect, and configuration names it. Storage providers, session stores, authentication backends and federated identity providers all work that way. The request lifecycle did not.

Middleware could be attached — but only by whoever CONSTRUCTS the application, or by a module that is mounted. A package that an application merely imports had no way in, which meant an interceptor could not be distributed as a plugin: it had to be code the application author pasted into their own bootstrap in the right order. That is the gap ADR-023 recorded as "observing is possible today, intercepting is not".

Ordering is the behaviour, so an operator declares it

Middleware order is not a detail: authentication before rate limiting and rate limiting before authentication are different systems. So an interceptor is not merely enabled, it is placed — `http_interceptors` is an ORDERED list, the way `auth_backends` is, and the order in the file is the order requests pass through.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Register

func Register(name string, factory Factory) error

Register makes an interceptor selectable by name from configuration.

Call it from an init function in the implementing package, then import that package for its side effects:

func init() {
    interceptor.Register("audit", New)
}

A name already taken is an error rather than a silent replacement: two packages claiming "audit" would make the effective interceptor depend on import order, and for something in the request path that is a security control whose identity depends on the order of an import block.

func Registered

func Registered() []string

Registered returns every selectable interceptor name, sorted.

func Unregister

func Unregister(name string)

Unregister removes a registered interceptor. It exists for tests that register a fake and must not leak it into the next one.

Types

type Config

type Config struct {
	// Name is the registered name the operator selected this interceptor
	// by.
	Name string

	// ProviderConfig is the raw `interceptors.<name>.*` subtree. Read it
	// with Bind rather than reaching into the map.
	ProviderConfig map[string]any
}

Config carries the `interceptors.<name>.*` subtree that belongs to one registered interceptor.

It is defined here rather than aliased from the authentication contract, even though the shape is identical. An interceptor has nothing to do with authentication, and borrowing that package's type would have made every third-party interceptor compile the auth contract to read a config map — a dependency inherited for a resemblance rather than for a reason. Bind behaves exactly as it does for a backend.

func (Config) Bind

func (c Config) Bind(dst any) error

Bind decodes the interceptor's own configuration subtree into dst, applying `default:` tags to fields the file left unset.

A key the destination struct does not declare is an ERROR, not a silently ignored line: an interceptor is usually a protection, and a misspelled setting on a protection is the kind of thing an audit finds months later.

type Factory

type Factory func(cfg Config) (Interceptor, error)

Factory builds a configured interceptor.

Returning an error fails BOOT rather than the first request. An interceptor that could not configure itself is a protection that is not there, and a protection that is not there must not be discovered by an audit six months later.

func Lookup

func Lookup(name string) (Factory, bool)

Lookup returns the factory registered under name.

type Interceptor

type Interceptor func(http.Handler) http.Handler

Interceptor wraps a handler. It is the standard Go middleware shape on purpose: an existing func(http.Handler) http.Handler needs no adapter, and an author already knows the contract.

func Build

func Build(names []string, providerConfig map[string]map[string]any) ([]Interceptor, error)

Build resolves an ORDERED list of registered names into the chain of interceptors, handing each one its own configuration subtree.

The returned slice is in the same order as names: first in the list is outermost, so it sees the request first and the response last — the order middleware is normally read in.

An unregistered name fails, naming what IS registered. That error is the only place an operator discovers the registry exists, and a typo in a list of request interceptors must not resolve to "one fewer protection, quietly".

Jump to

Keyboard shortcuts

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