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

Barbacane Documentation

Barbacane is a spec-driven API gateway. Define your API using OpenAPI, add Barbacane extensions for routing and middleware, compile to an artifact, and deploy.

Why Barbacane?

  • Spec-first: Your OpenAPI spec is the source of truth
  • Compile-time validation: Catch misconfigurations before deployment
  • Plugin architecture: Extend with WASM plugins for auth, rate limiting, transforms
  • Observable: Prometheus metrics, structured JSON logging, distributed tracing with OTLP export
  • European-made: Built in Europe, hosted on EU infrastructure

Quick Start

# Build from source (crates.io publishing planned for v1.0)
git clone https://github.com/barbacane/barbacane.git
cd barbacane && cargo build --release

# Add x-barbacane-dispatch to your OpenAPI spec
# Compile
./target/release/barbacane compile --spec api.yaml --output api.bca

# Run
./target/release/barbacane serve --artifact api.bca --listen 0.0.0.0:8080

Documentation

User Guide

Reference

Contributing

Supported Spec Versions

FormatVersionStatus
OpenAPI3.0.xSupported
OpenAPI3.1.xSupported
OpenAPI3.2.xSupported (draft)
AsyncAPI3.0.xSupported

AsyncAPI Support

Barbacane supports AsyncAPI 3.x for event-driven APIs. AsyncAPI send operations are accessible via HTTP POST requests, enabling a sync-to-async bridge pattern where HTTP clients can publish messages to Kafka or NATS brokers.

License

Apache 2.0 - See LICENSE

Getting Started

This guide walks you through creating your first Barbacane-powered API gateway.

Prerequisites

  • Rust 1.75+ (for building from source)
  • An OpenAPI 3.x specification

Installation

From Source

git clone https://github.com/barbacane-dev/barbacane.git
cd barbacane
cargo build --release

# Binary is in target/release/barbacane

Using Cargo (planned for v1.0)

# Not yet published to crates.io
cargo install barbacane

Your First Gateway

Quick Start with barbacane init

The fastest way to start a new project:

# Create a new project with example spec and official plugins
barbacane init my-api --fetch-plugins

cd my-api

This creates:

  • barbacane.yaml — project manifest with plugins configured
  • api.yaml — OpenAPI spec with example endpoints
  • plugins/mock.wasm — mock dispatcher plugin
  • plugins/http-upstream.wasm — HTTP proxy plugin
  • .gitignore — ignores build artifacts

For a minimal skeleton without example endpoints:

barbacane init my-api --template minimal --fetch-plugins

Skip to Step 3: Validate the Spec if using barbacane init.

1. Create an OpenAPI Spec

Create a file called api.yaml:

openapi: "3.1.0"
info:
  title: My API
  version: "1.0.0"

servers:
  - url: https://api.example.com
    x-barbacane-upstream:
      name: backend
      timeout: 30s

paths:
  /health:
    get:
      operationId: healthCheck
      x-barbacane-dispatch:
        name: mock
        config:
          status: 200
          body: '{"status":"ok"}'
      responses:
        "200":
          description: Health check response

  /users:
    get:
      operationId: listUsers
      x-barbacane-dispatch:
        name: http-upstream
        config:
          url: "https://api.example.com"
          path: /api/users
      responses:
        "200":
          description: List of users

  /users/{id}:
    get:
      operationId: getUser
      x-barbacane-dispatch:
        name: http-upstream
        config:
          url: "https://api.example.com"
          path: /api/users/{id}
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: User details

The key additions are:

  • x-barbacane-dispatch on each operation: tells Barbacane how to handle the request

2. Create a Manifest

Create a barbacane.yaml manifest to declare which plugins to use:

plugins:
  mock:
    path: ./plugins/mock.wasm
  http-upstream:
    path: ./plugins/http-upstream.wasm

The manifest declares all WASM plugins used by your spec. Plugins can be sourced from:

  • Local path: path: ./plugins/name.wasm
  • URL (planned): url: https://plugins.example.com/name.wasm

3. Validate the Spec

barbacane validate --spec api.yaml

Output:

✓ api.yaml is valid

validated 1 spec(s): 1 valid, 0 invalid

4. Compile to Artifact

barbacane compile --spec api.yaml --manifest barbacane.yaml --output api.bca

Output:

compiled 1 spec(s) to api.bca (3 routes, 2 plugin(s) bundled)

The .bca (Barbacane Compiled Artifact) file contains:

  • Compiled routing table
  • Embedded source specs (for /__barbacane/openapi)
  • Bundled WASM plugins
  • Manifest with checksums

5. Run the Gateway

barbacane serve --artifact api.bca --listen 127.0.0.1:8080 --dev

Output:

barbacane: loaded 3 route(s) from artifact
barbacane: listening on 127.0.0.1:8080

6. Test It

# Health check (mock dispatcher)
curl http://127.0.0.1:8080/health
# {"status":"ok"}

# Gateway health
curl http://127.0.0.1:8080/__barbacane/health
# {"status":"healthy","artifact_version":1,"compiler_version":"0.1.0","routes_count":3}

# View the OpenAPI spec
curl http://127.0.0.1:8080/__barbacane/openapi
# Returns your original spec

# Try a non-existent route
curl http://127.0.0.1:8080/nonexistent
# {"error":"not found"}

# Try wrong method
curl -X POST http://127.0.0.1:8080/health
# {"error":"method not allowed"}

What’s Next?

  • Spec Configuration - Learn about all x-barbacane-* extensions
  • Dispatchers - Route to HTTP backends, mock responses, and more
  • Middlewares - Add authentication, rate limiting, CORS
  • Secrets - Manage API keys, tokens, and passwords securely
  • Observability - Metrics, logging, and distributed tracing
  • Control Plane - Manage specs and artifacts via REST API
  • Web UI - Visual interface for managing your gateway

Development Mode

The --dev flag enables:

  • Verbose error messages with dispatcher details
  • Detailed logging
  • No production-only restrictions

For production, omit the flag:

barbacane serve --artifact api.bca --listen 0.0.0.0:8080

Observability

Barbacane includes built-in observability features:

# Pretty logs for development
barbacane serve --artifact api.bca --log-format pretty --log-level debug

# JSON logs with OTLP tracing for production
barbacane serve --artifact api.bca \
  --log-format json \
  --otlp-endpoint http://otel-collector:4317

Prometheus metrics are available at /__barbacane/metrics:

curl http://127.0.0.1:8080/__barbacane/metrics

See the Observability Guide for full details.

Spec Configuration

Barbacane extends OpenAPI and AsyncAPI specs with custom x-barbacane-* extensions. These tell the gateway how to route requests, apply middleware, and connect to backends.

Extension Overview

ExtensionLocationPurpose
x-barbacane-upstreamServer objectDefine named backend connections
x-barbacane-dispatchOperationRoute request to a dispatcher
x-barbacane-middlewaresRoot or OperationApply middleware chain

Upstreams

Define backend connections on the servers array:

servers:
  - url: https://api.example.com
    description: Production API
    x-barbacane-upstream:
      name: main-backend
      timeout: 30s
      retries: 3

  - url: https://auth.example.com
    description: Auth Service
    x-barbacane-upstream:
      name: auth-service
      timeout: 10s

Upstream Properties

PropertyTypeRequiredDescription
namestringYesUnique identifier for this upstream
timeoutdurationNoRequest timeout (default: 30s)
retriesintegerNoNumber of retry attempts (default: 0)

Upstreams are a design pattern for named backends. The http-upstream dispatcher uses the url config directly:

x-barbacane-dispatch:
  name: http-upstream
  config:
    url: "https://api.example.com"  # Direct URL to backend
    path: /api/resource

Dispatchers

Every operation needs an x-barbacane-dispatch to tell Barbacane how to handle it:

paths:
  /users:
    get:
      x-barbacane-dispatch:
        name: http-upstream
        config:
          url: "https://api.example.com"
          path: /api/v2/users

Dispatch Properties

PropertyTypeRequiredDescription
namestringYesDispatcher plugin name
configobjectNoPlugin-specific configuration

Built-in Dispatchers

mock - Return Static Responses

For health checks, stubs, or testing:

x-barbacane-dispatch:
  name: mock
  config:
    status: 200
    body: '{"status":"ok","version":"1.0"}'
ConfigTypeDefaultDescription
statusinteger200HTTP status code
bodystring“”Response body

http-upstream - Proxy to HTTP Backend

Forward requests to an upstream:

x-barbacane-dispatch:
  name: http-upstream
  config:
    url: "https://api.example.com"
    path: /api/users/{id}
    timeout: 10.0
ConfigTypeDefaultDescription
urlstringRequiredBase URL of upstream (HTTPS required in production)
pathstringSame as operationBackend path (supports {param} substitution)
timeoutnumber30.0Request timeout in seconds

Path parameters from the OpenAPI spec are substituted automatically:

# OpenAPI path: /users/{userId}/orders/{orderId}
# Request: GET /users/123/orders/456
x-barbacane-dispatch:
  name: http-upstream
  config:
    url: "https://api.example.com"
    path: /api/v2/users/{userId}/orders/{orderId}
    # Becomes: GET https://api.example.com/api/v2/users/123/orders/456

Secret References in Config

Config values can reference secrets instead of hardcoding sensitive data:

x-barbacane-dispatch:
  name: http-upstream
  config:
    url: "https://api.example.com"
    headers:
      Authorization: "Bearer env://UPSTREAM_API_KEY"

Supported formats:

  • env://VAR_NAME - Read from environment variable
  • file:///path/to/secret - Read from file

Secrets are resolved at gateway startup. If any secret is missing, the gateway fails with exit code 13. See Secrets for details.

Middlewares

Middlewares process requests before dispatching and responses after.

Global Middlewares

Apply to all operations:

openapi: "3.1.0"
info:
  title: My API
  version: "1.0.0"

x-barbacane-middlewares:
  - name: rate-limit
    config:
      requests_per_minute: 100
  - name: cors
    config:
      allowed_origins: ["https://app.example.com"]

paths:
  # ... all operations get these middlewares

Operation Middlewares

Apply to a specific operation (runs after global middlewares):

paths:
  /admin/users:
    get:
      x-barbacane-middlewares:
        - name: auth-jwt
          config:
            required: true
            scopes: ["admin:read"]
      x-barbacane-dispatch:
        name: http-upstream
        config:
          url: "https://api.example.com"

Middleware Override

Operation middlewares can override global ones by name:

# Global: rate limit 100/min
x-barbacane-middlewares:
  - name: rate-limit
    config:
      requests_per_minute: 100

paths:
  /public/stats:
    get:
      # Override: higher limit for this endpoint
      x-barbacane-middlewares:
        - name: rate-limit
          config:
            requests_per_minute: 1000

Middleware Chain Order

  1. Global middlewares (in order defined)
  2. Operation middlewares (in order defined)
  3. Dispatch
  4. Response middlewares (reverse order)

Complete Example

openapi: "3.1.0"
info:
  title: E-Commerce API
  version: "2.0.0"

servers:
  - url: https://api.shop.example.com
    x-barbacane-upstream:
      name: shop-backend
      timeout: 30s
      retries: 2

  - url: https://payments.example.com
    x-barbacane-upstream:
      name: payments
      timeout: 60s

# Global middlewares
x-barbacane-middlewares:
  - name: request-id
    config:
      header: X-Request-ID
  - name: cors
    config:
      allowed_origins: ["https://shop.example.com"]
  - name: rate-limit
    config:
      requests_per_minute: 200

paths:
  /health:
    get:
      operationId: healthCheck
      x-barbacane-dispatch:
        name: mock
        config:
          status: 200
          body: '{"status":"healthy"}'
      responses:
        "200":
          description: OK

  /products:
    get:
      operationId: listProducts
      x-barbacane-middlewares:
        - name: cache
          config:
            ttl: 300
      x-barbacane-dispatch:
        name: http-upstream
        config:
          url: "https://api.shop.example.com"
          path: /api/products
      responses:
        "200":
          description: Product list

  /orders:
    post:
      operationId: createOrder
      x-barbacane-middlewares:
        - name: auth-jwt
          config:
            required: true
        - name: idempotency
          config:
            header: Idempotency-Key
      x-barbacane-dispatch:
        name: http-upstream
        config:
          url: "https://api.shop.example.com"
          path: /api/orders
      responses:
        "201":
          description: Order created

  /orders/{orderId}/pay:
    post:
      operationId: payOrder
      x-barbacane-middlewares:
        - name: auth-jwt
          config:
            required: true
      x-barbacane-dispatch:
        name: http-upstream
        config:
          url: "https://payments.example.com"  # Different backend!
          path: /process/{orderId}
          timeout: 45.0
      responses:
        "200":
          description: Payment processed

AsyncAPI Support

Barbacane supports AsyncAPI 3.x for event-driven APIs. AsyncAPI specs work similarly to OpenAPI, with channels and operations instead of paths and methods.

Sync-to-Async Bridge Pattern

AsyncAPI send operations are accessible via HTTP POST requests. This enables clients to publish messages to Kafka or NATS through the gateway:

  1. Client sends HTTP POST to the channel address
  2. Gateway validates the message against the schema
  3. Dispatcher publishes to Kafka/NATS
  4. Gateway returns 202 Accepted

Basic AsyncAPI Example

asyncapi: "3.0.0"
info:
  title: User Events API
  version: "1.0.0"

channels:
  userEvents:
    address: /events/users
    messages:
      UserCreated:
        contentType: application/json
        payload:
          type: object
          required:
            - userId
            - email
          properties:
            userId:
              type: string
              format: uuid
            email:
              type: string
              format: email

operations:
  publishUserCreated:
    action: send
    channel:
      $ref: '#/channels/userEvents'
    x-barbacane-dispatch:
      name: kafka
      config:
        topic: "user-events"

Channel Parameters

AsyncAPI channels can have parameters (like path params in OpenAPI):

channels:
  orderEvents:
    address: /events/orders/{orderId}
    parameters:
      orderId:
        schema:
          type: string
          format: uuid
    messages:
      OrderPlaced:
        payload:
          type: object

Message Validation

Message payloads are validated against the schema before dispatch. Invalid messages receive a 400 response with validation details.

HTTP Method Mapping

AsyncAPI ActionHTTP Method
sendPOST
receiveGET

Middlewares

AsyncAPI operations support the same middleware extensions as OpenAPI:

operations:
  publishEvent:
    action: send
    channel:
      $ref: '#/channels/events'
    x-barbacane-middlewares:
      - name: jwt-auth
        config:
          required: true
    x-barbacane-dispatch:
      name: kafka
      config:
        topic: "events"

API Lifecycle

Barbacane supports API lifecycle management through standard OpenAPI deprecation and the x-barbacane-sunset extension.

Marking Operations as Deprecated

Use the standard OpenAPI deprecated field:

paths:
  /v1/users:
    get:
      deprecated: true
      summary: List users (deprecated, use /v2/users)
      x-barbacane-dispatch:
        name: http-upstream
        config:
          url: "https://api.example.com"

When a client calls a deprecated endpoint, the response includes a Deprecation: true header per draft-ietf-httpapi-deprecation-header.

Setting a Sunset Date

Use x-barbacane-sunset to specify when an endpoint will be removed:

paths:
  /v1/users:
    get:
      deprecated: true
      x-barbacane-sunset: "Sat, 31 Dec 2025 23:59:59 GMT"
      x-barbacane-dispatch:
        name: http-upstream
        config:
          url: "https://api.example.com"

The sunset date must be in HTTP-date format (RFC 9110). When set, the response includes a Sunset header per RFC 8594.

Example Response Headers

HTTP/1.1 200 OK
Deprecation: true
Sunset: Sat, 31 Dec 2025 23:59:59 GMT
Content-Type: application/json

Best Practices

  1. Mark deprecated first: Set deprecated: true before setting a sunset date
  2. Give advance notice: Set the sunset date at least 6 months in advance
  3. Update API docs: Include migration instructions in the operation summary or description
  4. Monitor usage: Track calls to deprecated endpoints via metrics

Validation

The compiler validates your spec:

barbacane validate --spec api.yaml

Errors you might see:

Error CodeMeaning
E1010Routing conflict (same path+method in multiple specs)
E1020Missing x-barbacane-dispatch on operation
E1031Plaintext http:// upstream URL (use HTTPS or --allow-plaintext-upstream)

Next Steps

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:

/proxy/{path}:
  get:
    parameters:
      - name: path
        in: path
        required: 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-upstream flag to allow http:// URLs
  • 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.

x-barbacane-dispatch:
  name: kafka
  config:
    topic: "user-events"

Configuration

PropertyTypeRequiredDefaultDescription
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:
    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:
        topic: "order-events"
        key: "$request.header.X-Order-Id"
        include_metadata: true

With request header forwarding:

x-barbacane-dispatch:
  name: kafka
  config:
    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.

x-barbacane-dispatch:
  name: nats
  config:
    subject: "notifications.user"

Configuration

PropertyTypeRequiredDefaultDescription
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:
        subject: "notifications"
        headers_from_request:
          - "x-request-id"

Custom acknowledgment:

x-barbacane-dispatch:
  name: nats
  config:
    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

Custom WASM Dispatchers

Custom dispatchers can be implemented as WASM plugins using the Plugin SDK. The mock dispatcher is an example of a WASM-based dispatcher.

Planned Dispatchers

The following dispatchers are planned for future releases:

AsyncAPI Dispatchers (Kafka, NATS)

Barbacane supports parsing AsyncAPI 3.x specifications. Message broker dispatchers are planned:

# Planned Kafka dispatcher
x-barbacane-dispatch:
  name: kafka
  config:
    broker: "kafka.internal:9092"
    topic: "orders"
# Planned NATS dispatcher
x-barbacane-dispatch:
  name: nats
  config:
    url: "nats://nats.internal:4222"
    subject: "events.orders"

gRPC Dispatcher

x-barbacane-dispatch:
  name: grpc
  config:
    upstream: grpc-backend
    service: users.UserService
    method: GetUser

GraphQL Dispatcher

x-barbacane-dispatch:
  name: graphql
  config:
    upstream: graphql-backend
    operation: |
      query GetUser($id: ID!) {
        user(id: $id) {
          id
          name
          email
        }
      }

Dispatcher Development

See Plugin Development for creating custom dispatchers.

Dispatcher Interface

trait Dispatcher {
    /// Initialize with configuration.
    fn init(config: Value) -> Result<Self, Error>;

    /// Handle a request and produce a response.
    async fn dispatch(
        &self,
        ctx: &RequestContext,
    ) -> Result<Response, Error>;
}

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

The compiler rejects http:// URLs by default (E1031). For development with local services:

# Compile allows http:// - the check happens at runtime
barbacane compile --spec api.yaml --output api.bca

# Serve with plaintext upstream allowed (dev only!)
barbacane serve --artifact api.bca --dev --allow-plaintext-upstream

Middlewares

Middlewares process requests before they reach dispatchers and can modify responses on the way back. They’re used for cross-cutting concerns like authentication, rate limiting, and caching.

Overview

Middlewares are configured with x-barbacane-middlewares:

x-barbacane-middlewares:
  - name: <middleware-name>
    config:
      # middleware-specific config

Middleware Chain

Middlewares execute in order:

Request  →  [Global MW 1]  →  [Global MW 2]  →  [Operation MW]  →  Dispatcher
                                                                        │
Response ←  [Global MW 1]  ←  [Global MW 2]  ←  [Operation MW]  ←───────┘

Global vs Operation Middlewares

Global Middlewares

Apply to all operations:

openapi: "3.1.0"
info:
  title: My API
  version: "1.0.0"

# These apply to every operation
x-barbacane-middlewares:
  - name: request-id
    config:
      header: X-Request-ID
  - name: cors
    config:
      allowed_origins: ["https://app.example.com"]

paths:
  /users:
    get:
      # Inherits global middlewares
      x-barbacane-dispatch:
        name: http
        config:
          upstream: backend

Operation Middlewares

Apply to specific operations (run after global):

paths:
  /admin/users:
    get:
      x-barbacane-middlewares:
        - name: auth-jwt
          config:
            required: true
            scopes: ["admin:read"]
      x-barbacane-dispatch:
        name: http
        config:
          upstream: backend

Override Global Middleware

Operation middlewares can override global config by name:

# Global: 100 requests/minute
x-barbacane-middlewares:
  - name: rate-limit
    config:
      requests_per_minute: 100

paths:
  /public/feed:
    get:
      # Override: 1000 requests/minute for this endpoint
      x-barbacane-middlewares:
        - name: rate-limit
          config:
            requests_per_minute: 1000

Authentication Middlewares

jwt-auth

Validates JWT tokens with RS256/HS256 signatures.

x-barbacane-middlewares:
  - name: jwt-auth
    config:
      secret: "your-hs256-secret"  # For HS256
      # OR
      public_key: |                 # For RS256
        -----BEGIN PUBLIC KEY-----
        ...
        -----END PUBLIC KEY-----
      issuer: https://auth.example.com
      audience: my-api
      required_claims:
        - sub
        - email

Configuration

PropertyTypeDefaultDescription
secretstring-HS256 secret key
public_keystring-RS256 public key (PEM format)
issuerstring-Expected iss claim
audiencestring-Expected aud claim
required_claimsarray[]Claims that must be present
leewayinteger0Seconds of clock skew tolerance

Context Headers

Sets headers for downstream:

  • x-auth-sub - Subject (user ID)
  • x-auth-claims - Full JWT claims as JSON

apikey-auth

Validates API keys from header or query parameter.

x-barbacane-middlewares:
  - name: apikey-auth
    config:
      key_location: header        # or "query"
      header_name: X-API-Key      # when key_location is "header"
      query_param: api_key        # when key_location is "query"
      keys:
        sk_live_abc123:
          id: key-001
          name: Production Key
          scopes: ["read", "write"]
        sk_test_xyz789:
          id: key-002
          name: Test Key
          scopes: ["read"]

Configuration

PropertyTypeDefaultDescription
key_locationstringheaderWhere to find key (header or query)
header_namestringX-API-KeyHeader name (when key_location: header)
query_paramstringapi_keyQuery param name (when key_location: query)
keysobject{}Map of valid API keys to metadata

Context Headers

Sets headers for downstream:

  • x-auth-key-id - Key identifier
  • x-auth-key-name - Key human-readable name
  • x-auth-key-scopes - Comma-separated scopes

oauth2-auth

Validates Bearer tokens via RFC 7662 token introspection.

x-barbacane-middlewares:
  - name: oauth2-auth
    config:
      introspection_endpoint: https://auth.example.com/oauth2/introspect
      client_id: my-api-client
      client_secret: "env://OAUTH2_CLIENT_SECRET"  # resolved at startup
      required_scopes: "read write"                 # space-separated
      timeout: 5.0                                  # seconds

The client_secret uses a secret reference (env://) which is resolved at gateway startup. See Secrets for details.

Configuration

PropertyTypeDefaultDescription
introspection_endpointstringrequiredRFC 7662 introspection URL
client_idstringrequiredClient ID for introspection auth
client_secretstringrequiredClient secret for introspection auth
required_scopesstring-Space-separated required scopes
timeoutfloat5.0Introspection request timeout (seconds)

Context Headers

Sets headers for downstream:

  • x-auth-sub - Subject
  • x-auth-scope - Token scopes
  • x-auth-client-id - Client ID
  • x-auth-username - Username (if present)
  • x-auth-claims - Full introspection response as JSON

Error Responses

  • 401 Unauthorized - Missing token, invalid token, or inactive token
  • 403 Forbidden - Token lacks required scopes

Includes RFC 6750 WWW-Authenticate header with error details.


Rate Limiting

rate-limit

Limits request rate per client using a sliding window algorithm. Implements IETF draft-ietf-httpapi-ratelimit-headers.

x-barbacane-middlewares:
  - name: rate-limit
    config:
      quota: 100
      window: 60
      policy_name: default
      partition_key: client_ip

Configuration

PropertyTypeDefaultDescription
quotaintegerrequiredMaximum requests allowed in the window
windowintegerrequiredWindow duration in seconds
policy_namestringdefaultPolicy name for RateLimit-Policy header
partition_keystringclient_ipRate limit key source

Partition Key Sources

  • client_ip - Client IP from X-Forwarded-For or X-Real-IP
  • header:<name> - Header value (e.g., header:X-API-Key)
  • context:<key> - Context value (e.g., context:auth.sub)
  • Any static string - Same limit for all requests

Response Headers

On allowed requests:

  • X-RateLimit-Policy - Policy name and configuration
  • X-RateLimit-Limit - Maximum requests in window
  • X-RateLimit-Remaining - Remaining requests
  • X-RateLimit-Reset - Unix timestamp when window resets

On rate-limited requests (429):

  • RateLimit-Policy - IETF draft header
  • RateLimit - IETF draft combined header
  • Retry-After - Seconds until retry is allowed

CORS

cors

Handles Cross-Origin Resource Sharing per the Fetch specification. Processes preflight OPTIONS requests and adds CORS headers to responses.

x-barbacane-middlewares:
  - name: cors
    config:
      allowed_origins:
        - https://app.example.com
        - https://admin.example.com
      allowed_methods:
        - GET
        - POST
        - PUT
        - DELETE
      allowed_headers:
        - Authorization
        - Content-Type
      expose_headers:
        - X-Request-ID
      max_age: 86400
      allow_credentials: false

Configuration

PropertyTypeDefaultDescription
allowed_originsarray[]Allowed origins (["*"] for any, or specific origins)
allowed_methodsarray["GET", "POST"]Allowed HTTP methods
allowed_headersarray[]Allowed request headers (beyond simple headers)
expose_headersarray[]Headers exposed to browser JavaScript
max_ageinteger3600Preflight cache time (seconds)
allow_credentialsbooleanfalseAllow credentials (cookies, auth headers)

Origin Patterns

Origins can be:

  • Exact match: https://app.example.com
  • Wildcard subdomain: *.example.com (matches sub.example.com)
  • Wildcard: * (only when allow_credentials: false)

Error Responses

  • 403 Forbidden - Origin not in allowed list
  • 403 Forbidden - Method not allowed (preflight)
  • 403 Forbidden - Headers not allowed (preflight)

Preflight Responses

Returns 204 No Content with:

  • Access-Control-Allow-Origin
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Headers
  • Access-Control-Max-Age
  • Vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers

Caching

cache

Caches responses in memory with TTL support.

x-barbacane-middlewares:
  - name: cache
    config:
      ttl: 300
      vary:
        - Accept-Language
        - Accept-Encoding
      methods:
        - GET
        - HEAD
      cacheable_status:
        - 200
        - 301

Configuration

PropertyTypeDefaultDescription
ttlinteger300Cache duration (seconds)
varyarray[]Headers that vary cache key
methodsarray["GET", "HEAD"]HTTP methods to cache
cacheable_statusarray[200, 301]Status codes to cache

Cache Key

Cache key is computed from:

  • HTTP method
  • Request path
  • Vary header values (if configured)

Cache-Control Respect

The middleware respects Cache-Control response headers:

  • no-store - Response not cached
  • no-cache - Cache but revalidate
  • max-age=N - Use specified TTL instead of config

Planned Middlewares

The following middlewares are planned for future milestones:

request-id

Adds request ID for tracing.

x-barbacane-middlewares:
  - name: request-id
    config:
      header: X-Request-ID
      generate_if_missing: true

Configuration

PropertyTypeDefaultDescription
headerstringX-Request-IDHeader name
generate_if_missingbooleantrueGenerate UUID if not present

idempotency

Ensures idempotent processing.

x-barbacane-middlewares:
  - name: idempotency
    config:
      header: Idempotency-Key
      ttl: 86400

Configuration

PropertyTypeDefaultDescription
headerstringIdempotency-KeyHeader containing key
ttlinteger86400Key expiration (seconds)

Context Passing

Middlewares can set context for downstream components:

# Auth middleware sets context:auth.sub
x-barbacane-middlewares:
  - name: auth-jwt
    config:
      required: true

# Rate limit uses auth context
  - name: rate-limit
    config:
      key: context:auth.sub  # Rate limit per user

Middleware Development (Future)

See Plugin Development for creating custom middlewares.

Middleware Interface

trait Middleware {
    /// Initialize with configuration.
    fn init(config: Value) -> Result<Self, Error>;

    /// Process incoming request.
    async fn on_request(
        &self,
        ctx: &mut RequestContext,
    ) -> Result<MiddlewareAction, Error>;

    /// Process outgoing response.
    async fn on_response(
        &self,
        ctx: &mut ResponseContext,
    ) -> Result<(), Error>;
}

enum MiddlewareAction {
    Continue,           // Pass to next middleware
    Respond(Response),  // Short-circuit with response
}

Best Practices

Order Matters

Put middlewares in logical order:

x-barbacane-middlewares:
  - name: request-id     # 1. Add tracing ID first
  - name: cors           # 2. Handle CORS early
  - name: rate-limit     # 3. Rate limit before auth (cheaper)
  - name: auth-jwt       # 4. Authenticate

Fail Fast

Put restrictive middlewares early to reject bad requests quickly:

x-barbacane-middlewares:
  - name: rate-limit     # Reject over-limit immediately
  - name: auth-jwt       # Reject unauthorized before processing

Use Global for Common Concerns

# Global: apply to everything
x-barbacane-middlewares:
  - name: request-id
  - name: cors
  - name: rate-limit

paths:
  /public:
    get:
      # No additional middlewares needed

  /private:
    get:
      # Only add what's different
      x-barbacane-middlewares:
        - name: auth-jwt

Secrets Management

Barbacane supports secure secret management to keep sensitive values like API keys, tokens, and passwords out of your specs and artifacts.

Overview

Instead of hardcoding secrets in your OpenAPI specs, you reference them using special URI schemes. The gateway resolves these references at startup, before handling any requests.

Key principles:

  • No secrets in specs
  • No secrets in artifacts
  • No secrets in Git
  • Secrets resolved at gateway startup

Secret Reference Formats

Environment Variables

Use env:// to reference environment variables:

x-barbacane-middlewares:
  - name: oauth2-auth
    config:
      client_id: my-client
      client_secret: "env://OAUTH2_CLIENT_SECRET"

At startup, the gateway reads the OAUTH2_CLIENT_SECRET environment variable and substitutes its value.

File-based Secrets

Use file:// to read secrets from files:

x-barbacane-middlewares:
  - name: jwt-auth
    config:
      secret: "file:///etc/secrets/jwt-signing-key"

The gateway reads the file content, trims whitespace, and uses the result. This works well with:

  • Kubernetes Secrets (mounted as files)
  • Docker secrets
  • HashiCorp Vault Agent (file injection)

Examples

OAuth2 Authentication Middleware

x-barbacane-middlewares:
  - name: oauth2-auth
    config:
      introspection_endpoint: https://auth.example.com/introspect
      client_id: my-api-client
      client_secret: "env://OAUTH2_SECRET"
      timeout: 5.0

Run with:

export OAUTH2_SECRET="super-secret-value"
barbacane serve --artifact api.bca --listen 0.0.0.0:8080

HTTP Upstream with API Key

x-barbacane-dispatch:
  name: http-upstream
  config:
    url: https://api.provider.com/v1
    headers:
      Authorization: "Bearer env://UPSTREAM_API_KEY"

JWT Auth with File-based Key

x-barbacane-middlewares:
  - name: jwt-auth
    config:
      public_key: "file:///var/run/secrets/jwt-public-key.pem"
      issuer: https://auth.example.com
      audience: my-api

Multiple Secrets

You can use multiple secret references in the same config:

x-barbacane-middlewares:
  - name: oauth2-auth
    config:
      introspection_endpoint: "env://AUTH_SERVER_URL"
      client_id: "env://CLIENT_ID"
      client_secret: "env://CLIENT_SECRET"

Startup Behavior

Resolution Timing

Secrets are resolved once at gateway startup:

  1. Gateway loads the artifact
  2. Gateway scans all dispatcher and middleware configs for secret references
  3. Each reference is resolved (env var read, file read)
  4. Resolved values replace the references in memory
  5. HTTP server starts listening

If any secret cannot be resolved, the gateway refuses to start.

Exit Codes

Exit CodeMeaning
0Normal shutdown
1General error
11Plugin hash mismatch
13Secret resolution failure

When exit code 13 occurs, the error message indicates which secret failed:

error: failed to resolve secrets: environment variable not found: OAUTH2_SECRET

Missing Secrets

The gateway fails fast on missing secrets:

# Missing env var
$ barbacane serve --artifact api.bca --listen 0.0.0.0:8080
error: failed to resolve secrets: environment variable not found: API_KEY
$ echo $?
13

# Missing file
$ barbacane serve --artifact api.bca --listen 0.0.0.0:8080
error: failed to resolve secrets: file not found: /etc/secrets/api-key
$ echo $?
13

This fail-fast behavior ensures the gateway never starts in an insecure state.

Supported Schemes

SchemeExampleStatus
env://env://API_KEYSupported
file://file:///etc/secrets/keySupported
vault://vault://secret/data/api-keysPlanned
aws-sm://aws-sm://prod/api-keyPlanned
k8s://k8s://namespace/secret/keyPlanned

Best Practices

Development

Use environment variables with .env files (not committed to Git):

# .env (add to .gitignore)
OAUTH2_SECRET=dev-secret-value
API_KEY=dev-api-key
# Load and run
source .env
barbacane serve --artifact api.bca --listen 127.0.0.1:8080 --dev

Production

Use your platform’s secret management:

Docker:

docker run -e OAUTH2_SECRET="$OAUTH2_SECRET" barbacane serve ...

Kubernetes:

apiVersion: v1
kind: Pod
spec:
  containers:
    - name: gateway
      env:
        - name: OAUTH2_SECRET
          valueFrom:
            secretKeyRef:
              name: api-secrets
              key: oauth2-secret

Kubernetes with file-based secrets:

apiVersion: v1
kind: Pod
spec:
  containers:
    - name: gateway
      volumeMounts:
        - name: secrets
          mountPath: /etc/secrets
          readOnly: true
  volumes:
    - name: secrets
      secret:
        secretName: api-secrets

Then use file:///etc/secrets/key-name in your spec.

Secret Rotation

For secrets that need rotation:

  1. Update the secret value in your secret store
  2. Restart the gateway (rolling restart in Kubernetes)

The gateway does not hot-reload secrets. This simplifies the security model and avoids race conditions.

Troubleshooting

“environment variable not found”

error: failed to resolve secrets: environment variable not found: MY_SECRET

Solutions:

  • Verify the env var is set: echo $MY_SECRET
  • Ensure the env var is exported: export MY_SECRET=value
  • Check for typos in the reference: env://MY_SECRET

“file not found”

error: failed to resolve secrets: file not found: /path/to/secret

Solutions:

  • Verify the file exists: ls -la /path/to/secret
  • Check file permissions: the gateway process must be able to read it
  • Use absolute paths starting with /

“unsupported secret scheme”

error: failed to resolve secrets: unsupported secret scheme: vault

This means you’re using a scheme that isn’t implemented yet. Currently only env:// and file:// are supported.

Security Considerations

  1. Never commit secrets to Git - Use .gitignore for .env files
  2. Rotate secrets regularly - Plan for secret rotation via gateway restarts
  3. Use least privilege - Only grant the gateway access to secrets it needs
  4. Audit secret access - Use your secret store’s audit logging
  5. Encrypt at rest - Ensure your secret storage encrypts secrets

Observability

Barbacane provides comprehensive observability features out of the box: structured logging, Prometheus metrics, and distributed tracing with OpenTelemetry support.

Logging

Structured logs are written to stdout. Two formats are available:

JSON Format (Default)

Production-ready structured JSON logs:

barbacane serve --artifact api.bca --log-format json
{"timestamp":"2024-01-15T10:30:00Z","level":"INFO","target":"barbacane","message":"request completed","trace_id":"abc123","request_id":"def456","method":"GET","path":"/users","status":200,"duration_ms":12}

Pretty Format (Development)

Human-readable format for local development:

barbacane serve --artifact api.bca --log-format pretty --log-level debug
2024-01-15T10:30:00Z INFO  barbacane > request completed method=GET path=/users status=200 duration_ms=12

Log Levels

Control verbosity with --log-level:

LevelDescription
errorErrors only
warnWarnings and errors
infoNormal operation (default)
debugDetailed debugging
traceVery verbose tracing
barbacane serve --artifact api.bca --log-level debug

Or use the RUST_LOG environment variable:

RUST_LOG=debug barbacane serve --artifact api.bca

Metrics

Prometheus metrics are exposed at /__barbacane/metrics:

curl http://localhost:8080/__barbacane/metrics

Available Metrics

MetricTypeDescription
barbacane_requests_totalcounterTotal requests by method, path, status, api
barbacane_request_duration_secondshistogramRequest latency
barbacane_request_size_byteshistogramRequest body size
barbacane_response_size_byteshistogramResponse body size
barbacane_active_connectionsgaugeCurrent open connections
barbacane_connections_totalcounterTotal connections accepted
barbacane_validation_failures_totalcounterValidation errors by reason
barbacane_middleware_duration_secondshistogramMiddleware execution time
barbacane_dispatch_duration_secondshistogramDispatcher execution time
barbacane_wasm_execution_duration_secondshistogramWASM plugin execution time
barbacane_slo_violation_totalcounterSLO violations (when configured)

Prometheus Integration

Configure Prometheus to scrape metrics:

# prometheus.yml
scrape_configs:
  - job_name: 'barbacane'
    static_configs:
      - targets: ['barbacane:8080']
    metrics_path: '/__barbacane/metrics'
    scrape_interval: 15s

Example Queries

# Request rate
rate(barbacane_requests_total[5m])

# P99 latency
histogram_quantile(0.99, rate(barbacane_request_duration_seconds_bucket[5m]))

# Error rate
sum(rate(barbacane_requests_total{status=~"5.."}[5m])) / sum(rate(barbacane_requests_total[5m]))

# Active connections
barbacane_active_connections

Distributed Tracing

Barbacane supports W3C Trace Context for distributed tracing and can export spans via OpenTelemetry Protocol (OTLP).

Enable OTLP Export

barbacane serve --artifact api.bca \
  --otlp-endpoint http://otel-collector:4317

Or use the environment variable:

OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317 barbacane serve --artifact api.bca

Trace Context Propagation

Barbacane automatically:

  • Extracts traceparent and tracestate headers from incoming requests
  • Generates a new trace ID if none provided
  • Injects trace context into upstream requests

This enables end-to-end tracing across your entire service mesh.

Span Structure

Each request creates a span tree:

barbacane.request (root span)
├── barbacane.routing
├── barbacane.validation
├── barbacane.middleware.jwt-auth.request
├── barbacane.middleware.rate-limit.request
├── barbacane.dispatch.http-upstream
├── barbacane.middleware.rate-limit.response
└── barbacane.middleware.jwt-auth.response

Span Attributes

Spans include attributes like:

  • http.method, http.route, http.status_code
  • barbacane.api, barbacane.operation_id
  • barbacane.middleware, barbacane.dispatcher

Integration with Collectors

Works with any OpenTelemetry-compatible backend:

Jaeger:

barbacane serve --artifact api.bca --otlp-endpoint http://jaeger:4317

Grafana Tempo:

barbacane serve --artifact api.bca --otlp-endpoint http://tempo:4317

Datadog (with collector):

# otel-collector-config.yaml
exporters:
  datadog:
    api:
      key: ${DD_API_KEY}

Per-Operation Configuration

Use x-barbacane-observability to configure observability per operation:

# Global defaults
x-barbacane-observability:
  trace_sampling: 0.1    # Sample 10% of traces

paths:
  /health:
    get:
      x-barbacane-observability:
        trace_sampling: 0.0  # Don't trace health checks
      x-barbacane-dispatch:
        name: mock
        config:
          status: 200
          body: '{"status":"ok"}'

  /payments:
    post:
      x-barbacane-observability:
        trace_sampling: 1.0           # 100% for critical endpoints
        latency_slo_ms: 200           # SLO threshold
        detailed_validation_logs: true # Debug validation issues
      x-barbacane-dispatch:
        name: http-upstream
        config:
          url: "https://payments.internal"

Options

OptionTypeDefaultDescription
trace_samplingnumber1.0Sampling rate (0.0 = none, 1.0 = all)
latency_slo_msinteger-Latency threshold; emits barbacane_slo_violation_total when exceeded
detailed_validation_logsbooleanfalseInclude full validation error details in logs

Production Setup

A typical production observability stack:

barbacane serve --artifact api.bca \
  --log-format json \
  --log-level info \
  --otlp-endpoint http://otel-collector:4317

Combined with:

  • Prometheus scraping /__barbacane/metrics
  • OpenTelemetry Collector receiving OTLP traces
  • Grafana for dashboards and alerting
  • Log aggregation (Loki, Elasticsearch) ingesting stdout

Example Alert Rules

# prometheus-rules.yaml
groups:
  - name: barbacane
    rules:
      - alert: HighErrorRate
        expr: |
          sum(rate(barbacane_requests_total{status=~"5.."}[5m]))
          / sum(rate(barbacane_requests_total[5m])) > 0.01
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "High error rate detected"

      - alert: HighLatency
        expr: |
          histogram_quantile(0.99, rate(barbacane_request_duration_seconds_bucket[5m])) > 1
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "P99 latency exceeds 1 second"

      - alert: SLOViolations
        expr: rate(barbacane_slo_violation_total[5m]) > 0.01
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "SLO violations detected"

What’s Next?

Control Plane

The Barbacane Control Plane provides a REST API for managing API specifications, plugins, and compiled artifacts. It enables centralized management of your API gateway configuration with PostgreSQL-backed storage and async compilation.

Overview

The control plane is a separate component from the data plane (gateway). While the data plane handles request routing and processing, the control plane manages:

  • Specs - Upload, version, and manage OpenAPI/AsyncAPI specifications
  • Plugins - Registry for WASM plugins with version management
  • Artifacts - Compiled .bca files ready for deployment
  • Compilations - Async compilation jobs with status tracking

Quick Start

Start the Server

# Start PostgreSQL (Docker example)
docker run -d --name barbacane-db \
  -e POSTGRES_PASSWORD=barbacane \
  -e POSTGRES_DB=barbacane \
  -p 5432:5432 \
  postgres:16

# Run the control plane
barbacane-control serve \
  --database-url postgres://postgres:barbacane@localhost/barbacane \
  --listen 127.0.0.1:9090

The server automatically runs database migrations on startup.

Upload a Spec

curl -X POST http://localhost:9090/specs \
  -F "file=@api.yaml"

Response:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Petstore API",
  "revision": 1,
  "sha256": "a1b2c3..."
}

Start Compilation

curl -X POST http://localhost:9090/specs/550e8400-e29b-41d4-a716-446655440000/compile \
  -H "Content-Type: application/json" \
  -d '{"production": true}'

Response (202 Accepted):

{
  "id": "660e8400-e29b-41d4-a716-446655440001",
  "spec_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "pending",
  "production": true,
  "started_at": "2024-01-15T10:30:00Z"
}

Poll Compilation Status

curl http://localhost:9090/compilations/660e8400-e29b-41d4-a716-446655440001

When complete:

{
  "id": "660e8400-e29b-41d4-a716-446655440001",
  "spec_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "succeeded",
  "artifact_id": "770e8400-e29b-41d4-a716-446655440002",
  "started_at": "2024-01-15T10:30:00Z",
  "completed_at": "2024-01-15T10:30:05Z"
}

Download Artifact

curl -o api.bca http://localhost:9090/artifacts/770e8400-e29b-41d4-a716-446655440002/download

API Versioning

All JSON responses from the control plane include a versioned content type:

Content-Type: application/vnd.barbacane.v1+json

This allows clients to detect the API version and handle future breaking changes gracefully.

API Reference

Full OpenAPI specification is available at crates/barbacane-control/openapi.yaml.

Specs

MethodEndpointDescription
POST/specsUpload a new spec (multipart)
GET/specsList all specs
GET/specs/{id}Get spec metadata
DELETE/specs/{id}Delete spec and revisions
GET/specs/{id}/historyGet revision history
GET/specs/{id}/contentDownload spec content

Query Parameters

  • type - Filter by spec type (openapi or asyncapi)
  • name - Filter by name (case-insensitive partial match)
  • revision - Specific revision (for /content endpoint)

Plugins

MethodEndpointDescription
POST/pluginsRegister a plugin (multipart)
GET/pluginsList all plugins
GET/plugins/{name}List versions of a plugin
GET/plugins/{name}/{version}Get plugin metadata
DELETE/plugins/{name}/{version}Delete a plugin version
GET/plugins/{name}/{version}/downloadDownload WASM binary

Plugin Registration

curl -X POST http://localhost:9090/plugins \
  -F "name=my-middleware" \
  -F "version=1.0.0" \
  -F "type=middleware" \
  -F "description=My custom middleware" \
  -F "capabilities=[\"http\", \"log\"]" \
  -F "config_schema={\"type\": \"object\"}" \
  -F "file=@my-middleware.wasm"

Artifacts

MethodEndpointDescription
GET/artifactsList all artifacts
GET/artifacts/{id}Get artifact metadata
DELETE/artifacts/{id}Delete an artifact
GET/artifacts/{id}/downloadDownload .bca file

Compilations

MethodEndpointDescription
POST/specs/{id}/compileStart async compilation
GET/specs/{id}/compilationsList compilations for a spec
GET/compilations/{id}Get compilation status
DELETE/compilations/{id}Delete compilation record

Compilation Request

{
  "production": true,
  "additional_specs": ["uuid-of-another-spec"]
}

Compilation Status

StatusDescription
pendingJob queued, waiting to start
compilingCompilation in progress
succeededCompleted, artifact_id available
failedFailed, check errors array

Health

curl http://localhost:9090/health

Response:

{
  "status": "healthy",
  "version": "0.1.0"
}

Projects

Projects organize your APIs and configure which plugins to use. Each project can have its own set of specs, plugin configurations, and connected data planes.

Create a Project

curl -X POST http://localhost:9090/projects \
  -H "Content-Type: application/json" \
  -d '{"name": "My API Gateway", "description": "Production gateway"}'

Response:

{
  "id": "880e8400-e29b-41d4-a716-446655440003",
  "name": "My API Gateway",
  "description": "Production gateway",
  "created_at": "2024-01-15T10:00:00Z"
}

Configure Plugins for a Project

Add plugins from the registry to your project with custom configuration:

curl -X POST http://localhost:9090/projects/880e8400.../plugins \
  -H "Content-Type: application/json" \
  -d '{
    "plugin_name": "rate-limit",
    "plugin_version": "0.1.0",
    "enabled": true,
    "config": {
      "quota": 1000,
      "window": 60
    }
  }'

Each plugin’s configuration is validated against its JSON Schema (if one is defined).

Data Planes

Data planes are gateway instances that connect to the control plane to receive configuration updates.

Data Plane Connection

Data planes connect via WebSocket to receive artifacts and configuration:

# Start a data plane connected to the control plane
barbacane serve \
  --control-plane ws://localhost:9090/ws/data-plane \
  --project-id 880e8400-e29b-41d4-a716-446655440003 \
  --api-key dp_key_abc123

Create API Key for Data Plane

curl -X POST http://localhost:9090/projects/880e8400.../api-keys \
  -H "Content-Type: application/json" \
  -d '{"name": "Production Data Plane"}'

Response:

{
  "id": "990e8400-e29b-41d4-a716-446655440004",
  "name": "Production Data Plane",
  "key": "dp_key_abc123...",
  "created_at": "2024-01-15T10:30:00Z"
}

Note: The API key is only shown once at creation time. Store it securely.

List Connected Data Planes

curl http://localhost:9090/projects/880e8400.../data-planes

Response:

[
  {
    "id": "aa0e8400-e29b-41d4-a716-446655440005",
    "name": "production-1",
    "status": "connected",
    "current_artifact_id": "770e8400...",
    "connected_at": "2024-01-15T10:35:00Z"
  }
]

Deploy

Deploy compiled artifacts to connected data planes for zero-downtime updates.

Trigger Deployment

curl -X POST http://localhost:9090/projects/880e8400.../deploy \
  -H "Content-Type: application/json" \
  -d '{"artifact_id": "770e8400-e29b-41d4-a716-446655440002"}'

Response:

{
  "deployment_id": "bb0e8400-e29b-41d4-a716-446655440006",
  "artifact_id": "770e8400...",
  "target_data_planes": 3,
  "status": "in_progress"
}

The control plane notifies all connected data planes, which download the new artifact, verify its checksum, and perform a hot-reload.

Web UI

The control plane includes a web-based management interface at http://localhost:5173 (when running the UI development server).

Running the UI

# Using Makefile
make ui

# Or manually
cd ui && npm run dev

The UI provides:

  • Dashboard - Overview of specs, artifacts, and data planes
  • Specs Management - Upload, view, and delete API specifications
  • Plugin Registry - Browse registered plugins with their schemas
  • Projects - Create projects and configure plugins
  • Artifacts - View compiled artifacts and download them

Plugin Configuration

When adding plugins to a project, the UI:

  • Shows the plugin’s JSON Schema (if available)
  • Pre-fills a skeleton configuration based on required fields
  • Validates configuration in real-time before saving

Interactive API Documentation

The control plane includes interactive API documentation powered by Scalar:

http://localhost:9090/api/docs

This provides a browsable interface for exploring and testing all API endpoints directly from your browser.

Seeding the Plugin Registry

Use the seed-plugins command to populate the plugin registry with built-in plugins:

# Using Makefile (builds plugins first)
make seed-plugins

# Or manually
barbacane-control seed-plugins \
  --plugins-dir plugins \
  --database-url postgres://localhost/barbacane \
  --verbose

This scans the plugins/ directory for plugin manifests (plugin.toml) and registers them in the database along with their WASM binaries and JSON Schemas.

See CLI Reference for full options.

Error Handling

All errors follow RFC 9457 Problem Details format:

{
  "type": "urn:barbacane:error:not-found",
  "title": "Not Found",
  "status": 404,
  "detail": "Spec 550e8400-e29b-41d4-a716-446655440000 not found"
}

Error Types

URNStatusDescription
urn:barbacane:error:not-found404Resource not found
urn:barbacane:error:bad-request400Invalid request
urn:barbacane:error:conflict409Resource already exists or is in use
urn:barbacane:error:spec-invalid422Spec validation failed
urn:barbacane:error:internal-error500Server error

Database Schema

The control plane uses PostgreSQL with the following tables:

  • specs - Spec metadata (name, type, version, timestamps)
  • spec_revisions - Version history with content (BYTEA)
  • plugins - Plugin registry with WASM binaries and JSON Schemas
  • artifacts - Compiled .bca files with manifests
  • artifact_specs - Junction table linking artifacts to specs
  • compilations - Async job tracking
  • projects - Project definitions
  • project_plugin_configs - Plugin configurations per project
  • data_planes - Connected gateway instances
  • api_keys - Authentication keys for data planes

Migrations run automatically on startup with --migrate (enabled by default).

Configuration

Environment Variables

VariableDescription
DATABASE_URLPostgreSQL connection string
RUST_LOGLog level (trace, debug, info, warn, error)

CLI Options

barbacane-control serve [OPTIONS]

Options:
  --listen <ADDR>        Listen address [default: 127.0.0.1:9090]
  --database-url <URL>   PostgreSQL URL [env: DATABASE_URL]
  --migrate              Run migrations on startup [default: true]

Deployment

Docker Compose Example

version: '3.8'

services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_DB: barbacane
      POSTGRES_PASSWORD: barbacane
    volumes:
      - pgdata:/var/lib/postgresql/data

  control-plane:
    image: barbacane/control:latest
    command: serve --database-url postgres://postgres:barbacane@postgres/barbacane
    ports:
      - "9090:9090"
    depends_on:
      - postgres

volumes:
  pgdata:

Production Considerations

  1. Database backups - Regular PostgreSQL backups for spec and plugin data
  2. Connection pooling - Consider PgBouncer for high-traffic deployments
  3. Authentication - Add a reverse proxy with authentication (not built-in)
  4. TLS - Terminate TLS at the load balancer or reverse proxy

What’s Next?

Web UI

The Barbacane Control Plane includes a React-based web interface for managing your API gateway. This guide covers the features and workflows available in the UI.

Getting Started

Starting the UI

# Using Makefile (from project root)
make ui

# Or manually
cd ui && npm run dev

The UI runs at http://localhost:5173 and proxies API requests to the control plane at http://localhost:9090.

Prerequisites

Before using the UI, ensure:

  1. Control Plane is running - Start with make control-plane
  2. Database is ready - Start PostgreSQL with make db-up
  3. Plugins are seeded - Run make seed-plugins to populate the plugin registry

Features Overview

FeatureDescription
ProjectsCreate and manage API gateway projects
SpecsUpload and manage OpenAPI/AsyncAPI specifications
Plugin RegistryBrowse available plugins with schemas
Plugin ConfigurationConfigure plugins per project with validation
BuildsCompile specs into deployable artifacts
DeployDeploy artifacts to connected data planes
API KeysManage authentication for data planes

Projects

Projects organize your API gateway configuration. Each project contains:

  • Specs - API specifications to compile
  • Plugins - Configured middleware and dispatchers
  • Builds - Compilation history and artifacts
  • Data Planes - Connected gateway instances

Creating a Project

  1. Navigate to Projects from the sidebar
  2. Click New Project
  3. Enter a name and optional description
  4. Click Create

You can also create a project from a template by clicking From Template, which uses the /init endpoint to generate a starter API specification.

Project Navigation

Each project has a tabbed interface:

TabDescription
SpecsManage API specifications for this project
PluginsConfigure which plugins to use and their settings
BuildsView compilation history and trigger new builds
DeployDeploy artifacts and manage connected data planes
SettingsProject settings and danger zone

Specs Management

Uploading Specs

  1. Navigate to a project’s Specs tab
  2. Click Upload Spec
  3. Select an OpenAPI or AsyncAPI YAML/JSON file
  4. The spec is parsed, validated, and stored

Spec Features

  • Revision History - Each upload creates a new revision
  • Content Preview - View the raw spec content
  • Validation - Specs are validated on upload
  • Type Detection - Automatically detects OpenAPI vs AsyncAPI

Global Specs View

The Specs page in the sidebar shows all specs across all projects. Use this for:

  • Browsing all uploaded specifications
  • Searching specs by name
  • Viewing specs not yet assigned to projects

Plugin Registry

The Plugin Registry shows all available WASM plugins:

Plugin Types

TypeDescription
MiddlewareRequest/response processing (auth, rate limiting, CORS)
DispatcherBackend integration (HTTP upstream, Lambda, mock)

Plugin Information

Each plugin displays:

  • Name and Version - Unique identifier
  • Description - What the plugin does
  • Capabilities - Required host functions (e.g., http, log, kv)
  • Config Schema - JSON Schema for configuration (if defined)

Deleting Plugins

Plugins can be deleted from the registry if they’re not in use by any project. If a plugin is in use, you’ll see an error message asking you to remove it from all projects first.

Plugin Configuration

Configure plugins for each project from the Plugins tab.

Adding a Plugin

  1. Click Add Plugin
  2. Select a plugin from the registry dropdown
  3. The plugin’s JSON Schema (if available) generates a configuration form
  4. Fill in required and optional fields
  5. Click Add Plugin

Configuration Features

  • Schema-based forms - Auto-generated from JSON Schema
  • Real-time validation - Invalid configs are rejected before save
  • Enable/Disable - Toggle plugins without removing configuration
  • Reorder - Drag to change middleware execution order

Example: Configuring Rate Limiting

  1. Add the rate-limit plugin
  2. Configure:
    • quota: Maximum requests per window (e.g., 1000)
    • window: Time window in seconds (e.g., 60)
  3. Save the configuration

Example: Configuring CORS

  1. Add the cors plugin
  2. Configure:
    • allowed_origins: Array of allowed origins (e.g., ["https://example.com"])
    • allowed_methods: HTTP methods (e.g., ["GET", "POST", "OPTIONS"])
    • max_age: Preflight cache duration in seconds
  3. Save the configuration

Builds

Compile your specs and plugins into deployable .bca artifacts.

Triggering a Build

  1. Navigate to a project’s Builds tab
  2. Click Build
  3. Watch the compilation progress
  4. Download the artifact when complete

Build Status

StatusDescription
PendingBuild queued
CompilingCompilation in progress
SucceededArtifact ready for download/deploy
FailedCheck error details for issues

Build Errors

Common build errors:

  • Missing dispatcher - Operation has no x-barbacane-dispatch
  • Invalid config - Plugin configuration doesn’t match schema
  • Plugin not found - Referenced plugin not in registry
  • HTTP URL rejected - Use HTTPS for production builds

Deploy

Deploy artifacts to connected data planes for zero-downtime updates.

Connecting Data Planes

Data planes connect to the control plane via WebSocket:

barbacane serve \
  --control-plane ws://localhost:9090/ws/data-plane \
  --project-id <project-uuid> \
  --api-key <api-key>

Connected data planes appear in the Deploy tab with status indicators:

StatusDescription
OnlineConnected and receiving updates
DeployingCurrently loading new artifact
OfflineNot connected

Creating API Keys

  1. Navigate to a project’s Deploy tab
  2. Click Create Key in the API Keys section
  3. Enter a descriptive name
  4. Copy the key immediately - it’s only shown once

Deploying an Artifact

  1. Ensure at least one data plane is connected
  2. Click Deploy Latest
  3. The control plane notifies all connected data planes
  4. Data planes download, verify, and hot-reload the artifact

Project Templates

Create new projects from templates using the Init page:

Available Templates

TemplateDescription
BasicMinimal OpenAPI spec with health endpoint
AuthIncludes JWT authentication middleware
FullComplete example with auth, rate limiting, and CORS

Using Templates

  1. Click From Template on the Projects page
  2. Enter project name and select a template
  3. Preview the generated files
  4. Choose Setup in Control Plane to create project and upload spec
  5. Or choose Download to get the files locally

Settings

Project Settings

Access from a project’s Settings tab:

  • Rename project - Update name and description
  • Production mode - Enable/disable production compilation
  • Delete project - Permanently remove project and all data

Global Settings

Access from Settings in the sidebar:

  • Theme - Light/dark mode toggle
  • API URL - Control plane endpoint configuration

Artifacts Browser

The Artifacts page shows all compiled artifacts:

  • Download - Get .bca file for local deployment
  • View manifest - See included specs and plugins
  • Delete - Remove old artifacts

Activity Log

The Activity page shows recent operations:

  • Spec uploads
  • Compilation jobs
  • Deployments
  • Plugin configuration changes

Keyboard Shortcuts

ShortcutAction
Ctrl/Cmd + KQuick search
EscClose dialogs

Troubleshooting

UI won’t load

  1. Check that the control plane is running on port 9090
  2. Verify the UI dev server is running on port 5173
  3. Check browser console for errors

Plugin configuration not saving

  1. Verify the configuration matches the plugin’s JSON Schema
  2. Check for required fields that are empty
  3. Look for validation errors in the form

Data plane not appearing

  1. Verify the data plane is started with correct flags
  2. Check the API key is valid and not revoked
  3. Ensure the project ID matches
  4. Check WebSocket connection in data plane logs

Build fails with “plugin not found”

  1. Run make seed-plugins to populate the registry
  2. Verify the plugin name in your spec matches the registry
  3. Check the plugin version exists

Next Steps

CLI Reference

Barbacane provides two command-line tools:

  • barbacane - Data plane (gateway) for compiling specs and serving traffic
  • barbacane-control - Control plane for managing specs, plugins, and artifacts via REST API

barbacane

barbacane <COMMAND> [OPTIONS]

Commands

CommandDescription
initInitialize a new Barbacane project
compileCompile OpenAPI spec(s) into a .bca artifact
validateValidate spec(s) without compiling
serveRun the gateway server

barbacane init

Initialize a new Barbacane project with manifest, spec, and directory structure.

barbacane init [NAME] [OPTIONS]

Arguments

ArgumentRequiredDefaultDescription
NAMENo.Project name (creates a directory with this name, or initializes in current directory if .)

Options

OptionRequiredDefaultDescription
--template, -tNobasicTemplate to use: basic (full example) or minimal (bare bones)
--fetch-pluginsNofalseDownload official plugins (mock, http-upstream) from GitHub releases

Plugin Download

The --fetch-plugins flag downloads official Barbacane plugins from GitHub releases:

  • mock — Returns static responses (useful for testing and mocking)
  • http-upstream — Proxies requests to HTTP/HTTPS backends

Downloaded plugins are placed in the plugins/ directory and automatically configured in barbacane.yaml.

# Create project with plugins downloaded
barbacane init my-api --fetch-plugins

If download fails (e.g., network issues), the project is still created with an empty plugins directory.

Templates

basic (default):

  • Complete OpenAPI spec with /health and /users endpoints
  • Example x-barbacane-dispatch configurations
  • Ready to compile and run

minimal:

  • Bare-bones OpenAPI spec with just the required structure
  • Single /health endpoint placeholder
  • Start from scratch

Examples

# Create project in new directory with basic template
barbacane init my-api

# Create project with official plugins downloaded
barbacane init my-api --fetch-plugins

# Create project with minimal template
barbacane init my-api --template minimal

# Initialize in current directory
barbacane init .

# Short form
barbacane init my-api -t minimal

Generated Files

my-api/
├── barbacane.yaml    # Project manifest (plugin declarations)
├── api.yaml          # OpenAPI 3.1 specification
├── plugins/          # Directory for WASM plugins
└── .gitignore        # Ignores *.bca, target/, plugins/*.wasm

Exit Codes

CodeMeaning
0Success
1Directory exists and is not empty, or write error

barbacane compile

Compile one or more OpenAPI specs into a .bca artifact.

barbacane compile --spec <FILES>... --output <PATH>

Options

OptionRequiredDefaultDescription
--spec, -sYes-One or more spec files (YAML or JSON)
--output, -oYes-Output artifact path
--manifest, -mNo-Path to barbacane.yaml manifest (required for plugin bundling)
--allow-plaintextNofalseAllow http:// upstream URLs during compilation

Examples

# Compile single spec with manifest
barbacane compile --spec api.yaml --manifest barbacane.yaml --output api.bca

# Compile multiple specs
barbacane compile -s users.yaml -s orders.yaml -m barbacane.yaml -o combined.bca

# Short form
barbacane compile -s api.yaml -m barbacane.yaml -o api.bca

# Legacy compilation without manifest (no plugins bundled)
barbacane compile -s api.yaml -o api.bca

Exit Codes

CodeMeaning
0Success
1Compilation error (validation failed, routing conflict, undeclared plugin)
2Manifest or plugin resolution error

barbacane validate

Validate specs without full compilation. Checks for spec validity and extension errors.

barbacane validate --spec <FILES>... [OPTIONS]

Options

OptionRequiredDefaultDescription
--spec, -sYes-One or more spec files to validate
--formatNotextOutput format: text or json

Error Codes

CodeCategoryDescription
E1001Spec validityNot a valid OpenAPI 3.x or AsyncAPI 3.x
E1002Spec validityYAML/JSON parse error
E1003Spec validityUnresolved $ref reference
E1004Spec validitySchema validation error (missing info, etc.)
E1010ExtensionRouting conflict (same path+method in multiple specs)
E1011ExtensionMiddleware entry missing name
E1015ExtensionUnknown x-barbacane-* extension (warning)
E1020ExtensionOperation missing x-barbacane-dispatch (warning)
E1031ExtensionPlaintext HTTP URL not allowed (use --allow-plaintext to override)
E1040ManifestPlugin used in spec but not declared in barbacane.yaml

Examples

# Validate single spec
barbacane validate --spec api.yaml

# Validate multiple specs (checks for routing conflicts)
barbacane validate -s users.yaml -s orders.yaml

# JSON output (for CI/tooling)
barbacane validate --spec api.yaml --format json

Output Examples

Text format (default):

✓ api.yaml is valid

validated 1 spec(s): 1 valid, 0 invalid

Text format with errors:

✗ api.yaml has 1 error(s)
  E1004 [api.yaml]: E1004: schema validation error: missing 'info' object

validated 1 spec(s): 0 valid, 1 invalid

JSON format:

{
  "results": [
    {
      "file": "api.yaml",
      "valid": true,
      "errors": [],
      "warnings": []
    }
  ],
  "summary": {
    "total": 1,
    "valid": 1,
    "invalid": 0
  }
}

Exit Codes

CodeMeaning
0All specs valid
1One or more specs have errors

barbacane serve

Run the gateway server, loading routes from a compiled artifact.

barbacane serve --artifact <PATH> [OPTIONS]

Options

OptionRequiredDefaultDescription
--artifactYes-Path to the .bca artifact file
--listenNo0.0.0.0:8080Listen address (ip:port)
--devNofalseEnable development mode
--log-levelNoinfoLog level (trace, debug, info, warn, error)
--log-formatNojsonLog format (json or pretty)
--otlp-endpointNo-OpenTelemetry endpoint for trace export (e.g., http://localhost:4317)
--max-body-sizeNo1048576Maximum request body size in bytes (1MB)
--max-headersNo100Maximum number of request headers
--max-header-sizeNo8192Maximum size of a single header in bytes (8KB)
--max-uri-lengthNo8192Maximum URI length in characters (8KB)
--allow-plaintext-upstreamNofalseAllow http:// upstream URLs (dev only)
--tls-certNo-Path to TLS certificate file (PEM format)
--tls-keyNo-Path to TLS private key file (PEM format)
--tls-min-versionNo1.2Minimum TLS version (1.2 or 1.3)
--keepalive-timeoutNo60HTTP keep-alive idle timeout in seconds
--shutdown-timeoutNo30Graceful shutdown timeout in seconds

Examples

# Run with defaults (HTTP)
barbacane serve --artifact api.bca

# Custom port
barbacane serve --artifact api.bca --listen 127.0.0.1:3000

# Development mode (verbose errors)
barbacane serve --artifact api.bca --dev

# Production with TLS (HTTPS)
barbacane serve --artifact api.bca \
  --tls-cert /etc/barbacane/certs/server.crt \
  --tls-key /etc/barbacane/certs/server.key

# Production with custom limits
barbacane serve --artifact api.bca \
  --max-body-size 5242880 \
  --max-headers 50

# With observability (OTLP export)
barbacane serve --artifact api.bca \
  --log-format json \
  --otlp-endpoint http://otel-collector:4317

# Development mode with pretty logging
barbacane serve --artifact api.bca --dev --log-format pretty

# All options
barbacane serve --artifact api.bca \
  --listen 0.0.0.0:8080 \
  --tls-cert /etc/barbacane/certs/server.crt \
  --tls-key /etc/barbacane/certs/server.key \
  --log-level info \
  --log-format json \
  --otlp-endpoint http://otel-collector:4317 \
  --max-body-size 1048576 \
  --max-headers 100 \
  --max-header-size 8192 \
  --max-uri-length 8192

TLS Termination

The gateway supports HTTPS with TLS termination. To enable TLS, provide both --tls-cert and --tls-key:

barbacane serve --artifact api.bca \
  --tls-cert /path/to/server.crt \
  --tls-key /path/to/server.key

For maximum security with TLS 1.3 only (modern clients):

barbacane serve --artifact api.bca \
  --tls-cert /path/to/server.crt \
  --tls-key /path/to/server.key \
  --tls-min-version 1.3

TLS Configuration:

  • Minimum TLS version: 1.2 (default) or 1.3 (via --tls-min-version)
  • Modern cipher suites (via aws-lc-rs)
  • ALPN support for HTTP/2 and HTTP/1.1

Certificate Requirements:

  • Certificate and key must be in PEM format
  • Certificate file can contain the full chain (cert + intermediates)
  • Both --tls-cert and --tls-key must be provided together

HTTP/2 Support

The gateway supports both HTTP/1.1 and HTTP/2 with automatic protocol detection:

  • With TLS: HTTP/2 is negotiated via ALPN (Application-Layer Protocol Negotiation). Clients that support HTTP/2 will automatically use it when connecting over HTTPS.
  • Without TLS: HTTP/1.1 is used by default. HTTP/2 cleartext (h2c) is also supported via protocol detection.

HTTP/2 Features:

  • Multiplexed streams over a single connection
  • Header compression (HPACK)
  • Keep-alive with configurable ping intervals (20 seconds)
  • Full support for all gateway features (routing, validation, middlewares)

No configuration is needed—HTTP/2 works automatically when TLS is enabled. To verify HTTP/2 is working:

# Test HTTP/2 with curl
curl -v --http2 https://localhost:8080/__barbacane/health

# Expected output shows HTTP/2:
# * Using HTTP/2
# < HTTP/2 200

Development Mode

The --dev flag enables:

  • Verbose error messages with field names, locations, and detailed reasons
  • Extended RFC 9457 problem details with errors array
  • Useful for debugging but do not use in production - it may expose internal information

Request Limits

The gateway enforces request limits to protect against abuse:

LimitDefaultDescription
Body size1 MBRequests with larger bodies are rejected with 400
Header count100Requests with more headers are rejected with 400
Header size8 KBIndividual headers larger than this are rejected
URI length8 KBURIs longer than this are rejected with 400

Requests exceeding limits receive an RFC 9457 problem details response:

{
  "type": "urn:barbacane:error:validation-failed",
  "title": "Request validation failed",
  "status": 400,
  "detail": "request body too large: 2000000 bytes exceeds limit of 1048576 bytes"
}

Graceful Shutdown

The gateway handles shutdown signals (SIGTERM, SIGINT) gracefully:

  1. Stop accepting new connections immediately
  2. Drain in-flight requests for up to --shutdown-timeout seconds (default: 30)
  3. Force close any remaining connections after timeout
  4. Exit with code 0 on successful shutdown
# Send SIGTERM to gracefully shutdown
kill -TERM $(pgrep barbacane)

# Output during graceful shutdown
barbacane: received shutdown signal, draining connections...
barbacane: waiting for 3 active connection(s) to complete...
barbacane: all connections drained, shutting down

Response Headers

Every response includes these standard headers:

HeaderDescription
Serverbarbacane/<version> (e.g., barbacane/0.1.0)
X-Request-IdRequest ID - propagates incoming header or generates UUID v4
X-Trace-IdTrace ID - extracted from traceparent header or generated
X-Content-Type-Optionsnosniff - prevents MIME sniffing attacks
X-Frame-OptionsDENY - prevents clickjacking via iframes

Example response headers:

HTTP/1.1 200 OK
Server: barbacane/0.1.0
X-Request-Id: 550e8400-e29b-41d4-a716-446655440000
X-Trace-Id: 4bf92f3577b34da6a3ce929d0e0e4736
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Content-Type: application/json

API Lifecycle Headers

For deprecated operations, additional headers are included:

HeaderDescription
Deprecationtrue - indicates the endpoint is deprecated (per draft-ietf-httpapi-deprecation-header)
SunsetHTTP-date when the endpoint will be removed (per RFC 8594)

Example for deprecated endpoint:

HTTP/1.1 200 OK
Server: barbacane/0.1.0
Deprecation: true
Sunset: Sat, 31 Dec 2025 23:59:59 GMT
Content-Type: application/json

See API Lifecycle for configuration details.

Exit Codes

CodeMeaning
0Clean shutdown
1Startup error (artifact not found, bind failed)
11Plugin hash mismatch (artifact tampering detected)
13Secret resolution failure (missing env var or file)

Exit code 13 occurs when a secret reference in your spec cannot be resolved:

$ export OAUTH2_SECRET=""  # unset the variable
$ unset OAUTH2_SECRET
$ barbacane serve --artifact api.bca
error: failed to resolve secrets: environment variable not found: OAUTH2_SECRET
$ echo $?
13

Environment Variables

VariableDescription
RUST_LOGOverride log level (e.g., RUST_LOG=debug)
OTEL_EXPORTER_OTLP_ENDPOINTAlternative to --otlp-endpoint flag

Observability

Barbacane provides built-in observability features:

Logging

Structured logs are written to stdout in either JSON (default) or pretty format:

# JSON format (production)
barbacane serve --artifact api.bca --log-format json

# Pretty format (development)
barbacane serve --artifact api.bca --log-format pretty --log-level debug

Metrics

Prometheus metrics are exposed at /__barbacane/metrics:

curl http://localhost:8080/__barbacane/metrics

Key metrics include:

  • barbacane_requests_total - Request counter by method, path, status
  • barbacane_request_duration_seconds - Request latency histogram
  • barbacane_active_connections - Current connection count
  • barbacane_validation_failures_total - Validation error counter

Distributed Tracing

Enable OTLP export to send traces to OpenTelemetry Collector:

barbacane serve --artifact api.bca \
  --otlp-endpoint http://otel-collector:4317

Barbacane supports W3C Trace Context propagation (traceparent/tracestate headers) for distributed tracing across services.


Secret References

Dispatcher and middleware configs can reference secrets using special URI schemes. These are resolved at startup:

SchemeExampleDescription
env://env://API_KEYRead from environment variable
file://file:///etc/secrets/keyRead from file

Example config with secrets:

x-barbacane-middlewares:
  - name: oauth2-auth
    config:
      client_secret: "env://OAUTH2_SECRET"

Run with:

export OAUTH2_SECRET="my-secret-value"
barbacane serve --artifact api.bca

See Secrets Guide for full documentation.


Common Workflows

Development Cycle

# Edit spec and manifest
vim api.yaml barbacane.yaml

# Validate (quick check)
barbacane validate --spec api.yaml

# Compile with manifest
barbacane compile --spec api.yaml --manifest barbacane.yaml --output api.bca

# Run in dev mode
barbacane serve --artifact api.bca --dev

CI/CD Pipeline

#!/bin/bash
set -e

# Validate all specs
barbacane validate --spec specs/*.yaml --format json > validation.json

# Compile artifact with manifest
barbacane compile \
  --spec specs/users.yaml \
  --spec specs/orders.yaml \
  --manifest barbacane.yaml \
  --output dist/gateway.bca

echo "Artifact built: dist/gateway.bca"

Multi-Spec Gateway

# Compile multiple specs into one artifact
barbacane compile \
  --spec users-api.yaml \
  --spec orders-api.yaml \
  --spec payments-api.yaml \
  --output combined.bca

# Routes from all specs are merged
# Conflicts (same path+method) cause E1010 error

Testing Locally

# Start gateway
barbacane serve --artifact api.bca --dev --listen 127.0.0.1:8080 &

# Test endpoints
curl http://localhost:8080/health
curl http://localhost:8080/__barbacane/health
curl http://localhost:8080/__barbacane/openapi

# Stop gateway
kill %1

barbacane-control

The control plane CLI for managing specs, plugins, and artifacts via REST API.

barbacane-control <COMMAND> [OPTIONS]

Commands

CommandDescription
compileCompile spec(s) into a .bca artifact (local)
validateValidate spec(s) without compiling
serveStart the control plane REST API server
seed-pluginsSeed the plugin registry with built-in plugins

barbacane-control seed-plugins

Seed the plugin registry with built-in plugins from the local plugins/ directory. This command scans plugin directories, reads their manifests (plugin.toml), and registers them in the database.

barbacane-control seed-plugins [OPTIONS]

Options

OptionRequiredDefaultDescription
--plugins-dirNopluginsPath to the plugins directory
--database-urlYes-PostgreSQL connection URL
--skip-existingNotrueSkip plugins that already exist in the registry
--verboseNofalseShow detailed output

The --database-url can also be set via the DATABASE_URL environment variable.

Plugin Directory Structure

Each plugin directory should contain:

plugins/
├── http-upstream/
│   ├── plugin.toml          # Plugin manifest (required)
│   ├── config-schema.json   # JSON Schema for config (optional)
│   ├── http-upstream.wasm   # Compiled WASM binary (required)
│   └── src/
│       └── lib.rs
├── rate-limit/
│   ├── plugin.toml
│   ├── config-schema.json
│   └── rate-limit.wasm
└── ...

Plugin Manifest (plugin.toml)

[plugin]
name = "http-upstream"
version = "0.1.0"
type = "dispatcher"                    # or "middleware"
description = "HTTP upstream proxy"    # optional
wasm = "http-upstream.wasm"           # optional, defaults to {name}.wasm

[capabilities]
host_functions = ["host_http_call", "host_log"]

Examples

# Build plugins and seed them into the registry
make seed-plugins

# Or manually:
cargo run -p barbacane-control -- seed-plugins \
  --plugins-dir plugins \
  --database-url postgres://localhost/barbacane \
  --verbose

# Output:
#   Registered http-upstream v0.1.0 (dispatcher)
#   Registered rate-limit v0.1.0 (middleware)
#   Registered cors v0.1.0 (middleware)
#   ...
# Seeded 9 plugin(s) into the registry.

Exit Codes

CodeMeaning
0Success
1Error (database connection, invalid manifest, etc.)

barbacane-control serve

Start the control plane HTTP server with PostgreSQL backend.

barbacane-control serve [OPTIONS]

Options

OptionRequiredDefaultDescription
--listenNo127.0.0.1:9090Listen address (ip:port)
--database-urlYes-PostgreSQL connection URL
--migrateNotrueRun database migrations on startup

The --database-url can also be set via the DATABASE_URL environment variable.

Examples

# Start with explicit database URL
barbacane-control serve \
  --database-url postgres://postgres:password@localhost/barbacane \
  --listen 0.0.0.0:9090

# Using environment variable
export DATABASE_URL=postgres://postgres:password@localhost/barbacane
barbacane-control serve

# Skip migrations (not recommended)
barbacane-control serve \
  --database-url postgres://localhost/barbacane \
  --migrate=false

Database Setup

The control plane requires PostgreSQL 14+. Tables are created automatically via migrations:

# Create database
createdb barbacane

# Start server (migrations run automatically)
barbacane-control serve --database-url postgres://localhost/barbacane

API Endpoints

The server exposes a REST API for managing specs, plugins, artifacts, and projects:

EndpointDescription
System
GET /healthHealth check
GET /api/docsInteractive API documentation (Scalar)
Specs
POST /specsUpload spec (multipart)
GET /specsList specs
GET /specs/{id}Get spec metadata
DELETE /specs/{id}Delete spec
GET /specs/{id}/historyRevision history
GET /specs/{id}/contentDownload spec content
POST /specs/{id}/compileStart async compilation
GET /compilations/{id}Poll compilation status
Plugins
POST /pluginsRegister plugin (multipart)
GET /pluginsList plugins
GET /plugins/{name}/{version}Get plugin metadata
DELETE /plugins/{name}/{version}Delete plugin
GET /plugins/{name}/{version}/downloadDownload WASM binary
Artifacts
GET /artifactsList artifacts
GET /artifacts/{id}Get artifact metadata
GET /artifacts/{id}/downloadDownload .bca file
Projects
POST /projectsCreate a new project
GET /projectsList all projects
GET /projects/{id}Get project details
PUT /projects/{id}Update project
DELETE /projects/{id}Delete project
GET /projects/{id}/pluginsList plugins configured for project
POST /projects/{id}/pluginsAdd plugin to project
PUT /projects/{id}/plugins/{name}Update plugin config
DELETE /projects/{id}/plugins/{name}Remove plugin from project
POST /projects/{id}/deployDeploy artifact to connected data planes
Data Planes
GET /projects/{id}/data-planesList connected data planes
GET /data-planes/{id}Get data plane status
API Keys
POST /projects/{id}/api-keysCreate API key for data plane auth
GET /projects/{id}/api-keysList API keys
DELETE /projects/{id}/api-keys/{id}Revoke API key

Interactive API Documentation

The control plane includes interactive API documentation powered by Scalar. Access it at:

http://localhost:9090/api/docs

This provides a browsable interface for exploring and testing all API endpoints.

Full API Specification

Full OpenAPI specification: Control Plane OpenAPI

See the Control Plane Guide for detailed usage examples.

Spec Extensions Reference

Complete reference for all x-barbacane-* OpenAPI extensions.

Summary

ExtensionLocationRequiredPurpose
x-barbacane-upstreamServerNoDefine backend connection
x-barbacane-dispatchOperationYesRoute to dispatcher
x-barbacane-middlewaresRoot / OperationNoApply middleware chain
x-barbacane-observabilityRoot / OperationNoConfigure observability settings

x-barbacane-upstream

Defines a named upstream backend connection.

Location

Server object in servers array.

Schema

x-barbacane-upstream:
  name: string          # Required. Unique upstream identifier
  timeout: duration     # Optional. Request timeout (default: 30s)
  retries: integer      # Optional. Retry attempts (default: 0)

Properties

PropertyTypeRequiredDefaultDescription
namestringYes-Unique identifier for this upstream
timeoutdurationNo30sRequest timeout
retriesintegerNo0Number of retry attempts

Duration Format

Durations support:

  • 5s - seconds
  • 100ms - milliseconds
  • 1m - minutes
  • 1h - hours

Example

servers:
  - url: https://api.example.com
    description: Production API
    x-barbacane-upstream:
      name: main-api
      timeout: 30s
      retries: 2

  - url: https://payments.example.com
    description: Payment Service
    x-barbacane-upstream:
      name: payments
      timeout: 60s
      retries: 3

x-barbacane-dispatch

Specifies how to handle a request for an operation.

Location

Operation object (get, post, put, delete, patch, options, head).

Schema

x-barbacane-dispatch:
  name: string    # Required. Dispatcher name
  config: object  # Optional. Dispatcher-specific configuration

Properties

PropertyTypeRequiredDescription
namestringYesName of the dispatcher (e.g., mock, http)
configobjectNoConfiguration passed to the dispatcher

Dispatcher: mock

Returns static responses.

x-barbacane-dispatch:
  name: mock
  config:
    status: integer   # HTTP status (default: 200)
    body: string      # Response body (default: "")

Dispatcher: http-upstream

Reverse proxy to HTTP/HTTPS backend.

x-barbacane-dispatch:
  name: http-upstream
  config:
    url: string       # Required. Base URL (HTTPS required in production)
    path: string      # Optional. Upstream path template (default: operation path)
    timeout: number   # Optional. Timeout in seconds (default: 30.0)

Examples

Mock response:

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

HTTP upstream proxy:

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

Wildcard proxy:

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

Secret References

Config values can reference secrets instead of hardcoding sensitive data. Secrets are resolved at gateway startup.

SchemeExampleDescription
env://env://API_KEYRead from environment variable
file://file:///etc/secrets/keyRead from file (content trimmed)

Example with secret reference:

x-barbacane-dispatch:
  name: http-upstream
  config:
    url: "https://api.example.com"
    headers:
      Authorization: "Bearer env://UPSTREAM_API_KEY"

If a secret cannot be resolved, the gateway fails to start with exit code 13.

See Secrets Guide for full documentation.


x-barbacane-middlewares

Defines a middleware chain.

Location

  • Root level: Applies to all operations (global)
  • Operation level: Applies to specific operation (after global)

Schema

x-barbacane-middlewares:
  - name: string    # Required. Middleware name
    config: object  # Optional. Middleware-specific configuration

Properties

PropertyTypeRequiredDescription
namestringYesName of the middleware plugin
configobjectNoConfiguration passed to the middleware

Middleware Override

When an operation defines a middleware with the same name as a global one, the operation config overrides the global config for that middleware.

Examples

Global middlewares:

openapi: "3.1.0"
info:
  title: My API
  version: "1.0.0"

x-barbacane-middlewares:
  - name: request-id
    config:
      header: X-Request-ID
  - name: rate-limit
    config:
      requests_per_minute: 100
  - name: cors
    config:
      allowed_origins: ["https://app.example.com"]

paths:
  /users:
    get:
      # Inherits all global middlewares
      x-barbacane-dispatch:
        name: http-upstream
        config:
          url: "https://api.example.com"

Operation-specific middlewares:

paths:
  /admin:
    get:
      x-barbacane-middlewares:
        - name: auth-jwt
          config:
            required: true
            scopes: ["admin:read"]
      x-barbacane-dispatch:
        name: http-upstream
        config:
          url: "https://api.example.com"

Override global config:

# Global: 100 req/min
x-barbacane-middlewares:
  - name: rate-limit
    config:
      requests_per_minute: 100

paths:
  /high-traffic:
    get:
      # Override: 1000 req/min for this endpoint
      x-barbacane-middlewares:
        - name: rate-limit
          config:
            requests_per_minute: 1000
      x-barbacane-dispatch:
        name: http-upstream
        config:
          url: "https://api.example.com"

Common Middleware Configurations

auth-jwt

- name: auth-jwt
  config:
    required: true
    header: Authorization
    scheme: Bearer
    issuer: https://auth.example.com
    audience: my-api
    scopes: ["read"]

rate-limit

- name: rate-limit
  config:
    quota: 100             # Maximum requests allowed in window
    window: 60             # Window duration in seconds
    policy_name: "default" # Optional: name for RateLimit-Policy header
    partition_key: "client_ip" # Options: "client_ip", "header:<name>", "context:<key>"

Returns IETF draft-ietf-httpapi-ratelimit-headers compliant headers:

  • RateLimit-Policy: Policy description (e.g., default;q=100;w=60)
  • RateLimit: Current limit status
  • Retry-After: Seconds until quota reset (only on 429)

cors

- name: cors
  config:
    allowed_origins: ["https://app.example.com"]
    allowed_methods: ["GET", "POST", "PUT", "DELETE"]
    allowed_headers: ["Authorization", "Content-Type"]
    max_age: 86400

cache

- name: cache
  config:
    ttl: 300                  # TTL in seconds (default: 300)
    vary: ["Accept-Language"] # Headers that differentiate cache entries
    methods: ["GET", "HEAD"]  # Cacheable methods (default: GET, HEAD)
    cacheable_status: [200, 301, 404] # Cacheable status codes

Adds X-Cache header to responses:

  • HIT: Response served from cache
  • MISS: Response not in cache (will be cached if cacheable)

request-id

- name: request-id
  config:
    header: X-Request-ID
    generate_if_missing: true

idempotency

- name: idempotency
  config:
    header: Idempotency-Key
    ttl: 86400

x-barbacane-observability

Configures observability settings for tracing, logging, and SLO monitoring.

Location

  • Root level: Applies to all operations (global defaults)
  • Operation level: Overrides global settings for specific operation

Schema

x-barbacane-observability:
  trace_sampling: number         # Optional. Sampling rate 0.0-1.0 (default: 1.0)
  detailed_validation_logs: bool # Optional. Log validation details (default: false)
  latency_slo_ms: integer        # Optional. Latency SLO threshold in milliseconds

Properties

PropertyTypeRequiredDefaultDescription
trace_samplingnumberNo1.0Trace sampling rate (0.0 = none, 1.0 = all)
detailed_validation_logsbooleanNofalseInclude validation error details in logs
latency_slo_msintegerNo-Emit barbacane_slo_violation_total metric when exceeded

Examples

Global observability settings:

openapi: "3.1.0"
info:
  title: My API
  version: "1.0.0"

x-barbacane-observability:
  trace_sampling: 0.1          # Sample 10% of traces
  latency_slo_ms: 500          # Alert if requests exceed 500ms

paths:
  /users:
    get:
      x-barbacane-dispatch:
        name: http-upstream
        config:
          url: "https://api.example.com"

Operation-specific override:

x-barbacane-observability:
  trace_sampling: 0.1   # Global: 10% sampling

paths:
  /critical-endpoint:
    get:
      x-barbacane-observability:
        trace_sampling: 1.0     # Override: 100% for critical endpoint
        latency_slo_ms: 100     # Stricter SLO
      x-barbacane-dispatch:
        name: http-upstream
        config:
          url: "https://api.example.com"

Debugging with detailed validation logs:

paths:
  /validate:
    post:
      x-barbacane-observability:
        detailed_validation_logs: true  # Log full validation error details
      x-barbacane-dispatch:
        name: http-upstream
        config:
          url: "https://api.example.com"

SLO Monitoring

When latency_slo_ms is configured, the gateway emits a barbacane_slo_violation_total metric each time a request exceeds the threshold:

barbacane_slo_violation_total{method="GET",path="/users",api="users-api",slo_ms="500"} 12

This integrates with Prometheus alerting:

# Prometheus alert rule
groups:
  - name: barbacane
    rules:
      - alert: HighLatencySLOViolations
        expr: rate(barbacane_slo_violation_total[5m]) > 0.01
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High SLO violation rate"

Validation Errors

CodeMessageCause
E1010Routing conflictSame path+method in multiple specs
E1020Missing dispatchOperation has no x-barbacane-dispatch

Complete Example

openapi: "3.1.0"
info:
  title: Complete Example API
  version: "1.0.0"

servers:
  - url: https://api.example.com
    x-barbacane-upstream:
      name: main-backend
      timeout: 30s
      retries: 2

x-barbacane-middlewares:
  - name: request-id
    config:
      header: X-Request-ID
  - name: cors
    config:
      allowed_origins: ["*"]
  - name: rate-limit
    config:
      quota: 100
      window: 60
      partition_key: "client_ip"

paths:
  /health:
    get:
      operationId: healthCheck
      x-barbacane-dispatch:
        name: mock
        config:
          status: 200
          body: '{"status":"healthy"}'
      responses:
        "200":
          description: OK

  /users:
    get:
      operationId: listUsers
      x-barbacane-middlewares:
        - name: cache
          config:
            ttl: 60
      x-barbacane-dispatch:
        name: http-upstream
        config:
          url: "https://api.example.com"
          path: /api/users
      responses:
        "200":
          description: User list

  /users/{id}:
    get:
      operationId: getUser
      x-barbacane-dispatch:
        name: http-upstream
        config:
          url: "https://api.example.com"
          path: /api/users/{id}
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: User details

  /admin/users:
    get:
      operationId: adminListUsers
      x-barbacane-middlewares:
        - name: auth-jwt
          config:
            required: true
            scopes: ["admin:read"]
        - name: rate-limit
          config:
            quota: 50
            window: 60
      x-barbacane-dispatch:
        name: http-upstream
        config:
          url: "https://api.example.com"
          path: /api/admin/users
      responses:
        "200":
          description: Admin user list

Artifact Format

Barbacane compiles OpenAPI specs into .bca (Barbacane Compiled Artifact) files. This document describes the artifact format.

Overview

A .bca file is a gzip-compressed tar archive containing:

artifact.bca (tar.gz)
├── manifest.json       # Artifact metadata
├── routes.json         # Compiled routing table
├── specs/              # Embedded source specifications
│   ├── api.yaml
│   └── ...
└── plugins/            # Bundled WASM plugins (optional)
    ├── rate-limit.wasm
    └── ...

File Structure

manifest.json

Metadata about the artifact.

{
  "barbacane_artifact_version": 1,
  "compiled_at": "2025-01-29T10:30:00Z",
  "compiler_version": "0.1.0",
  "source_specs": [
    {
      "file": "api.yaml",
      "sha256": "abc123...",
      "type": "openapi",
      "version": "3.1.0"
    }
  ],
  "bundled_plugins": [
    {
      "name": "rate-limit",
      "version": "1.0.0",
      "plugin_type": "middleware",
      "wasm_path": "plugins/rate-limit.wasm",
      "sha256": "789abc..."
    }
  ],
  "routes_count": 12,
  "checksums": {
    "routes.json": "sha256:def456..."
  }
}

Fields

FieldTypeDescription
barbacane_artifact_versionintegerFormat version (currently 1)
compiled_atstringISO 8601 timestamp of compilation
compiler_versionstringVersion of barbacane compiler
source_specsarrayList of source specifications
bundled_pluginsarrayList of bundled WASM plugins (optional)
routes_countintegerNumber of compiled routes
checksumsobjectSHA-256 checksums for integrity

source_specs entry

FieldTypeDescription
filestringOriginal filename
sha256stringHash of source content
typestringSpec type (openapi or asyncapi)
versionstringSpec version (e.g., 3.1.0)

bundled_plugins entry

FieldTypeDescription
namestringPlugin name (kebab-case)
versionstringPlugin version (semver)
plugin_typestringPlugin type (middleware or dispatcher)
wasm_pathstringPath to WASM file within artifact
sha256stringSHA-256 hash of WASM file

routes.json

Compiled operations with routing information.

{
  "operations": [
    {
      "index": 0,
      "path": "/users",
      "method": "GET",
      "operation_id": "listUsers",
      "dispatch": {
        "name": "http",
        "config": {
          "upstream": "backend",
          "path": "/api/users"
        }
      }
    },
    {
      "index": 1,
      "path": "/users/{id}",
      "method": "GET",
      "operation_id": "getUser",
      "dispatch": {
        "name": "http",
        "config": {
          "upstream": "backend",
          "path": "/api/users/{id}"
        }
      }
    }
  ]
}

operation entry

FieldTypeDescription
indexintegerUnique operation index
pathstringOpenAPI path template
methodstringHTTP method (uppercase)
operation_idstringOperation ID (optional)
dispatchobjectDispatcher configuration

specs/

Directory containing the original source specifications. These are embedded for:

  • Serving via /__barbacane/openapi endpoint
  • Documentation and debugging
  • Audit trail

Files retain their original names.

Version History

VersionChanges
1Initial format

Inspecting Artifacts

List Contents

tar -tzf artifact.bca

Output:

manifest.json
routes.json
specs/
specs/api.yaml
plugins/
plugins/rate-limit.wasm

Extract and View

# Extract
tar -xzf artifact.bca -C ./extracted

# View manifest
cat extracted/manifest.json | jq .

# View routes
cat extracted/routes.json | jq '.operations | length'

Verify Checksums

# Extract
tar -xzf artifact.bca -C ./extracted

# Verify routes.json
sha256sum extracted/routes.json
# Compare with manifest.checksums["routes.json"]

Security Considerations

Integrity

  • All embedded files have SHA-256 checksums in the manifest
  • The gateway can verify checksums on load (planned)

Contents

  • Source specs are embedded and served publicly via /__barbacane/openapi
  • Do not include secrets in spec files
  • Use environment variables or secret management for sensitive config

Signing (Planned)

Future versions will support:

  • GPG signatures
  • Artifact signing with private keys
  • Signature verification on load

Programmatic Access

Rust

use barbacane_compiler::{load_manifest, load_routes, load_specs, load_plugins};
use std::path::Path;

let path = Path::new("artifact.bca");

// Load manifest
let manifest = load_manifest(path)?;
println!("Routes: {}", manifest.routes_count);

// Load routes
let routes = load_routes(path)?;
for op in &routes.operations {
    println!("{} {}", op.method, op.path);
}

// Load specs
let specs = load_specs(path)?;
for (name, content) in &specs {
    println!("Spec: {} ({} bytes)", name, content.len());
}

// Load plugins
let plugins = load_plugins(path)?;
for (name, wasm_bytes) in &plugins {
    println!("Plugin: {} ({} bytes)", name, wasm_bytes.len());
}

Best Practices

Naming

Use descriptive names:

my-api-v2.1.0.bca
gateway-prod-2025-01-29.bca

Version Control

Don’t commit .bca files to git. Instead:

  • Commit source specs
  • Build artifacts in CI/CD
  • Store in artifact registry

CI/CD Pipeline

# Compile in CI
barbacane compile \
  --spec specs/*.yaml \
  --output dist/gateway-${VERSION}.bca

# Upload to registry
aws s3 cp dist/gateway-${VERSION}.bca s3://artifacts/

# Deploy
ssh prod "barbacane serve --artifact /opt/barbacane/gateway.bca"

Reserved Endpoints

Barbacane reserves the /__barbacane/* path prefix for gateway introspection and management endpoints. These are always available regardless of your spec configuration.

Health Check

GET /__barbacane/health

Returns the gateway health status.

Response

{
  "status": "healthy",
  "artifact_version": 1,
  "compiler_version": "0.1.0",
  "routes_count": 12
}

Fields

FieldTypeDescription
statusstringAlways "healthy" if responding
artifact_versioninteger.bca format version
compiler_versionstringbarbacane version that compiled the artifact
routes_countintegerNumber of routes loaded

Usage

# Kubernetes liveness probe
livenessProbe:
  httpGet:
    path: /__barbacane/health
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 10

# Load balancer health check
curl -f http://localhost:8080/__barbacane/health

OpenAPI Spec

GET /__barbacane/openapi

Returns the embedded OpenAPI specification(s).

Single Spec

When the artifact contains one spec, returns it directly:

curl http://localhost:8080/__barbacane/openapi

Response: The original YAML/JSON spec

Headers:

  • Content-Type: application/x-yaml (for YAML files)
  • Content-Type: application/json (for JSON files)

Multiple Specs

When the artifact contains multiple specs, returns an index:

curl http://localhost:8080/__barbacane/openapi
{
  "specs": [
    {
      "name": "users-api.yaml",
      "url": "/__barbacane/openapi/users-api.yaml"
    },
    {
      "name": "orders-api.yaml",
      "url": "/__barbacane/openapi/orders-api.yaml"
    }
  ],
  "count": 2
}

Then fetch individual specs:

curl http://localhost:8080/__barbacane/openapi/users-api.yaml

Usage

# Swagger UI integration
# Point Swagger UI to: http://your-gateway/__barbacane/openapi

# Download spec for documentation
curl -o api.yaml http://localhost:8080/__barbacane/openapi

# API client generation
curl http://localhost:8080/__barbacane/openapi | \
  openapi-generator generate -i /dev/stdin -g typescript-fetch -o ./client

Path Reservation

The entire /__barbacane/ prefix is reserved. Attempting to define operations under this path in your spec will result in undefined behavior (your routes may be shadowed by built-in endpoints).

Don’t do this:

paths:
  /__barbacane/custom:  # BAD: Reserved prefix
    get:
      ...

Prometheus Metrics

GET /__barbacane/metrics

Returns gateway metrics in Prometheus text exposition format.

Response

# HELP barbacane_requests_total Total number of HTTP requests processed
# TYPE barbacane_requests_total counter
barbacane_requests_total{method="GET",path="/users",status="200",api="users-api"} 42

# HELP barbacane_request_duration_seconds HTTP request duration in seconds
# TYPE barbacane_request_duration_seconds histogram
barbacane_request_duration_seconds_bucket{method="GET",path="/users",status="200",api="users-api",le="0.01"} 35
...

# HELP barbacane_active_connections Number of currently active connections
# TYPE barbacane_active_connections gauge
barbacane_active_connections 5

Available Metrics

MetricTypeLabelsDescription
barbacane_requests_totalcountermethod, path, status, apiTotal requests processed
barbacane_request_duration_secondshistogrammethod, path, status, apiRequest latency
barbacane_request_size_byteshistogrammethod, path, status, apiRequest body size
barbacane_response_size_byteshistogrammethod, path, status, apiResponse body size
barbacane_active_connectionsgauge-Current open connections
barbacane_connections_totalcounter-Total connections accepted
barbacane_validation_failures_totalcountermethod, path, reasonValidation errors
barbacane_middleware_duration_secondshistogrammiddleware, phaseMiddleware execution time
barbacane_dispatch_duration_secondshistogramdispatcher, upstreamDispatcher execution time
barbacane_wasm_execution_duration_secondshistogramplugin, functionWASM plugin execution time

Usage

# Scrape metrics
curl http://localhost:8080/__barbacane/metrics
# Prometheus scrape config
scrape_configs:
  - job_name: 'barbacane'
    static_configs:
      - targets: ['barbacane:8080']
    metrics_path: '/__barbacane/metrics'

Future Endpoints

These endpoints are planned for future releases:

EndpointPurpose
/__barbacane/readyReadiness probe (after warm-up)
/__barbacane/configRuntime configuration
/__barbacane/routesRoute table inspection

Security Considerations

Reserved endpoints are public by default. In production, consider:

  1. Network segmentation: Only expose port 8080 to your load balancer
  2. Firewall rules: Block /__barbacane/* from public access
  3. Reverse proxy: Strip or restrict access to reserved paths

Example nginx configuration:

location /__barbacane/ {
    # Only allow from internal network
    allow 10.0.0.0/8;
    deny all;

    proxy_pass http://barbacane:8080;
}

location / {
    proxy_pass http://barbacane:8080;
}

Architecture

This document describes Barbacane’s system architecture for contributors.

High-Level Overview

┌─────────────────────────────────────────────────────────────────┐
│                         Control Plane                            │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────────────┐  │
│  │   OpenAPI   │───▶│   Parser    │───▶│      Compiler       │  │
│  │    Specs    │    │             │    │  (validation, trie) │  │
│  └─────────────┘    └─────────────┘    └──────────┬──────────┘  │
│                                                    │             │
│                                                    ▼             │
│                                           ┌───────────────┐     │
│                                           │  .bca Artifact │     │
│                                           └───────┬───────┘     │
└───────────────────────────────────────────────────┼─────────────┘
                                                    │
                                                    ▼
┌─────────────────────────────────────────────────────────────────┐
│                          Data Plane                              │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────────────┐  │
│  │   Artifact  │───▶│   Router    │───▶│    Dispatchers      │  │
│  │   Loader    │    │   (trie)    │    │  (mock, http, ...)  │  │
│  └─────────────┘    └─────────────┘    └─────────────────────┘  │
│         │                  │                      │              │
│         │                  ▼                      ▼              │
│         │           ┌─────────────┐    ┌─────────────────────┐  │
│         │           │ Middlewares │◀──▶│   Plugin Runtime    │  │
│         │           │   Chain     │    │      (WASM)         │  │
│         │           └─────────────┘    └─────────────────────┘  │
│         │                                                        │
│         ▼                                                        │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                    HTTP Server (hyper)                   │    │
│  └─────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────┘

Crate Structure

The project is organized as a Cargo workspace with specialized crates:

crates/
├── barbacane/              # Main CLI (compile, validate, serve)
├── barbacane-control/      # Control plane CLI (spec upload, plugin register)
├── barbacane-compiler/     # Spec compilation & artifact format
├── barbacane-spec-parser/  # OpenAPI/AsyncAPI parsing
├── barbacane-router/       # Prefix trie request routing
├── barbacane-validator/    # Request validation
├── barbacane-wasm/         # WASM plugin runtime (wasmtime)
├── barbacane-plugin-sdk/   # WASM plugin development kit
├── barbacane-plugin-macros/# Proc macros for plugin development
└── barbacane-test/         # Integration test harness

Crate Dependencies

barbacane (CLI / data plane)
    ├── barbacane-compiler
    │   ├── barbacane-spec-parser
    │   └── barbacane-router
    ├── barbacane-validator
    ├── barbacane-router
    └── barbacane-wasm
        └── barbacane-plugin-sdk

barbacane-plugin-sdk
    └── barbacane-plugin-macros

barbacane-test
    └── barbacane-compiler

Crate Details

barbacane-spec-parser

Parses OpenAPI and AsyncAPI specifications and extracts Barbacane extensions.

Key types:

  • ApiSpec - Parsed specification with operations and metadata
  • Operation - Single API operation with dispatch/middleware config
  • DispatchConfig - Dispatcher name and configuration
  • MiddlewareConfig - Middleware name and configuration
  • Channel - AsyncAPI channel with publish/subscribe operations

Supported formats:

  • OpenAPI 3.0.x
  • OpenAPI 3.1.x
  • OpenAPI 3.2.x (draft)
  • AsyncAPI 3.x (parsing supported, dispatchers planned)

barbacane-router

Prefix trie implementation for fast HTTP request routing.

Key types:

  • Router - The routing trie
  • RouteEntry - Points to compiled operation index
  • RouteMatch - Found / MethodNotAllowed / NotFound

Features:

  • O(path length) lookup
  • Static routes take precedence over parameters
  • Path parameter extraction
  • Path normalization (trailing slashes, double slashes)

barbacane-compiler

Compiles parsed specs into deployable artifacts.

Responsibilities:

  • Validate dispatcher requirements (every operation needs dispatch)
  • Detect routing conflicts (same path+method in multiple specs)
  • Build routing trie
  • Package into .bca archive

Artifact format (.bca):

artifact.bca (tar.gz)
├── manifest.json       # Metadata, checksums, bundled plugins
├── routes.json         # Compiled operations
├── specs/              # Embedded source specs
│   ├── api.yaml
│   └── ...
└── plugins/            # Bundled WASM plugins (optional)
    ├── rate-limit.wasm
    └── ...

barbacane

Main CLI with three subcommands:

  • compile - Compile specs to artifact
  • validate - Validate specs without compilation
  • serve - Run the gateway

barbacane (serve)

Data plane binary - the actual gateway.

Startup flow:

  1. Load artifact from disk
  2. Load compiled routes from artifact
  3. Load bundled plugins from artifact
  4. Compile WASM modules (AOT)
  5. Resolve secrets - scan configs for env:// and file:// references
  6. Create plugin instance pool with resolved secrets
  7. Start HTTP server

If any secret cannot be resolved in step 5, the gateway exits with code 13.

Request flow:

  1. Receive HTTP request
  2. Check reserved endpoints (/__barbacane/*)
  3. Route lookup in trie
  4. Apply middleware chain
  5. Dispatch to handler
  6. Apply response middlewares
  7. Send response

barbacane-wasm

WASM plugin runtime built on wasmtime.

Key types:

  • WasmEngine - Configured wasmtime engine with AOT compilation
  • InstancePool - Instance pooling per (plugin_name, config_hash)
  • PluginInstance - Single WASM instance with host function bindings
  • MiddlewareChain - Ordered middleware execution

Host functions:

  • host_set_output - Plugin writes result to host buffer
  • host_log - Structured logging with trace context
  • host_context_get/set - Per-request key-value store
  • host_clock_now - Monotonic time in milliseconds
  • host_http_call - Make outbound HTTP requests
  • host_http_read_result - Read HTTP response data
  • host_get_secret - Get a resolved secret by reference
  • host_secret_read_result - Read secret value into plugin memory

Resource limits:

  • 16 MB linear memory
  • 1 MB stack
  • 100ms execution timeout (via fuel)

barbacane-plugin-sdk

SDK for developing WASM plugins (dispatchers and middlewares).

Provides:

  • Request, Response, Action types
  • #[barbacane_middleware] macro - generates WASM exports for middlewares
  • #[barbacane_dispatcher] macro - generates WASM exports for dispatchers
  • Host function FFI bindings

barbacane-plugin-macros

Proc macros for plugin development (used by barbacane-plugin-sdk).

Generates:

  • init(ptr, len) -> i32 - Initialize with JSON config
  • on_request(ptr, len) -> i32 - Process request (0=continue, 1=short-circuit)
  • on_response(ptr, len) -> i32 - Process response
  • dispatch(ptr, len) -> i32 - Handle request and return response

barbacane-test

Integration testing harness.

Key types:

  • TestGateway - Spins up gateway with compiled artifact on random port
  • Request helpers for easy HTTP testing

Request Lifecycle

┌──────────────────────────────────────────────────────────────────┐
│                         Request Flow                              │
└──────────────────────────────────────────────────────────────────┘

    Client Request
          │
          ▼
    ┌───────────┐
    │  Receive  │  TCP accept, HTTP parse
    └─────┬─────┘
          │
          ▼
    ┌───────────┐
    │  Reserved │  /__barbacane/* check
    │  Endpoint │  (health, openapi, etc.)
    └─────┬─────┘
          │ Not reserved
          ▼
    ┌───────────┐
    │   Route   │  Trie lookup: path + method
    │   Lookup  │  Returns: Found / NotFound / MethodNotAllowed
    └─────┬─────┘
          │ Found
          ▼
    ┌───────────┐
    │ Middleware│  Global middlewares
    │  (Global) │  auth, rate-limit, cors, etc.
    └─────┬─────┘
          │
          ▼
    ┌───────────┐
    │ Middleware│  Operation-specific middlewares
    │ (Operation│  May override global config
    └─────┬─────┘
          │
          ▼
    ┌───────────┐
    │ Dispatch  │  mock, http, custom plugins
    └─────┬─────┘
          │
          ▼
    ┌───────────┐
    │ Response  │  Reverse middleware chain
    │ Middleware│  Transform response
    └─────┬─────┘
          │
          ▼
    ┌───────────┐
    │   Send    │  HTTP response to client
    └───────────┘

Plugin Architecture

Plugins are WebAssembly (WASM) modules that implement dispatchers or middlewares.

┌─────────────────────────────────────────────────────────┐
│                    Plugin Contract                       │
├─────────────────────────────────────────────────────────┤
│  Middleware exports:                                     │
│    - on_request(ctx) -> Continue | Respond | Error      │
│    - on_response(ctx) -> Continue | Modify | Error      │
│                                                          │
│  Dispatcher exports:                                     │
│    - dispatch(ctx) -> Response | Error                  │
│                                                          │
│  Common:                                                 │
│    - init(config) -> Ok | Error                         │
├─────────────────────────────────────────────────────────┤
│  Host functions (provided by runtime):                   │
│    - http_call(req) -> Response                         │
│    - log(level, message)                                │
│    - get_secret(name) -> Value                          │
│    - context_get(key) -> Value                          │
│    - context_set(key, value)                            │
└─────────────────────────────────────────────────────────┘

Key Design Decisions

Compilation Model

Decision: Compile specs to artifacts at build time, not runtime.

Rationale:

  • Fail fast: catch configuration errors before deployment
  • Reproducible: artifact is immutable, version-controlled
  • Fast startup: no parsing at runtime
  • Secure: no spec files needed in production

Prefix Trie Routing

Decision: Use a prefix trie for routing instead of linear search.

Rationale:

  • O(path length) lookup regardless of route count
  • Natural handling of path parameters
  • Easy static-over-param precedence

WASM Plugins

Decision: Use WebAssembly for plugin sandboxing.

Rationale:

  • Language agnostic (Rust, Go, AssemblyScript, etc.)
  • Secure sandbox (no filesystem, network without host functions)
  • Near-native performance
  • Portable across platforms

Embedded Specs

Decision: Embed source specs in the artifact.

Rationale:

  • Self-documenting: /__barbacane/openapi always works
  • No external dependencies at runtime
  • Version consistency

Testing Strategy

Unit Tests (per crate)
    ├── Parser: various OpenAPI versions, edge cases
    ├── Router: routing scenarios, parameters, precedence
    └── Compiler: validation, conflict detection

Integration Tests (barbacane-test)
    └── TestGateway: full request/response cycles
        ├── Health endpoint
        ├── Mock dispatcher
        ├── 404 / 405 handling
        └── Path parameters

Run all tests:

cargo test --workspace

Performance Considerations

  • Zero-copy routing: Trie lookup doesn’t allocate
  • Connection reuse: HTTP/1.1 keep-alive by default
  • Async I/O: Tokio runtime, non-blocking everything
  • Plugin caching: WASM modules compiled once, instantiated per-request

Future Directions

  • gRPC passthrough: Transparent proxying for gRPC services
  • Hot reload: Reload artifacts without restart via control plane notifications
  • Cluster mode: Distributed configuration across multiple nodes
  • AsyncAPI dispatchers: Event-driven APIs with Kafka/NATS dispatch (parsing already supported)

Development Guide

This guide helps you set up a development environment for contributing to Barbacane.

Prerequisites

  • Rust 1.75+ - Install via rustup
  • Git - For version control
  • Node.js 20+ - For the UI (if working on the web interface)
  • PostgreSQL 14+ - For the control plane (or use Docker)
  • Docker - For running PostgreSQL locally (optional)

Optional:

  • cargo-watch - For auto-rebuild on file changes
  • wasm32-unknown-unknown target - For building WASM plugins (rustup target add wasm32-unknown-unknown)
  • tmux - For running multiple services in one terminal

Quick Start with Makefile

The easiest way to get started is using the Makefile:

# Start PostgreSQL in Docker
make db-up

# Build all WASM plugins and seed them into the database
make seed-plugins

# Start the control plane (port 9090)
make control-plane

# In another terminal, start the UI (port 5173)
make ui

Then open http://localhost:5173 in your browser.

Makefile Targets

TargetDescription
Build & Test
makeRun check + test (default)
make testRun all workspace tests
make test-verboseRun tests with output
make test-one TEST=nameRun specific test
make clippyRun clippy lints
make fmtFormat all code
make checkRun fmt-check + clippy
make buildBuild debug
make releaseBuild release
make pluginsBuild all WASM plugins
make seed-pluginsBuild plugins and seed registry
make cleanClean all build artifacts
Development
make control-planeStart control plane server (port 9090)
make uiStart UI dev server (port 5173)
make devShow instructions to start both
make dev-tmuxStart both in tmux session
Database
make db-upStart PostgreSQL container
make db-downStop PostgreSQL container
make db-resetReset database (removes all data)

Override the database URL:

make control-plane DATABASE_URL=postgres://user:pass@host/db

Getting Started

Clone the Repository

git clone https://github.com/barbacane/barbacane.git
cd barbacane

Build

# Build all crates
cargo build --workspace

# Build in release mode
cargo build --workspace --release

Test

# Run all tests
cargo test --workspace

# Run tests for a specific crate
cargo test -p barbacane-router

# Run tests with output
cargo test --workspace -- --nocapture

# Run a specific test
cargo test -p barbacane-router trie::tests::static_takes_precedence

Run

# Validate a spec
cargo run --bin barbacane -- validate --spec tests/fixtures/minimal.yaml

# Compile a spec
cargo run --bin barbacane -- compile --spec tests/fixtures/minimal.yaml --output test.bca

# Run the gateway
cargo run --bin barbacane -- serve --artifact test.bca --listen 127.0.0.1:8080 --dev

Project Structure

barbacane/
├── Cargo.toml              # Workspace definition
├── Makefile                # Development shortcuts
├── docker-compose.yml      # PostgreSQL for local dev
├── LICENSE
├── CONTRIBUTING.md
├── README.md
│
├── crates/
│   ├── barbacane/          # Data plane CLI (compile, validate, serve)
│   │   ├── Cargo.toml
│   │   └── src/
│   │       └── main.rs
│   │
│   ├── barbacane-control/  # Control plane server
│   │   ├── Cargo.toml
│   │   ├── openapi.yaml    # API specification
│   │   └── src/
│   │       ├── main.rs
│   │       ├── server.rs
│   │       └── db/
│   │
│   ├── barbacane-compiler/ # Compilation logic
│   │   ├── Cargo.toml
│   │   └── src/
│   │       ├── lib.rs
│   │       ├── artifact.rs
│   │       └── error.rs
│   │
│   ├── barbacane-spec-parser/  # OpenAPI/AsyncAPI parsing
│   │   ├── Cargo.toml
│   │   └── src/
│   │       ├── lib.rs
│   │       ├── openapi.rs
│   │       ├── asyncapi.rs
│   │       └── error.rs
│   │
│   ├── barbacane-router/   # Request routing
│   │   ├── Cargo.toml
│   │   └── src/
│   │       ├── lib.rs
│   │       └── trie.rs
│   │
│   ├── barbacane-plugin-sdk/  # Plugin development SDK
│   │   ├── Cargo.toml
│   │   └── src/
│   │       └── lib.rs
│   │
│   └── barbacane-test/     # Test harness
│       ├── Cargo.toml
│       └── src/
│           ├── lib.rs
│           └── gateway.rs
│
├── plugins/                # Built-in WASM plugins
│   ├── http-upstream/      # HTTP reverse proxy dispatcher
│   ├── mock/               # Mock response dispatcher
│   ├── lambda/             # AWS Lambda dispatcher
│   ├── kafka/              # Kafka dispatcher (AsyncAPI)
│   ├── nats/               # NATS dispatcher (AsyncAPI)
│   ├── rate-limit/         # Rate limiting middleware
│   ├── cors/               # CORS middleware
│   ├── cache/              # Caching middleware
│   ├── jwt-auth/           # JWT authentication
│   ├── apikey-auth/        # API key authentication
│   └── oauth2-auth/        # OAuth2 token introspection
│
├── ui/                     # React web interface
│   ├── package.json
│   ├── vite.config.ts
│   └── src/
│       ├── pages/          # Page components
│       ├── components/     # UI components
│       ├── hooks/          # Custom React hooks
│       └── lib/            # API client, utilities
│
├── tests/
│   └── fixtures/           # Test spec files
│       ├── minimal.yaml
│       ├── train-travel-3.0.yaml
│       └── ...
│
├── docs/                   # Documentation
│   ├── index.md
│   ├── guide/
│   ├── reference/
│   └── contributing/
│
└── adr/                    # Architecture Decision Records
    ├── 0001-*.md
    └── ...

Development Workflow

Making Changes

  1. Create a branch

    git checkout -b feature/my-feature
    
  2. Make changes and test

    cargo test --workspace
    
  3. Format code

    cargo fmt --all
    
  4. Check lints

    cargo clippy --workspace -- -D warnings
    
  5. Commit

    git commit -m "feat: add my feature"
    

Commit Messages

Follow Conventional Commits:

  • feat: - New feature
  • fix: - Bug fix
  • docs: - Documentation
  • refactor: - Code refactoring
  • test: - Adding tests
  • chore: - Maintenance

Examples:

feat: add cache middleware
fix: handle empty path in router
docs: add middleware configuration guide
refactor: extract trie traversal logic
test: add integration tests for 405 responses

Adding a New Crate

  1. Create the crate directory:

    mkdir -p crates/barbacane-mycrate/src
    
  2. Create Cargo.toml:

    [package]
    name = "barbacane-mycrate"
    description = "Description here"
    version.workspace = true
    edition.workspace = true
    license.workspace = true
    
    [dependencies]
    # Use workspace dependencies
    serde = { workspace = true }
    
  3. Add to workspace in root Cargo.toml:

    [workspace]
    members = [
        # ...existing crates...
        "crates/barbacane-mycrate",
    ]
    
    [workspace.dependencies]
    barbacane-mycrate = { path = "crates/barbacane-mycrate" }
    
  4. Create src/lib.rs:

    //! Brief description of the crate.
    //!
    //! More detailed explanation.

Testing

Unit Tests

Place unit tests in the same file:

// src/parser.rs

pub fn parse(input: &str) -> Result<Spec, Error> {
    // implementation
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parse_minimal() {
        let result = parse("openapi: 3.1.0...");
        assert!(result.is_ok());
    }
}

Integration Tests

Use barbacane-test crate for full-stack tests:

use barbacane_test::TestGateway;

#[tokio::test]
async fn test_my_feature() {
    let gateway = TestGateway::from_spec("tests/fixtures/my-fixture.yaml")
        .await
        .expect("failed to start gateway");

    let resp = gateway.get("/my-endpoint").await.unwrap();
    assert_eq!(resp.status(), 200);
}

Test Fixtures

Add test spec files to tests/fixtures/:

# tests/fixtures/my-feature.yaml
openapi: "3.1.0"
info:
  title: Test
  version: "1.0.0"
paths:
  /test:
    get:
      x-barbacane-dispatch:
        name: mock
        config:
          status: 200

UI Development

The web interface is a React application in the ui/ directory.

Setup

cd ui
npm install

Development Server

# Using Makefile (from project root)
make ui

# Or manually
cd ui && npm run dev

The UI runs at http://localhost:5173 and proxies API requests to the control plane at http://localhost:9090.

Testing

cd ui
npm run test        # Run tests once
npm run test:watch  # Watch mode

Key Directories

ui/src/
├── pages/         # Page components (ProjectPluginsPage, etc.)
├── components/    # Reusable UI components
│   └── ui/        # Base components (Button, Card, Badge)
├── hooks/         # Custom hooks (useJsonSchema, usePlugins)
├── lib/
│   ├── api/       # API client (types, requests)
│   └── utils.ts   # Utilities (cn, formatters)
└── App.tsx        # Main app with routing

Adding a New Page

  1. Create page component in src/pages/:

    // src/pages/my-feature.tsx
    export function MyFeaturePage() {
      return <div>...</div>
    }
    
  2. Add route in src/App.tsx:

    <Route path="/my-feature" element={<MyFeaturePage />} />
    

API Client

Use the typed API client from @/lib/api:

import { useQuery } from '@tanstack/react-query'
import { listPlugins } from '@/lib/api'

function MyComponent() {
  const { data: plugins, isLoading } = useQuery({
    queryKey: ['plugins'],
    queryFn: () => listPlugins(),
  })
  // ...
}

Debugging

Logging

Use eprintln! for development logging:

if cfg!(debug_assertions) {
    eprintln!("debug: processing request to {}", path);
}

Running with Verbose Output

# Gateway with dev mode
cargo run --bin barbacane -- serve --artifact test.bca --dev

# Compile with output
cargo run --bin barbacane -- compile --spec api.yaml --output api.bca

Integration Test Debugging

# Run single test with output
cargo test -p barbacane-test test_gateway_health -- --nocapture

Performance Profiling

Benchmarks

Criterion benchmarks are available for performance-critical components:

# Run all benchmarks
cargo bench --workspace

# Run router benchmarks (trie lookup and insertion)
cargo bench -p barbacane-router

# Run validator benchmarks (schema validation)
cargo bench -p barbacane-validator

Router benchmarks (crates/barbacane-router/benches/routing.rs):

  • router_lookup - Measures lookup performance for static paths, parameterized paths, and not-found cases
  • router_insert - Measures route insertion performance at various route counts (10-1000 routes)

Validator benchmarks (crates/barbacane-validator/benches/validation.rs):

  • validator_creation - Measures schema compilation time
  • path_param_validation - Validates path parameters against schemas
  • query_param_validation - Validates query parameters
  • body_validation - Validates JSON request bodies
  • full_request_validation - End-to-end request validation

Benchmark results are saved to target/criterion/ with HTML reports.

Flamegraph

cargo install flamegraph
cargo flamegraph -p barbacane -- --artifact test.bca

Documentation

Doc Comments

All public APIs should have doc comments:

/// Parse an OpenAPI specification from a string.
///
/// # Arguments
///
/// * `input` - YAML or JSON string containing the spec
///
/// # Returns
///
/// Parsed `ApiSpec` or error if parsing fails.
///
/// # Example
///
/// ```
/// let spec = parse_spec("openapi: 3.1.0...")?;
/// println!("Found {} operations", spec.operations.len());
/// ```
pub fn parse_spec(input: &str) -> Result<ApiSpec, ParseError> {
    // ...
}

Generate Docs

cargo doc --workspace --open

Release Process

  1. Update version in workspace Cargo.toml
  2. Update CHANGELOG.md
  3. Create git tag: git tag v0.1.0
  4. Push: git push origin main --tags
  5. CI builds and publishes

Getting Help

  • Open an issue on GitHub
  • Check existing ADRs for design decisions
  • Read the architecture docs

Plugin Development Guide

This guide explains how to create WASM plugins for Barbacane.

Overview

Barbacane plugins are WebAssembly (WASM) modules that extend gateway functionality. There are two types:

TypePurposeExports
MiddlewareProcess requests/responses in a chaininit, on_request, on_response
DispatcherHandle requests and generate responsesinit, dispatch

Prerequisites

  • Rust stable with wasm32-unknown-unknown target
  • barbacane-plugin-sdk crate
# Add the WASM target
rustup target add wasm32-unknown-unknown

Quick Start

1. Create a New Plugin

cargo new --lib my-plugin
cd my-plugin

2. Configure Cargo.toml

[package]
name = "my-plugin"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
barbacane-plugin-sdk = { path = "../path/to/barbacane/crates/barbacane-plugin-sdk" }
serde = { version = "1", features = ["derive"] }
serde_json = "1"

3. Write the Plugin

Middleware example:

use barbacane_plugin_sdk::prelude::*;
use serde::Deserialize;

#[barbacane_middleware]
#[derive(Deserialize)]
pub struct MyMiddleware {
    // Configuration fields from the spec
    header_name: String,
    header_value: String,
}

impl MyMiddleware {
    pub fn on_request(&mut self, req: Request) -> Action {
        // Add a header to the request
        let mut req = req;
        req.headers.insert(
            self.header_name.clone(),
            self.header_value.clone(),
        );
        Action::Continue(req)
    }

    pub fn on_response(&mut self, resp: Response) -> Response {
        // Pass through unchanged
        resp
    }
}

Dispatcher example:

use barbacane_plugin_sdk::prelude::*;
use serde::Deserialize;

#[barbacane_dispatcher]
#[derive(Deserialize)]
pub struct MyDispatcher {
    status: u16,
    body: String,
}

impl MyDispatcher {
    pub fn dispatch(&mut self, _req: Request) -> Response {
        Response {
            status: self.status,
            headers: Default::default(),
            body: Some(self.body.clone()),
        }
    }
}

4. Create plugin.toml

[plugin]
name = "my-plugin"
version = "0.1.0"
type = "middleware"  # or "dispatcher"
description = "My custom plugin"
wasm = "my_plugin.wasm"

[capabilities]
host_functions = ["log"]

5. Create config-schema.json

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["header_name", "header_value"],
  "properties": {
    "header_name": {
      "type": "string",
      "description": "Header name to add"
    },
    "header_value": {
      "type": "string",
      "description": "Header value to set"
    }
  }
}

6. Build

cargo build --target wasm32-unknown-unknown --release
cp target/wasm32-unknown-unknown/release/my_plugin.wasm .

Plugin SDK Types

Request

pub struct Request {
    pub method: String,      // HTTP method (GET, POST, etc.)
    pub path: String,        // Request path
    pub query: Option<String>, // Query string
    pub headers: BTreeMap<String, String>,
    pub body: Option<String>,
    pub client_ip: String,
    pub path_params: BTreeMap<String, String>,
}

Response

pub struct Response {
    pub status: u16,
    pub headers: BTreeMap<String, String>,
    pub body: Option<String>,
}

Action (Middleware only)

pub enum Action {
    /// Continue to next middleware/dispatcher with (possibly modified) request
    Continue(Request),
    /// Short-circuit the chain and return this response immediately
    Respond(Response),
}

Host Functions

Plugins can call host functions to access gateway capabilities. Declare required capabilities in plugin.toml:

Logging

[capabilities]
host_functions = ["log"]
use barbacane_plugin_sdk::host;

host::log("info", "Processing request");
host::log("error", "Something went wrong");

Context (per-request key-value store)

[capabilities]
host_functions = ["context_get", "context_set"]
use barbacane_plugin_sdk::host;

// Set a value for downstream middleware/dispatcher
host::context_set("user_id", "12345");

// Get a value set by upstream middleware
if let Some(value) = host::context_get("auth_token") {
    // use value
}

Clock

[capabilities]
host_functions = ["clock_now"]
use barbacane_plugin_sdk::host;

let timestamp_ms = host::clock_now();

Secrets

[capabilities]
host_functions = ["get_secret"]
use barbacane_plugin_sdk::host;

// Secrets are resolved at gateway startup from env:// or file:// references
if let Some(api_key) = host::get_secret("api_key") {
    // use api_key
}

HTTP Calls (Dispatcher only)

[capabilities]
host_functions = ["http_call"]
use barbacane_plugin_sdk::host;

let response = host::http_call(HttpRequest {
    method: "GET".to_string(),
    url: "https://api.example.com/data".to_string(),
    headers: Default::default(),
    body: None,
    timeout_ms: Some(5000),
})?;

Using Plugins in Specs

Declare in barbacane.yaml

plugins:
  my-plugin:
    path: ./plugins/my_plugin.wasm

Use in OpenAPI spec

As middleware:

paths:
  /users:
    get:
      x-barbacane-middlewares:
        - name: my-plugin
          config:
            header_name: "X-Custom"
            header_value: "hello"

As dispatcher:

paths:
  /mock:
    get:
      x-barbacane-dispatch:
        name: my-plugin
        config:
          status: 200
          body: '{"message": "Hello"}'

Testing Plugins

Unit Testing

Test your plugin logic directly:

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_adds_header() {
        let mut plugin = MyMiddleware {
            header_name: "X-Test".to_string(),
            header_value: "value".to_string(),
        };

        let req = Request {
            method: "GET".to_string(),
            path: "/test".to_string(),
            headers: Default::default(),
            ..Default::default()
        };

        let action = plugin.on_request(req);
        match action {
            Action::Continue(req) => {
                assert_eq!(req.headers.get("X-Test"), Some(&"value".to_string()));
            }
            _ => panic!("Expected Continue"),
        }
    }
}

Integration Testing

Use fixture specs with barbacane-test:

use barbacane_test::TestGateway;

#[tokio::test]
async fn test_my_plugin() {
    let gw = TestGateway::from_spec("tests/fixtures/my-plugin-test.yaml")
        .await
        .unwrap();

    let resp = gw.get("/test").await.unwrap();
    assert_eq!(resp.status(), 200);
    assert_eq!(resp.headers().get("X-Test"), Some("value"));
}

Official Plugins

Barbacane includes these official plugins in the plugins/ directory:

PluginTypeDescription
mockDispatcherReturn static responses
http-upstreamDispatcherReverse proxy to HTTP backends
lambdaDispatcherInvoke AWS Lambda functions
jwt-authMiddlewareJWT token validation
apikey-authMiddlewareAPI key authentication
oauth2-authMiddlewareOAuth2 token introspection
rate-limitMiddlewareSliding window rate limiting
cacheMiddlewareResponse caching
corsMiddlewareCORS header management

Use these as references for your own plugins.

Best Practices

  1. Keep plugins focused - One plugin, one responsibility
  2. Validate configuration - Use JSON Schema to catch config errors at compile time
  3. Handle errors gracefully - Return appropriate error responses, don’t panic
  4. Document capabilities - Only declare host functions you actually use
  5. Test thoroughly - Unit test logic, integration test with the gateway
  6. Use semantic versioning - Follow semver for plugin versions

Resource Limits

Plugins run in a sandboxed WASM environment with these limits:

ResourceLimit
Linear memory16 MB
Stack size1 MB
Execution time100 ms

Exceeding these limits results in a trap (500 error for request phase, fault-tolerant for response phase).

Troubleshooting

Plugin not found

Ensure the plugin is declared in barbacane.yaml and the WASM file exists at the specified path.

Config validation failed

Check that your plugin’s configuration in the OpenAPI spec matches the JSON Schema in config-schema.json.

WASM trap

Your plugin exceeded resource limits or panicked. Check logs for details. Common causes:

  • Infinite loops
  • Large memory allocations
  • Unhandled errors causing panic

Unknown capability

You’re using a host function not declared in plugin.toml. Add it to capabilities.host_functions.