Help us shape the future of Go! Take the 2026 Go Developer Survey

extractors

package
v3.6.1 Latest Latest
Warning

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

Go to latest
Published: Oct 14, 2026 License: MIT Imports: 11 Imported by: 13

README

Extractors Package

Package providing shared value extraction utilities for Fiber middleware packages.

Audience

This README is targeted at middleware developers and contributors. If you are a Fiber framework user looking to use extractors in your application, please refer to the Extractors Guide instead.

Architecture

Core Types
  • Extractor: Core extraction function with metadata
  • Source: Enumeration of extraction sources (Header, AuthHeader, Query, Form, Param, Cookie, Custom)
  • ErrNotFound: Standardized error for missing values
Extractor Structure
type Extractor struct {
  Extract    func(fiber.Ctx) (string, error)
  Key        string      // The parameter/header name used for extraction
  AuthScheme string      // The auth scheme used, e.g., "Bearer"
  Chain      []Extractor // For chained extractors, stores all extractors in the chain
  Source     Source      // Declared/static source metadata (first child for a chain)
}

Source-aware extraction does not add fields to Extractor, so existing unkeyed literals and keyed constructors keep working. Use Resolve for the winning source.

Resolve reports provenance as a Result:

type Result struct {
  Value    string // The extracted value
  Key      string // The parameter/header/cookie name the winning extractor read
  Source   Source // The kind of source the winning extractor read from
  Resolved bool   // Whether Key and Source name the extractor that actually produced Value
}

A Result carries metadata only — nothing runnable — so a chain's defensive copy of its children cannot be reached through it.

Resolved is false when a chain's own Extract answered without any child being observed to win — a full replacement, or a decorator that does not delegate. Key and Source are then the chain's declared metadata (its first child), which says nothing about where the value came from. Anything deciding from provenance that a value may be written back to where it was read from must treat Resolved: false as "origin unknown" and refuse, exactly as it would a read-only source. A record only counts when the chain being resolved is the one that made it, so a value is never credited to a chain some unrelated helper happened to run.

Available Functions
  • FromAuthHeader(authScheme string): Extract from Authorization header with optional scheme
  • FromCookie(key string): Extract from HTTP cookies
  • FromParam(param string): Extract from URL path parameters
  • FromForm(param string): Extract from form data
  • FromHeader(header string): Extract from custom HTTP headers
  • FromQuery(param string): Extract from URL query parameters
  • FromCustom(key string, fn func(fiber.Ctx) (string, error)): Define custom extraction logic with metadata
  • Chain(extractors ...Extractor): Chain multiple extractors with fallback
  • Resolve(e Extractor, c fiber.Ctx) (Result, error): Extract a value and report which extractor supplied it (Result.Value, Result.Key, Result.Source)
  • Extractor.Walk(fn func(Extractor) bool): Visit this extractor and every nested chained extractor, depth first and in chain order, stopping early when fn returns false
  • Extractor.Contains(pred func(Extractor) bool): Check whether this extractor, or any nested chained extractor, matches a predicate
Source Inspection

Extractor.Source is declared/static metadata, not an authoritative proof of origin by itself:

  • For a single built-in extractor it matches that constructor's source.
  • For a Chain, static Source is always the first child's source.
  • SourceHeader is the zero value of Source. A legacy Extract-only extractor that omits Source therefore reports SourceHeader through Resolve.
  • On failure (err != nil), Resolve may still return static or last-child metadata even though no value was supplied. Treat the reported Key and Source as meaningful only when err == nil and Resolved is true.
  • Result carries metadata only, never anything runnable, so a chain's defensive copy of its children cannot be reached through it.

Prefer Resolve when security or audit decisions depend on which source actually produced the value, or when a value must be written back to where it was read from. Verify the reported source before acting on it:

tokenExtractor := extractors.Chain(
    extractors.FromHeader("X-API-Key"),
    extractors.FromQuery("api_key"),
)
res, err := extractors.Resolve(tokenExtractor, c)
if err != nil {
    return err
}
token := res.Value
switch res.Source {
case extractors.SourceAuthHeader:
    // Authorization header - commonly used for authentication tokens
case extractors.SourceHeader:
    // Custom HTTP headers - application-specific data
case extractors.SourceCookie:
    // HTTP cookies - client-side stored data
case extractors.SourceQuery:
    // URL query parameters - visible in URLs and logs (security consideration)
case extractors.SourceForm:
    // Form data - POST body data
case extractors.SourceParam:
    // URL path parameters - route-based data
case extractors.SourceCustom:
    // Custom extraction logic
}

Resolve always calls Extract when set (leaves and chains), so decorating Extract for validation or normalization is visible to source-aware callers. Built-in Chain.Extract records the winning child during that pass; Resolve consumes the capture (no second child walk). If Extract succeeds without a capture (custom full replacement, or leaf), the declared static metadata is returned — Chain children are not re-executed to guess provenance. There is no Resolve struct field.

Consumers that need the winning extractor must go through Resolve rather than walking the Chain field themselves: a hand-rolled walk calls the children directly and silently skips a chain-level Extract.

Chain Behavior

The Chain function implements fallback logic:

  • Returns first successful extraction (non-empty value, no error)
  • If all extractors fail, returns the last error encountered or ErrNotFound
  • Skips extractors with nil Extract (zero-value children)
  • Detects recursive chain re-entry and returns ErrChainCycle (shared guard across Extract and Resolve)
  • Preserves Source and Key from the first extractor for static introspection (not AuthScheme)
  • Exposes a separate defensive copy via the Chain field for introspection; mutating it does not change which children Extract runs
  • On success with Resolved true, Resolve reports the winning child's Key and Source
  • On failure, the returned source is fallback metadata only — do not treat it as the origin of an extracted value
Chain Introspection

Use Contains to inspect a single extractor or extractor tree with a predicate.

chain := Chain(
    FromHeader("X-CSRF-Token"),
    FromCookie("CSRF"),
)

hasCSRFCookie := chain.Contains(func(e Extractor) bool {
    return e.Source == SourceCookie && e.Key == "CSRF"
})

Security Considerations

Source Awareness and Custom Extractors

As described in the Source Inspection section, the Source field enables middleware to enforce security policies based on data source:

  • CSRF Protection: The double-submit-cookie pattern requires tokens to be submitted in both a cookie AND a form field/header. Source awareness allows CSRF middleware to verify that tokens come from both expected sources, and not for example only from cookies
  • Authentication: Security middleware can enforce source-specific policies (e.g., auth tokens from headers, not query parameters)
  • Audit Trails: Source information enables security analysis and compliance reporting

However, when using FromCustom, middleware cannot determine the source of the extracted value, which can limit the ability of a middleware to provide warnings about potential security risks. Documentation and examples should clearly warn about these risks when using custom extractors.

Walking a chain

Never range over the Chain field to find the extractors inside a tree. That sees only direct children, and judges a nested chain by its declared metadata — its first child — so everything below it is invisible. Use Walk, which descends the whole tree in chain order and carries the cycle guard:

var sinks []extractors.Extractor
cfg.Extractor.Walk(func(candidate extractors.Extractor) bool {
    if len(candidate.Chain) > 0 || candidate.Key == "" {
        return true // a chain is not itself a sink
    }
    if candidate.Source == extractors.SourceCookie {
        sinks = append(sinks, candidate)
    }
    return true
})

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrChainCycle = errors.New("cyclic extractor chain")

ErrChainCycle is returned when a chain extractor recursively invokes itself.

View Source
var ErrNotFound = errors.New("value not found")

ErrNotFound is returned when the requested value is missing or empty.

Functions

This section is empty.

Types

type Extractor

type Extractor struct {
	Extract    func(fiber.Ctx) (string, error)
	Key        string      // The parameter/header name used for extraction
	AuthScheme string      // The auth scheme used, e.g., "Bearer"
	Chain      []Extractor // For chained extractors, stores all extractors in the chain
	Source     Source      // The type of source being extracted from
}

Extractor defines a value extraction method with metadata.

func Chain

func Chain(extractors ...Extractor) Extractor

Chain creates an Extractor that tries multiple extractors in order until one succeeds. This implements a fallback pattern where multiple extraction sources are attempted in sequence.

The function:

  • Tries each extractor in the order provided
  • Returns the first successful extraction (non-empty value with no error)
  • Skips children with a nil Extract function
  • Returns the last error encountered if all extractors fail
  • Returns ErrNotFound if no extractors are provided or all return empty values
  • Resolve on a chain walks the same children and reports the winning extractor

Parameters:

  • extractors: A variadic list of Extractor instances to try in sequence. The order matters - more secure/preferred sources should be listed first.

Returns:

An Extractor that attempts each provided extractor in order.
The returned extractor uses the Source and Key from the first extractor for
static metadata. Resolve reports the winning child.

Behavior:

  • Success: Returns the first non-empty value with no error
  • Partial failure: Continues to next extractor if current returns error or empty value
  • Total failure: Returns last error encountered, or ErrNotFound if no errors
  • Empty chain: Always returns ErrNotFound
  • Extract and Resolve share one cycle guard so a child that re-enters the same chain still returns ErrChainCycle. The guard is cleared on return, so sequential Extract then Resolve is fine.

Examples:

// Try header first, then cookie, then query param
extractor := Chain(
    FromHeader("Authorization"),
    FromCookie("auth_token"),
    FromQuery("token"),
)

// API key from multiple possible sources
apiKeyExtractor := Chain(
    FromHeader("X-API-Key"),
    FromQuery("api_key"),
    FromForm("apiKey"),
)

Security Note:

Order extractors by security preference. Most secure sources (headers, cookies)
should be attempted before less secure ones (query params, form data).

func FromAuthHeader

func FromAuthHeader(authScheme string) Extractor

FromAuthHeader extracts a value from the Authorization header with an optional prefix. This function implements RFC 9110 compliant Authorization header parsing with strict token68 validation.

RFC Compliance:

  • Follows RFC 9110 Section 11.6.2 for Authorization header format
  • Requires exactly one SP between auth-scheme and credentials. RFC 9110 permits 1*SP, but a single space is what clients send in practice and the stricter rule keeps the parse unambiguous.
  • Implements RFC 7235 token68 character validation for extracted tokens
  • Case-insensitive auth scheme matching per HTTP standards

Token68 Validation:

  • Only allows characters: A-Z, a-z, 0-9, -, ., _, ~, +, /, =
  • Rejects tokens containing spaces, tabs, or other whitespace
  • Validates proper padding: = only at end, no characters after padding starts
  • Prevents tokens starting with = (invalid padding)

Security Features:

  • Strict validation prevents header injection attacks
  • Rejects malformed tokens that could bypass authentication
  • Consistent error handling for missing or invalid credentials

Parameters:

  • authScheme: The auth scheme to strip from the header value (e.g., "Bearer", "Basic"). If empty, the entire header value is returned without validation.

Returns:

An Extractor that attempts to retrieve and parse the Authorization header.
Returns ErrNotFound if the header is missing, malformed, or doesn't match the expected scheme.

Examples:

// Extract Bearer token with validation
extractor := FromAuthHeader("Bearer")
// Input: "Bearer abc123" -> Output: "abc123"
// Input: "Bearer abc def" -> Output: ErrNotFound (space in token)
// Input: "Basic dXNlcjpwYXNz" -> Output: ErrNotFound (wrong scheme)

// Extract raw header value (no validation)
extractor := FromAuthHeader("")
// Input: "CustomAuth token123" -> Output: "CustomAuth token123"

func FromCookie

func FromCookie(key string) Extractor

FromCookie creates an Extractor that retrieves a value from a specified cookie in the request.

The function:

  • Retrieves the cookie value using the specified name
  • Returns ErrNotFound if the cookie is missing

Parameters:

  • key: The name of the cookie from which to extract the value.

Returns:

An Extractor that attempts to retrieve the value from the specified cookie.
Returns ErrNotFound if the cookie is not present.

Security Note:

Cookies are generally more secure than query parameters for sensitive data
as they are not logged in access logs or visible in browser history.
However, ensure cookies are properly secured with appropriate flags.

Example:

extractor := FromCookie("session_id")
// Cookie: "session_id=abc123" -> Output: "abc123"
// Missing cookie -> Output: ErrNotFound

func FromCustom

func FromCustom(key string, fn func(fiber.Ctx) (string, error)) Extractor

FromCustom creates an Extractor using a provided function. This allows for custom extraction logic beyond the built-in extractors.

The function:

  • Accepts a custom extraction function with signature func(fiber.Ctx) (string, error)
  • Handles nil functions gracefully by returning ErrNotFound
  • Preserves the custom function for execution

Parameters:

  • key: A descriptive identifier for the custom extractor. Used for debugging, logging, and Chain metadata. Should be meaningful for introspection. Examples: "X-Custom-Header", "Database-Lookup", "Cache-Key"
  • fn: The custom function to extract the value from the fiber.Ctx. If nil, the extractor will return ErrNotFound when executed. The function should return (value, nil) on success or ("", error) on failure.

Returns:

An Extractor that uses the provided function for extraction.
If fn is nil, the returned extractor will always return ErrNotFound.

Examples:

// Custom header with transformation
extractor := FromCustom("X-API-Key", func(c fiber.Ctx) (string, error) {
    value := c.Get("X-API-Key")
    if value == "" {
        return "", ErrNotFound
    }
    return strings.ToUpper(value), nil
})

// Database lookup (pseudo-code)
userExtractor := FromCustom("user-from-db", func(c fiber.Ctx) (string, error) {
    userID := c.Params("userId")
    user, err := db.GetUser(userID)
    if err != nil {
        return "", err
    }
    return user.Name, nil
})

// Conditional extraction
smartExtractor := FromCustom("smart-auth", func(c fiber.Ctx) (string, error) {
    if c.Get("X-Service-Auth") != "" {
        return c.Get("X-Service-Auth"), nil
    }
    return c.Cookies("session"), nil
})

func FromForm

func FromForm(param string) Extractor

FromForm creates an Extractor that retrieves a value from a specified form field in the request. Form data is typically submitted via POST requests with content-type application/x-www-form-urlencoded.

SECURITY WARNING: Extracting values from form data can leak sensitive information through:

  • Server access logs and error logs
  • Browser referrer headers (especially if form is submitted via GET)
  • Proxy and intermediary server logs
  • Browser history (if form uses GET method)

For sensitive data, prefer FromAuthHeader or FromCookie instead. If using form data, ensure the form uses POST method and HTTPS.

Parameters:

  • param: The name of the form field from which to extract the value.

Returns:

An Extractor that attempts to retrieve the value from the specified form field.
Returns ErrNotFound if the field is not present.

Example:

extractor := FromForm("username")
// Form data: "username=john_doe&password=secret" -> Output: "john_doe"
// Missing field -> Output: ErrNotFound

func FromHeader

func FromHeader(header string) Extractor

FromHeader creates an Extractor that retrieves a value from a specified HTTP header in the request. HTTP headers are commonly used for API keys, tokens, and other metadata.

The function:

  • Retrieves the header value using the specified name
  • Returns ErrNotFound if the header is missing

Parameters:

  • header: The name of the HTTP header from which to extract the value.

Returns:

An Extractor that attempts to retrieve the value from the specified HTTP header.
Returns ErrNotFound if the header is not present.

Security Note:

Headers are generally secure for sensitive data as they are not logged
in access logs by default. However, be aware that some proxies may log headers.

Example:

extractor := FromHeader("X-API-Key")
// Header: "X-API-Key: abc123" -> Output: "abc123"
// Missing header -> Output: ErrNotFound

func FromParam

func FromParam(param string) Extractor

FromParam creates an Extractor that retrieves a value from a specified URL parameter in the request. URL parameters are extracted from the route path (e.g., /users/:id).

SECURITY WARNING: Extracting values from URL parameters can leak sensitive information through:

  • Server access logs and error logs
  • Browser referrer headers when following links
  • Proxy and intermediary server logs
  • Browser history and bookmarks
  • Network monitoring tools

For sensitive data, prefer FromAuthHeader, FromCookie, or FromHeader instead.

Parameters:

  • param: The name of the URL parameter from which to extract the value.

Returns:

An Extractor that attempts to retrieve the value from the specified URL parameter.
Returns ErrNotFound if the parameter is not present.

Example:

// Route: GET /users/:userId/posts/:postId
userExtractor := FromParam("userId")
postExtractor := FromParam("postId")
// URL: /users/123/posts/456 -> userId: "123", postId: "456"

func FromQuery

func FromQuery(param string) Extractor

FromQuery creates an Extractor that retrieves a value from a specified query parameter in the request. Query parameters are extracted from the URL query string (e.g., ?key=value&foo=bar).

SECURITY WARNING: Extracting values from URL query parameters can leak sensitive information through:

  • Server access logs and error logs
  • Browser referrer headers when following links
  • Proxy and intermediary server logs
  • Browser history and bookmarks
  • Network monitoring tools and packet sniffers
  • Web browser developer tools

For sensitive data, prefer FromAuthHeader, FromCookie, or FromHeader instead. If query parameters must be used, ensure HTTPS is enforced.

Parameters:

  • param: The name of the query parameter from which to extract the value.

Returns:

An Extractor that attempts to retrieve the value from the specified query parameter.
Returns ErrNotFound if the parameter is not present.

Example:

extractor := FromQuery("token")
// URL: /api/data?token=abc123&format=json -> Output: "abc123"
// URL: /api/data?format=json -> Output: ErrNotFound

func (Extractor) Contains added in v3.4.0

func (e Extractor) Contains(pred func(Extractor) bool) bool

Contains reports whether this extractor, or any extractor in its chain, matches pred.

If pred is nil, Contains returns false.

func (Extractor) Walk added in v3.6.0

func (e Extractor) Walk(fn func(Extractor) bool)

Walk visits this extractor and every extractor nested in its Chain, depth first and in chain order, stopping early when fn returns false. A chain that re-enters itself is visited once. If fn is nil, Walk does nothing.

Prefer this to ranging over Chain, which sees only direct children and judges a nested chain by its declared metadata rather than by what is inside it.

type Result added in v3.6.0

type Result struct {
	// Value is the extracted value, non-empty only when err was nil.
	Value string

	// Key is the parameter, header or cookie name the winning extractor read.
	Key string

	// Source is the kind of source the winning extractor read from.
	Source Source

	// Resolved reports whether Key and Source name the extractor that actually
	// produced Value. It is false when a chain's own Extract answered without a
	// child winning: Key and Source are then the chain's declared metadata (its
	// first child) and say nothing about the value's origin, so a caller
	// deciding where a value may be written back must refuse. Always false on
	// error.
	Resolved bool
}

Result is a resolved extraction: the value, and the provenance of the extractor that supplied it.

It carries metadata only, so a chain's defensive copy of its children is never reachable through it.

func Resolve added in v3.6.0

func Resolve(e Extractor, c fiber.Ctx) (Result, error)

Resolve extracts a value and reports which extractor supplied it.

Prefer this over Extract when the caller needs a value's provenance — its Key as well as its Source — such as to write the value back where it was read from. It adds no field to Extractor, so unkeyed literals keep compiling.

Extract runs when set, so overrides and decoration are honored. A built-in Chain records its winning child as it runs, and only a record made by the chain being resolved counts, so a value is never credited to a chain some unrelated helper ran. Without such a record the declared metadata is reported with Resolved false rather than re-walking e.Chain to guess. An extractor with no Extract walks its own Chain instead, nested ones included; a built-in chain still runs only the children it can run. An extractor with neither returns ErrNotFound.

Key and Source are meaningful for security decisions only when err is nil and Resolved is true.

type Source

type Source int

Source represents the type of source from which an API key is extracted. This is informational metadata that helps developers understand the extractor behavior.

const (
	// SourceHeader indicates the value is extracted from an HTTP header.
	SourceHeader Source = iota

	// SourceAuthHeader indicates the value is extracted from the Authorization header.
	SourceAuthHeader

	// SourceForm indicates the value is extracted from form data.
	SourceForm

	// SourceQuery indicates the value is extracted from URL query parameters.
	SourceQuery

	// SourceParam indicates the value is extracted from URL path parameters.
	SourceParam

	// SourceCookie indicates the value is extracted from cookies.
	SourceCookie

	// SourceCustom indicates the value is extracted using a custom extractor function.
	SourceCustom
)

Jump to

Keyboard shortcuts

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