Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Dispatchers

Dispatchers handle how requests are processed and responses are generated. Every operation in your OpenAPI or AsyncAPI spec needs an x-barbacane-dispatch extension.

Overview

paths:
  /example:
    get:
      x-barbacane-dispatch:
        name: <dispatcher-name>
        config:
          # dispatcher-specific config

Available Dispatchers

All dispatchers are implemented as WASM plugins and must be declared in your barbacane.yaml manifest.

mock

Returns static responses. Useful for health checks, stubs, and testing.

x-barbacane-dispatch:
  name: mock
  config:
    status: 200
    body: '{"status":"ok"}'

Configuration

PropertyTypeDefaultDescription
statusinteger200HTTP status code
bodystring""Response body
headersobject{}Additional response headers
content_typestring"application/json"Content-Type header value

Examples

Simple health check:

x-barbacane-dispatch:
  name: mock
  config:
    status: 200
    body: '{"status":"healthy","version":"1.0.0"}'

Not found response:

x-barbacane-dispatch:
  name: mock
  config:
    status: 404
    body: '{"error":"resource not found"}'

Empty success:

x-barbacane-dispatch:
  name: mock
  config:
    status: 204

Custom headers:

x-barbacane-dispatch:
  name: mock
  config:
    status: 200
    body: '<html><body>Hello</body></html>'
    content_type: 'text/html'
    headers:
      X-Custom-Header: 'custom-value'
      Cache-Control: 'no-cache'

http-upstream

Reverse proxy to an HTTP/HTTPS upstream backend. Supports path parameter substitution, header forwarding, and configurable timeouts.

x-barbacane-dispatch:
  name: http-upstream
  config:
    url: "https://api.example.com"
    path: "/api/v2/resource"
    timeout: 30.0

Configuration

PropertyTypeRequiredDefaultDescription
urlstringYes-Base URL of the upstream (must be HTTPS in production)
pathstringNoSame as operation pathUpstream path template with {param} substitution
timeoutnumberNo30.0Request timeout in seconds
tlsobjectNo-TLS configuration for mTLS (see below)
TLS Configuration (mTLS)

For upstreams that require mutual TLS (client certificate authentication):

PropertyTypeRequiredDescription
tls.client_certstringIf mTLSPath to PEM-encoded client certificate
tls.client_keystringIf mTLSPath to PEM-encoded client private key
tls.castringNoPath to PEM-encoded CA certificate for server verification

Example with mTLS:

x-barbacane-dispatch:
  name: http-upstream
  config:
    url: "https://secure-backend.internal"
    tls:
      client_cert: "/etc/barbacane/certs/client.crt"
      client_key: "/etc/barbacane/certs/client.key"
      ca: "/etc/barbacane/certs/ca.crt"

Notes:

  • Both client_cert and client_key must be specified together
  • Certificate files must be in PEM format
  • The ca option adds a custom CA for server verification (in addition to system roots)
  • TLS-configured clients are cached and reused across requests

Path Parameters

Path parameters from the OpenAPI spec are automatically substituted in the path template:

# OpenAPI path: /users/{userId}/orders/{orderId}
/users/{userId}/orders/{orderId}:
  get:
    x-barbacane-dispatch:
      name: http-upstream
      config:
        url: "https://backend.internal"
        path: "/api/users/{userId}/orders/{orderId}"

# Request: GET /users/123/orders/456
# Backend: GET https://backend.internal/api/users/123/orders/456

Path Rewriting

Map frontend paths to different backend paths:

# Frontend: /v2/products
# Backend: https://catalog.internal/api/v1/catalog/products
/v2/products:
  get:
    x-barbacane-dispatch:
      name: http-upstream
      config:
        url: "https://catalog.internal"
        path: "/api/v1/catalog/products"

Wildcard Proxy

Proxy any path to upstream using a greedy wildcard parameter ({param+}):

/proxy/{path+}:
  get:
    parameters:
      - name: path
        in: path
        required: true
        allowReserved: true
        schema:
          type: string
    x-barbacane-dispatch:
      name: http-upstream
      config:
        url: "https://httpbin.org"
        path: "/{path}"
        timeout: 10.0

Timeout Override

Per-operation timeout for long-running operations:

/reports/generate:
  post:
    x-barbacane-dispatch:
      name: http-upstream
      config:
        url: "https://reports.internal"
        path: "/generate"
        timeout: 120.0  # 2 minutes for report generation

Error Handling

The dispatcher returns RFC 9457 error responses:

StatusCondition
502 Bad GatewayConnection failed or upstream returned invalid response
503 Service UnavailableCircuit breaker is open
504 Gateway TimeoutRequest exceeded configured timeout

Security

  • HTTPS required in production: http:// URLs are rejected by the compiler (E1031)
  • Development mode: Use --allow-plaintext at compile time and --allow-plaintext-upstream at runtime
  • TLS: Uses rustls with system CA roots by default
  • mTLS: Configure tls.client_cert and tls.client_key for mutual TLS authentication
  • Custom CA: Use tls.ca to add a custom CA certificate for private PKI

lambda

Invokes AWS Lambda functions via Lambda Function URLs. Implemented as a WASM plugin.

x-barbacane-dispatch:
  name: lambda
  config:
    url: "https://abc123.lambda-url.us-east-1.on.aws/"

Configuration

PropertyTypeRequiredDefaultDescription
urlstringYes-Lambda Function URL
timeoutnumberNo30.0Request timeout in seconds
pass_through_headersbooleanNotruePass incoming headers to Lambda

Setup

  1. Enable Lambda Function URLs in AWS Console or via CLI
  2. Use the generated URL in your OpenAPI spec
# Enable Function URL for your Lambda
aws lambda create-function-url-config \
  --function-name my-function \
  --auth-type NONE

# Get the URL
aws lambda get-function-url-config --function-name my-function

Examples

Basic Lambda invocation:

/api/process:
  post:
    x-barbacane-dispatch:
      name: lambda
      config:
        url: "https://abc123.lambda-url.us-east-1.on.aws/"

With custom timeout:

/api/long-running:
  post:
    x-barbacane-dispatch:
      name: lambda
      config:
        url: "https://xyz789.lambda-url.eu-west-1.on.aws/"
        timeout: 120.0

Request/Response Format

The dispatcher passes the incoming HTTP request to Lambda:

  • Method, headers, and body are forwarded
  • Lambda should return a standard HTTP response

Lambda response format:

{
  "statusCode": 200,
  "headers": {"content-type": "application/json"},
  "body": "{\"result\": \"success\"}"
}

Error Handling

StatusCondition
502 Bad GatewayLambda invocation failed or returned invalid response
504 Gateway TimeoutRequest exceeded configured timeout

kafka

Publishes messages to Apache Kafka topics. Designed for AsyncAPI specs using the sync-to-async bridge pattern: HTTP POST requests publish messages and return 202 Accepted. Uses a pure-Rust Kafka client with connection caching and a dedicated runtime.

x-barbacane-dispatch:
  name: kafka
  config:
    brokers: "kafka.internal:9092"
    topic: "user-events"

Configuration

PropertyTypeRequiredDefaultDescription
brokersstringYes-Comma-separated Kafka broker addresses (e.g. "kafka:9092" or "broker1:9092, broker2:9092")
topicstringYes-Kafka topic to publish to
keystringNo-Message key expression (see below)
ack_responseobjectNo-Custom acknowledgment response
include_metadatabooleanNofalseInclude partition/offset in response
headers_from_requestarrayNo[]Request headers to forward as message headers
Key Expression

The key property supports dynamic expressions:

ExpressionDescription
$request.header.X-KeyExtract key from request header
$request.path.userIdExtract key from path parameter
literal-valueUse a literal string value
Custom Acknowledgment Response

Override the default 202 Accepted response:

x-barbacane-dispatch:
  name: kafka
  config:
    brokers: "kafka.internal:9092"
    topic: "orders"
    ack_response:
      body: {"queued": true, "estimatedDelivery": "5s"}
      headers:
        X-Queue-Name: "orders"

Examples

Basic Kafka publish:

# AsyncAPI spec
asyncapi: "3.0.0"
info:
  title: Order Events
  version: "1.0.0"
channels:
  orderEvents:
    address: /events/orders
    messages:
      OrderCreated:
        payload:
          type: object
          properties:
            orderId:
              type: string
operations:
  publishOrder:
    action: send
    channel:
      $ref: '#/channels/orderEvents'
    x-barbacane-dispatch:
      name: kafka
      config:
        brokers: "kafka.internal:9092"
        topic: "order-events"
        key: "$request.header.X-Order-Id"
        include_metadata: true

With request header forwarding:

x-barbacane-dispatch:
  name: kafka
  config:
    brokers: "kafka.internal:9092"
    topic: "audit-events"
    headers_from_request:
      - "x-correlation-id"
      - "x-user-id"

Response

On successful publish, returns 202 Accepted:

{
  "status": "accepted",
  "topic": "order-events",
  "partition": 3,
  "offset": 12345
}

(partition/offset only included if include_metadata: true)

Error Handling

StatusCondition
502 Bad GatewayKafka publish failed

nats

Publishes messages to NATS subjects. Designed for AsyncAPI specs using the sync-to-async bridge pattern. Uses a pure-Rust NATS client with connection caching and a dedicated runtime.

x-barbacane-dispatch:
  name: nats
  config:
    url: "nats://nats.internal:4222"
    subject: "notifications.user"

Configuration

PropertyTypeRequiredDefaultDescription
urlstringYes-NATS server URL (e.g. "nats://localhost:4222")
subjectstringYes-NATS subject to publish to (supports wildcards)
ack_responseobjectNo-Custom acknowledgment response
headers_from_requestarrayNo[]Request headers to forward as message headers

Examples

Basic NATS publish:

asyncapi: "3.0.0"
info:
  title: Notification Service
  version: "1.0.0"
channels:
  notifications:
    address: /notifications/{userId}
    parameters:
      userId:
        schema:
          type: string
    messages:
      Notification:
        payload:
          type: object
          required:
            - title
          properties:
            title:
              type: string
            body:
              type: string
operations:
  sendNotification:
    action: send
    channel:
      $ref: '#/channels/notifications'
    x-barbacane-dispatch:
      name: nats
      config:
        url: "nats://nats.internal:4222"
        subject: "notifications"
        headers_from_request:
          - "x-request-id"

Custom acknowledgment:

x-barbacane-dispatch:
  name: nats
  config:
    url: "nats://nats.internal:4222"
    subject: "events.user.signup"
    ack_response:
      body: {"accepted": true}
      headers:
        X-Subject: "events.user.signup"

Response

On successful publish, returns 202 Accepted:

{
  "status": "accepted",
  "subject": "notifications"
}

Error Handling

StatusCondition
502 Bad GatewayNATS publish failed

s3

Proxies requests to AWS S3 or any S3-compatible object storage (MinIO, RustFS, Ceph, etc.) with AWS Signature Version 4 signing. Supports multi-bucket routing via path parameters and single-bucket CDN-style routes.

x-barbacane-dispatch:
  name: s3
  config:
    region: us-east-1
    access_key_id: env://AWS_ACCESS_KEY_ID
    secret_access_key: env://AWS_SECRET_ACCESS_KEY

Configuration

PropertyTypeRequiredDefaultDescription
access_key_idstringYes-AWS access key ID. Supports env:// references (e.g. env://AWS_ACCESS_KEY_ID)
secret_access_keystringYes-AWS secret access key. Supports env:// references
regionstringYes-AWS region (e.g. us-east-1, eu-west-1)
session_tokenstringNo-Session token for temporary credentials (STS / AssumeRole / IRSA). Supports env:// references
endpointstringNo-Custom S3-compatible endpoint URL (e.g. https://minio.internal:9000). When set, path-style URLs are always used
force_path_stylebooleanNofalseUse path-style URLs (s3.{region}.amazonaws.com/{bucket}/{key}) instead of virtual-hosted style. Automatically true when endpoint is set
bucketstringNo-Hard-coded bucket name. When set, bucket_param is ignored. Use for single-bucket routes like /assets/{key+}
bucket_paramstringNo"bucket"Name of the path parameter that holds the bucket
key_paramstringNo"key"Name of the path parameter that holds the object key
timeoutnumberNo30Request timeout in seconds

URL Styles

Virtual-hosted (default for AWS S3):

Host: {bucket}.s3.{region}.amazonaws.com
Path: /{key}

Path-style (set force_path_style: true or when endpoint is set):

Host: s3.{region}.amazonaws.com   # or custom endpoint host
Path: /{bucket}/{key}

Custom endpoints always use path-style regardless of force_path_style.

Wildcard Keys

Use {key+} (greedy wildcard) to capture multi-segment S3 keys containing slashes:

/files/{bucket}/{key+}:
  get:
    parameters:
      - { name: bucket, in: path, required: true, schema: { type: string } }
      - { name: key, in: path, required: true, allowReserved: true, schema: { type: string } }
    x-barbacane-dispatch:
      name: s3
      config:
        region: us-east-1
        access_key_id: env://AWS_ACCESS_KEY_ID
        secret_access_key: env://AWS_SECRET_ACCESS_KEY

GET /files/uploads/2024/01/report.pdf → S3 key 2024/01/report.pdf in bucket uploads.

Examples

Multi-bucket proxy with OIDC authentication:

paths:
  /storage/{bucket}/{key+}:
    get:
      parameters:
        - { name: bucket, in: path, required: true, schema: { type: string } }
        - { name: key, in: path, required: true, allowReserved: true, schema: { type: string } }
      x-barbacane-middlewares:
        - name: oidc-auth
          config:
            issuer: https://auth.example.com
            audience: my-api
            required: true
      x-barbacane-dispatch:
        name: s3
        config:
          region: eu-west-1
          access_key_id: env://AWS_ACCESS_KEY_ID
          secret_access_key: env://AWS_SECRET_ACCESS_KEY

Single-bucket CDN (hard-coded bucket, rate limited):

paths:
  /assets/{key+}:
    get:
      parameters:
        - { name: key, in: path, required: true, allowReserved: true, schema: { type: string } }
      x-barbacane-middlewares:
        - name: rate-limit
          config:
            quota: 120
            window: 60
      x-barbacane-dispatch:
        name: s3
        config:
          region: us-east-1
          bucket: public-assets
          access_key_id: env://AWS_ACCESS_KEY_ID
          secret_access_key: env://AWS_SECRET_ACCESS_KEY

S3-compatible storage (MinIO / RustFS):

x-barbacane-dispatch:
  name: s3
  config:
    region: us-east-1
    endpoint: https://minio.internal:9000
    access_key_id: env://MINIO_ACCESS_KEY
    secret_access_key: env://MINIO_SECRET_KEY
    bucket: uploads

Temporary credentials (STS / AssumeRole / IRSA):

x-barbacane-dispatch:
  name: s3
  config:
    region: us-east-1
    access_key_id: env://AWS_ACCESS_KEY_ID
    secret_access_key: env://AWS_SECRET_ACCESS_KEY
    session_token: env://AWS_SESSION_TOKEN
    bucket: my-bucket

Error Handling

StatusCondition
400 Bad RequestMissing bucket or key path parameter
502 Bad Gatewayhost_http_call failed (network error, endpoint unreachable)
403 / 404 / 5xxPassed through transparently from S3

Security

  • Credentials: Use env:// references so secrets are never baked into spec files or compiled artifacts
  • Session tokens: Support for STS, AssumeRole, and IRSA (IAM Roles for Service Accounts) via session_token
  • Signing: All requests are signed with AWS Signature Version 4. The signed headers are host, x-amz-content-sha256, x-amz-date, and x-amz-security-token (when a session token is present)
  • Binary objects: The current implementation returns the response body as a UTF-8 string. Binary objects (images, archives, etc.) are not suitable for this dispatcher — use pre-signed URLs for binary downloads

ws-upstream

Transparent WebSocket proxy. Upgrades the client connection to WebSocket and relays frames bidirectionally to an upstream WebSocket server. The gateway handles the full lifecycle: handshake, frame relay, and connection teardown.

x-barbacane-dispatch:
  name: ws-upstream
  config:
    url: "ws://echo.internal:8080"

Configuration

PropertyTypeRequiredDefaultDescription
urlstringYes-Upstream WebSocket URL (ws:// or wss://)
connect_timeoutnumberNo5Connection timeout in seconds (0.1–300)
pathstringNoSame as operation pathUpstream path template with {param} substitution

How It Works

  1. Client sends an HTTP request with Upgrade: websocket
  2. The plugin validates the upgrade header and connects to the upstream WebSocket server
  3. On success, the gateway returns 101 Switching Protocols to the client
  4. Frames are relayed bidirectionally between client and upstream until either side closes

The middleware chain (x-barbacane-middlewares) runs on the initial HTTP request and can inspect/modify headers, enforce authentication, apply rate limiting, etc. Once the connection is upgraded, middleware is bypassed for individual frames.

Path Parameters

Path parameters from the OpenAPI spec are substituted in the path template:

/ws/{room}:
  get:
    parameters:
      - name: room
        in: path
        required: true
        schema:
          type: string
    x-barbacane-dispatch:
      name: ws-upstream
      config:
        url: "ws://chat.internal:8080"
        path: "/rooms/{room}"

# Request: GET /ws/general → Upstream: ws://chat.internal:8080/rooms/general

Query String Forwarding

Query parameters from the client request are automatically forwarded to the upstream URL:

Client: GET /ws/echo?token=abc → Upstream: ws://echo.internal:8080/?token=abc

Examples

Basic WebSocket proxy:

/ws:
  get:
    x-barbacane-dispatch:
      name: ws-upstream
      config:
        url: "ws://backend.internal:8080"

With authentication and path routing:

/ws/{room}:
  get:
    parameters:
      - name: room
        in: path
        required: true
        schema:
          type: string
    x-barbacane-middlewares:
      - name: jwt-auth
        config:
          required: true
    x-barbacane-dispatch:
      name: ws-upstream
      config:
        url: "wss://realtime.internal"
        path: "/rooms/{room}"
        connect_timeout: 10

Secure upstream (WSS):

/live:
  get:
    x-barbacane-dispatch:
      name: ws-upstream
      config:
        url: "wss://stream.example.com"
        connect_timeout: 15

Error Handling

StatusCondition
400 Bad RequestMissing Upgrade: websocket header
502 Bad GatewayUpstream connection failed or timed out

Security

  • WSS in production: Use wss:// for encrypted upstream connections
  • Development mode: ws:// URLs are allowed with --allow-plaintext-upstream
  • Authentication: Apply auth middleware (jwt-auth, oidc-auth, etc.) to protect WebSocket endpoints — middleware runs on the initial upgrade request

Best Practices

Set Appropriate Timeouts

  • Fast endpoints (health, simple reads): 5-10s
  • Normal operations: 30s (default)
  • Long operations (reports, uploads): 60-120s
x-barbacane-dispatch:
  name: http-upstream
  config:
    url: "https://backend.internal"
    timeout: 10.0  # Quick timeout for simple operation

Mock for Development

Use mock dispatchers during API design:

/users/{id}:
  get:
    x-barbacane-dispatch:
      name: mock
      config:
        status: 200
        body: '{"id":"123","name":"Test User"}'

Then switch to real backend:

/users/{id}:
  get:
    x-barbacane-dispatch:
      name: http-upstream
      config:
        url: "https://user-service.internal"
        path: "/api/users/{id}"

Use HTTPS in Production

Barbacane enforces HTTPS for upstream connections at two levels:

FlagCommandPurpose
--allow-plaintextcompileAllow http:// URLs in spec (bypasses E1031 validation)
--allow-plaintext-upstreamserveAllow runtime HTTP client to connect to http:// upstreams

Why two flags?

  • Compile-time validation catches insecure URLs early in your CI pipeline
  • Runtime enforcement provides defense-in-depth, even if specs are modified

For local development with services like WireMock or Docker containers:

# Allow http:// URLs during compilation
barbacane compile --spec api.yaml --manifest barbacane.yaml --output api.bca --allow-plaintext

# Allow plaintext connections at runtime
barbacane serve --artifact api.bca --dev --allow-plaintext-upstream

In production, omit both flags to ensure all upstream connections use TLS.