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
- Getting Started - First steps with Barbacane
- Spec Configuration - Configure routing and middleware in your OpenAPI spec
- Dispatchers - Route requests to backends
- Middlewares - Add authentication, rate limiting, and more
- Secrets - Manage secrets in plugin configurations
- Observability - Metrics, logging, and distributed tracing
- Control Plane - REST API for spec and artifact management
- Web UI - Web-based management interface
Reference
- CLI Reference - Command-line tools
- Spec Extensions - Complete
x-barbacane-*reference - Artifact Format -
.bcafile format - Reserved Endpoints -
/__barbacane/*endpoints
Contributing
- Architecture - System design and crate structure
- Development Guide - Setting up and building
- Plugin Development - Creating WASM plugins
Supported Spec Versions
| Format | Version | Status |
|---|---|---|
| OpenAPI | 3.0.x | Supported |
| OpenAPI | 3.1.x | Supported |
| OpenAPI | 3.2.x | Supported (draft) |
| AsyncAPI | 3.0.x | Supported |
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 configuredapi.yaml— OpenAPI spec with example endpointsplugins/mock.wasm— mock dispatcher pluginplugins/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-dispatchon 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
| Extension | Location | Purpose |
|---|---|---|
x-barbacane-upstream | Server object | Define named backend connections |
x-barbacane-dispatch | Operation | Route request to a dispatcher |
x-barbacane-middlewares | Root or Operation | Apply 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
| Property | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Unique identifier for this upstream |
timeout | duration | No | Request timeout (default: 30s) |
retries | integer | No | Number 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
| Property | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Dispatcher plugin name |
config | object | No | Plugin-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"}'
| Config | Type | Default | Description |
|---|---|---|---|
status | integer | 200 | HTTP status code |
body | string | “” | 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
| Config | Type | Default | Description |
|---|---|---|---|
url | string | Required | Base URL of upstream (HTTPS required in production) |
path | string | Same as operation | Backend path (supports {param} substitution) |
timeout | number | 30.0 | Request 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 variablefile:///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
- Global middlewares (in order defined)
- Operation middlewares (in order defined)
- Dispatch
- 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:
- Client sends HTTP POST to the channel address
- Gateway validates the message against the schema
- Dispatcher publishes to Kafka/NATS
- 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 Action | HTTP Method |
|---|---|
send | POST |
receive | GET |
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
- Mark deprecated first: Set
deprecated: truebefore setting a sunset date - Give advance notice: Set the sunset date at least 6 months in advance
- Update API docs: Include migration instructions in the operation summary or description
- 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 Code | Meaning |
|---|---|
| E1010 | Routing conflict (same path+method in multiple specs) |
| E1020 | Missing x-barbacane-dispatch on operation |
| E1031 | Plaintext http:// upstream URL (use HTTPS or --allow-plaintext-upstream) |
Next Steps
- Dispatchers - All dispatcher types and options
- Middlewares - Available middleware plugins
- CLI Reference - Full command options
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
| Property | Type | Default | Description |
|---|---|---|---|
status | integer | 200 | HTTP status code |
body | string | "" | Response body |
headers | object | {} | Additional response headers |
content_type | string | "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
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
url | string | Yes | - | Base URL of the upstream (must be HTTPS in production) |
path | string | No | Same as operation path | Upstream path template with {param} substitution |
timeout | number | No | 30.0 | Request timeout in seconds |
tls | object | No | - | TLS configuration for mTLS (see below) |
TLS Configuration (mTLS)
For upstreams that require mutual TLS (client certificate authentication):
| Property | Type | Required | Description |
|---|---|---|---|
tls.client_cert | string | If mTLS | Path to PEM-encoded client certificate |
tls.client_key | string | If mTLS | Path to PEM-encoded client private key |
tls.ca | string | No | Path 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_certandclient_keymust be specified together - Certificate files must be in PEM format
- The
caoption 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:
| Status | Condition |
|---|---|
| 502 Bad Gateway | Connection failed or upstream returned invalid response |
| 503 Service Unavailable | Circuit breaker is open |
| 504 Gateway Timeout | Request exceeded configured timeout |
Security
- HTTPS required in production:
http://URLs are rejected by the compiler (E1031) - Development mode: Use
--allow-plaintext-upstreamflag to allowhttp://URLs - TLS: Uses rustls with system CA roots by default
- mTLS: Configure
tls.client_certandtls.client_keyfor mutual TLS authentication - Custom CA: Use
tls.cato 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
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
url | string | Yes | - | Lambda Function URL |
timeout | number | No | 30.0 | Request timeout in seconds |
pass_through_headers | boolean | No | true | Pass incoming headers to Lambda |
Setup
- Enable Lambda Function URLs in AWS Console or via CLI
- 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
| Status | Condition |
|---|---|
| 502 Bad Gateway | Lambda invocation failed or returned invalid response |
| 504 Gateway Timeout | Request 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
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
topic | string | Yes | - | Kafka topic to publish to |
key | string | No | - | Message key expression (see below) |
ack_response | object | No | - | Custom acknowledgment response |
include_metadata | boolean | No | false | Include partition/offset in response |
headers_from_request | array | No | [] | Request headers to forward as message headers |
Key Expression
The key property supports dynamic expressions:
| Expression | Description |
|---|---|
$request.header.X-Key | Extract key from request header |
$request.path.userId | Extract key from path parameter |
literal-value | Use 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
| Status | Condition |
|---|---|
| 502 Bad Gateway | Kafka 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
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
subject | string | Yes | - | NATS subject to publish to (supports wildcards) |
ack_response | object | No | - | Custom acknowledgment response |
headers_from_request | array | No | [] | 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
| Status | Condition |
|---|---|
| 502 Bad Gateway | NATS 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
| Property | Type | Default | Description |
|---|---|---|---|
secret | string | - | HS256 secret key |
public_key | string | - | RS256 public key (PEM format) |
issuer | string | - | Expected iss claim |
audience | string | - | Expected aud claim |
required_claims | array | [] | Claims that must be present |
leeway | integer | 0 | Seconds 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
| Property | Type | Default | Description |
|---|---|---|---|
key_location | string | header | Where to find key (header or query) |
header_name | string | X-API-Key | Header name (when key_location: header) |
query_param | string | api_key | Query param name (when key_location: query) |
keys | object | {} | Map of valid API keys to metadata |
Context Headers
Sets headers for downstream:
x-auth-key-id- Key identifierx-auth-key-name- Key human-readable namex-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
| Property | Type | Default | Description |
|---|---|---|---|
introspection_endpoint | string | required | RFC 7662 introspection URL |
client_id | string | required | Client ID for introspection auth |
client_secret | string | required | Client secret for introspection auth |
required_scopes | string | - | Space-separated required scopes |
timeout | float | 5.0 | Introspection request timeout (seconds) |
Context Headers
Sets headers for downstream:
x-auth-sub- Subjectx-auth-scope- Token scopesx-auth-client-id- Client IDx-auth-username- Username (if present)x-auth-claims- Full introspection response as JSON
Error Responses
401 Unauthorized- Missing token, invalid token, or inactive token403 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
| Property | Type | Default | Description |
|---|---|---|---|
quota | integer | required | Maximum requests allowed in the window |
window | integer | required | Window duration in seconds |
policy_name | string | default | Policy name for RateLimit-Policy header |
partition_key | string | client_ip | Rate limit key source |
Partition Key Sources
client_ip- Client IP fromX-Forwarded-FororX-Real-IPheader:<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 configurationX-RateLimit-Limit- Maximum requests in windowX-RateLimit-Remaining- Remaining requestsX-RateLimit-Reset- Unix timestamp when window resets
On rate-limited requests (429):
RateLimit-Policy- IETF draft headerRateLimit- IETF draft combined headerRetry-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
| Property | Type | Default | Description |
|---|---|---|---|
allowed_origins | array | [] | Allowed origins (["*"] for any, or specific origins) |
allowed_methods | array | ["GET", "POST"] | Allowed HTTP methods |
allowed_headers | array | [] | Allowed request headers (beyond simple headers) |
expose_headers | array | [] | Headers exposed to browser JavaScript |
max_age | integer | 3600 | Preflight cache time (seconds) |
allow_credentials | boolean | false | Allow credentials (cookies, auth headers) |
Origin Patterns
Origins can be:
- Exact match:
https://app.example.com - Wildcard subdomain:
*.example.com(matchessub.example.com) - Wildcard:
*(only whenallow_credentials: false)
Error Responses
403 Forbidden- Origin not in allowed list403 Forbidden- Method not allowed (preflight)403 Forbidden- Headers not allowed (preflight)
Preflight Responses
Returns 204 No Content with:
Access-Control-Allow-OriginAccess-Control-Allow-MethodsAccess-Control-Allow-HeadersAccess-Control-Max-AgeVary: 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
| Property | Type | Default | Description |
|---|---|---|---|
ttl | integer | 300 | Cache duration (seconds) |
vary | array | [] | Headers that vary cache key |
methods | array | ["GET", "HEAD"] | HTTP methods to cache |
cacheable_status | array | [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 cachedno-cache- Cache but revalidatemax-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
| Property | Type | Default | Description |
|---|---|---|---|
header | string | X-Request-ID | Header name |
generate_if_missing | boolean | true | Generate UUID if not present |
idempotency
Ensures idempotent processing.
x-barbacane-middlewares:
- name: idempotency
config:
header: Idempotency-Key
ttl: 86400
Configuration
| Property | Type | Default | Description |
|---|---|---|---|
header | string | Idempotency-Key | Header containing key |
ttl | integer | 86400 | Key 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:
- Gateway loads the artifact
- Gateway scans all dispatcher and middleware configs for secret references
- Each reference is resolved (env var read, file read)
- Resolved values replace the references in memory
- HTTP server starts listening
If any secret cannot be resolved, the gateway refuses to start.
Exit Codes
| Exit Code | Meaning |
|---|---|
| 0 | Normal shutdown |
| 1 | General error |
| 11 | Plugin hash mismatch |
| 13 | Secret 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
| Scheme | Example | Status |
|---|---|---|
env:// | env://API_KEY | Supported |
file:// | file:///etc/secrets/key | Supported |
vault:// | vault://secret/data/api-keys | Planned |
aws-sm:// | aws-sm://prod/api-key | Planned |
k8s:// | k8s://namespace/secret/key | Planned |
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:
- Update the secret value in your secret store
- 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
- Never commit secrets to Git - Use
.gitignorefor.envfiles - Rotate secrets regularly - Plan for secret rotation via gateway restarts
- Use least privilege - Only grant the gateway access to secrets it needs
- Audit secret access - Use your secret store’s audit logging
- 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:
| Level | Description |
|---|---|
error | Errors only |
warn | Warnings and errors |
info | Normal operation (default) |
debug | Detailed debugging |
trace | Very 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
| Metric | Type | Description |
|---|---|---|
barbacane_requests_total | counter | Total requests by method, path, status, api |
barbacane_request_duration_seconds | histogram | Request latency |
barbacane_request_size_bytes | histogram | Request body size |
barbacane_response_size_bytes | histogram | Response body size |
barbacane_active_connections | gauge | Current open connections |
barbacane_connections_total | counter | Total connections accepted |
barbacane_validation_failures_total | counter | Validation errors by reason |
barbacane_middleware_duration_seconds | histogram | Middleware execution time |
barbacane_dispatch_duration_seconds | histogram | Dispatcher execution time |
barbacane_wasm_execution_duration_seconds | histogram | WASM plugin execution time |
barbacane_slo_violation_total | counter | SLO 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
traceparentandtracestateheaders 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_codebarbacane.api,barbacane.operation_idbarbacane.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
| Option | Type | Default | Description |
|---|---|---|---|
trace_sampling | number | 1.0 | Sampling rate (0.0 = none, 1.0 = all) |
latency_slo_ms | integer | - | Latency threshold; emits barbacane_slo_violation_total when exceeded |
detailed_validation_logs | boolean | false | Include 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?
- CLI Reference - All command-line options
- Reserved Endpoints - Full metrics endpoint documentation
- Spec Extensions - Complete
x-barbacane-observabilityreference
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
.bcafiles 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
| Method | Endpoint | Description |
|---|---|---|
| POST | /specs | Upload a new spec (multipart) |
| GET | /specs | List all specs |
| GET | /specs/{id} | Get spec metadata |
| DELETE | /specs/{id} | Delete spec and revisions |
| GET | /specs/{id}/history | Get revision history |
| GET | /specs/{id}/content | Download spec content |
Query Parameters
type- Filter by spec type (openapiorasyncapi)name- Filter by name (case-insensitive partial match)revision- Specific revision (for/contentendpoint)
Plugins
| Method | Endpoint | Description |
|---|---|---|
| POST | /plugins | Register a plugin (multipart) |
| GET | /plugins | List 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}/download | Download 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
| Method | Endpoint | Description |
|---|---|---|
| GET | /artifacts | List all artifacts |
| GET | /artifacts/{id} | Get artifact metadata |
| DELETE | /artifacts/{id} | Delete an artifact |
| GET | /artifacts/{id}/download | Download .bca file |
Compilations
| Method | Endpoint | Description |
|---|---|---|
| POST | /specs/{id}/compile | Start async compilation |
| GET | /specs/{id}/compilations | List 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
| Status | Description |
|---|---|
pending | Job queued, waiting to start |
compiling | Compilation in progress |
succeeded | Completed, artifact_id available |
failed | Failed, 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
| URN | Status | Description |
|---|---|---|
urn:barbacane:error:not-found | 404 | Resource not found |
urn:barbacane:error:bad-request | 400 | Invalid request |
urn:barbacane:error:conflict | 409 | Resource already exists or is in use |
urn:barbacane:error:spec-invalid | 422 | Spec validation failed |
urn:barbacane:error:internal-error | 500 | Server 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 Schemasartifacts- Compiled.bcafiles with manifestsartifact_specs- Junction table linking artifacts to specscompilations- Async job trackingprojects- Project definitionsproject_plugin_configs- Plugin configurations per projectdata_planes- Connected gateway instancesapi_keys- Authentication keys for data planes
Migrations run automatically on startup with --migrate (enabled by default).
Configuration
Environment Variables
| Variable | Description |
|---|---|
DATABASE_URL | PostgreSQL connection string |
RUST_LOG | Log 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
- Database backups - Regular PostgreSQL backups for spec and plugin data
- Connection pooling - Consider PgBouncer for high-traffic deployments
- Authentication - Add a reverse proxy with authentication (not built-in)
- TLS - Terminate TLS at the load balancer or reverse proxy
What’s Next?
- CLI Reference - Full command-line options
- Artifact Format - Understanding
.bcafiles - Getting Started - Basic workflow with local compilation
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:
- Control Plane is running - Start with
make control-plane - Database is ready - Start PostgreSQL with
make db-up - Plugins are seeded - Run
make seed-pluginsto populate the plugin registry
Features Overview
| Feature | Description |
|---|---|
| Projects | Create and manage API gateway projects |
| Specs | Upload and manage OpenAPI/AsyncAPI specifications |
| Plugin Registry | Browse available plugins with schemas |
| Plugin Configuration | Configure plugins per project with validation |
| Builds | Compile specs into deployable artifacts |
| Deploy | Deploy artifacts to connected data planes |
| API Keys | Manage 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
- Navigate to Projects from the sidebar
- Click New Project
- Enter a name and optional description
- 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:
| Tab | Description |
|---|---|
| Specs | Manage API specifications for this project |
| Plugins | Configure which plugins to use and their settings |
| Builds | View compilation history and trigger new builds |
| Deploy | Deploy artifacts and manage connected data planes |
| Settings | Project settings and danger zone |
Specs Management
Uploading Specs
- Navigate to a project’s Specs tab
- Click Upload Spec
- Select an OpenAPI or AsyncAPI YAML/JSON file
- 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
| Type | Description |
|---|---|
| Middleware | Request/response processing (auth, rate limiting, CORS) |
| Dispatcher | Backend 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
- Click Add Plugin
- Select a plugin from the registry dropdown
- The plugin’s JSON Schema (if available) generates a configuration form
- Fill in required and optional fields
- 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
- Add the
rate-limitplugin - Configure:
quota: Maximum requests per window (e.g.,1000)window: Time window in seconds (e.g.,60)
- Save the configuration
Example: Configuring CORS
- Add the
corsplugin - 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
- Save the configuration
Builds
Compile your specs and plugins into deployable .bca artifacts.
Triggering a Build
- Navigate to a project’s Builds tab
- Click Build
- Watch the compilation progress
- Download the artifact when complete
Build Status
| Status | Description |
|---|---|
| Pending | Build queued |
| Compiling | Compilation in progress |
| Succeeded | Artifact ready for download/deploy |
| Failed | Check 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:
| Status | Description |
|---|---|
| Online | Connected and receiving updates |
| Deploying | Currently loading new artifact |
| Offline | Not connected |
Creating API Keys
- Navigate to a project’s Deploy tab
- Click Create Key in the API Keys section
- Enter a descriptive name
- Copy the key immediately - it’s only shown once
Deploying an Artifact
- Ensure at least one data plane is connected
- Click Deploy Latest
- The control plane notifies all connected data planes
- Data planes download, verify, and hot-reload the artifact
Project Templates
Create new projects from templates using the Init page:
Available Templates
| Template | Description |
|---|---|
| Basic | Minimal OpenAPI spec with health endpoint |
| Auth | Includes JWT authentication middleware |
| Full | Complete example with auth, rate limiting, and CORS |
Using Templates
- Click From Template on the Projects page
- Enter project name and select a template
- Preview the generated files
- Choose Setup in Control Plane to create project and upload spec
- 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
.bcafile 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
| Shortcut | Action |
|---|---|
Ctrl/Cmd + K | Quick search |
Esc | Close dialogs |
Troubleshooting
UI won’t load
- Check that the control plane is running on port 9090
- Verify the UI dev server is running on port 5173
- Check browser console for errors
Plugin configuration not saving
- Verify the configuration matches the plugin’s JSON Schema
- Check for required fields that are empty
- Look for validation errors in the form
Data plane not appearing
- Verify the data plane is started with correct flags
- Check the API key is valid and not revoked
- Ensure the project ID matches
- Check WebSocket connection in data plane logs
Build fails with “plugin not found”
- Run
make seed-pluginsto populate the registry - Verify the plugin name in your spec matches the registry
- Check the plugin version exists
Next Steps
- Control Plane API - Full REST API reference
- CLI Reference - Command-line options
- Plugin Development - Create custom plugins
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
| Command | Description |
|---|---|
init | Initialize a new Barbacane project |
compile | Compile OpenAPI spec(s) into a .bca artifact |
validate | Validate spec(s) without compiling |
serve | Run the gateway server |
barbacane init
Initialize a new Barbacane project with manifest, spec, and directory structure.
barbacane init [NAME] [OPTIONS]
Arguments
| Argument | Required | Default | Description |
|---|---|---|---|
NAME | No | . | Project name (creates a directory with this name, or initializes in current directory if .) |
Options
| Option | Required | Default | Description |
|---|---|---|---|
--template, -t | No | basic | Template to use: basic (full example) or minimal (bare bones) |
--fetch-plugins | No | false | Download 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
/healthand/usersendpoints - Example
x-barbacane-dispatchconfigurations - Ready to compile and run
minimal:
- Bare-bones OpenAPI spec with just the required structure
- Single
/healthendpoint 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
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Directory 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
| Option | Required | Default | Description |
|---|---|---|---|
--spec, -s | Yes | - | One or more spec files (YAML or JSON) |
--output, -o | Yes | - | Output artifact path |
--manifest, -m | No | - | Path to barbacane.yaml manifest (required for plugin bundling) |
--allow-plaintext | No | false | Allow 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
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Compilation error (validation failed, routing conflict, undeclared plugin) |
| 2 | Manifest or plugin resolution error |
barbacane validate
Validate specs without full compilation. Checks for spec validity and extension errors.
barbacane validate --spec <FILES>... [OPTIONS]
Options
| Option | Required | Default | Description |
|---|---|---|---|
--spec, -s | Yes | - | One or more spec files to validate |
--format | No | text | Output format: text or json |
Error Codes
| Code | Category | Description |
|---|---|---|
| E1001 | Spec validity | Not a valid OpenAPI 3.x or AsyncAPI 3.x |
| E1002 | Spec validity | YAML/JSON parse error |
| E1003 | Spec validity | Unresolved $ref reference |
| E1004 | Spec validity | Schema validation error (missing info, etc.) |
| E1010 | Extension | Routing conflict (same path+method in multiple specs) |
| E1011 | Extension | Middleware entry missing name |
| E1015 | Extension | Unknown x-barbacane-* extension (warning) |
| E1020 | Extension | Operation missing x-barbacane-dispatch (warning) |
| E1031 | Extension | Plaintext HTTP URL not allowed (use --allow-plaintext to override) |
| E1040 | Manifest | Plugin 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
| Code | Meaning |
|---|---|
| 0 | All specs valid |
| 1 | One or more specs have errors |
barbacane serve
Run the gateway server, loading routes from a compiled artifact.
barbacane serve --artifact <PATH> [OPTIONS]
Options
| Option | Required | Default | Description |
|---|---|---|---|
--artifact | Yes | - | Path to the .bca artifact file |
--listen | No | 0.0.0.0:8080 | Listen address (ip:port) |
--dev | No | false | Enable development mode |
--log-level | No | info | Log level (trace, debug, info, warn, error) |
--log-format | No | json | Log format (json or pretty) |
--otlp-endpoint | No | - | OpenTelemetry endpoint for trace export (e.g., http://localhost:4317) |
--max-body-size | No | 1048576 | Maximum request body size in bytes (1MB) |
--max-headers | No | 100 | Maximum number of request headers |
--max-header-size | No | 8192 | Maximum size of a single header in bytes (8KB) |
--max-uri-length | No | 8192 | Maximum URI length in characters (8KB) |
--allow-plaintext-upstream | No | false | Allow http:// upstream URLs (dev only) |
--tls-cert | No | - | Path to TLS certificate file (PEM format) |
--tls-key | No | - | Path to TLS private key file (PEM format) |
--tls-min-version | No | 1.2 | Minimum TLS version (1.2 or 1.3) |
--keepalive-timeout | No | 60 | HTTP keep-alive idle timeout in seconds |
--shutdown-timeout | No | 30 | Graceful 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-certand--tls-keymust 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
errorsarray - 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:
| Limit | Default | Description |
|---|---|---|
| Body size | 1 MB | Requests with larger bodies are rejected with 400 |
| Header count | 100 | Requests with more headers are rejected with 400 |
| Header size | 8 KB | Individual headers larger than this are rejected |
| URI length | 8 KB | URIs 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:
- Stop accepting new connections immediately
- Drain in-flight requests for up to
--shutdown-timeoutseconds (default: 30) - Force close any remaining connections after timeout
- 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:
| Header | Description |
|---|---|
Server | barbacane/<version> (e.g., barbacane/0.1.0) |
X-Request-Id | Request ID - propagates incoming header or generates UUID v4 |
X-Trace-Id | Trace ID - extracted from traceparent header or generated |
X-Content-Type-Options | nosniff - prevents MIME sniffing attacks |
X-Frame-Options | DENY - 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:
| Header | Description |
|---|---|
Deprecation | true - indicates the endpoint is deprecated (per draft-ietf-httpapi-deprecation-header) |
Sunset | HTTP-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
| Code | Meaning |
|---|---|
| 0 | Clean shutdown |
| 1 | Startup error (artifact not found, bind failed) |
| 11 | Plugin hash mismatch (artifact tampering detected) |
| 13 | Secret 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
| Variable | Description |
|---|---|
RUST_LOG | Override log level (e.g., RUST_LOG=debug) |
OTEL_EXPORTER_OTLP_ENDPOINT | Alternative 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, statusbarbacane_request_duration_seconds- Request latency histogrambarbacane_active_connections- Current connection countbarbacane_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:
| Scheme | Example | Description |
|---|---|---|
env:// | env://API_KEY | Read from environment variable |
file:// | file:///etc/secrets/key | Read 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
| Command | Description |
|---|---|
compile | Compile spec(s) into a .bca artifact (local) |
validate | Validate spec(s) without compiling |
serve | Start the control plane REST API server |
seed-plugins | Seed 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
| Option | Required | Default | Description |
|---|---|---|---|
--plugins-dir | No | plugins | Path to the plugins directory |
--database-url | Yes | - | PostgreSQL connection URL |
--skip-existing | No | true | Skip plugins that already exist in the registry |
--verbose | No | false | Show 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
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Error (database connection, invalid manifest, etc.) |
barbacane-control serve
Start the control plane HTTP server with PostgreSQL backend.
barbacane-control serve [OPTIONS]
Options
| Option | Required | Default | Description |
|---|---|---|---|
--listen | No | 127.0.0.1:9090 | Listen address (ip:port) |
--database-url | Yes | - | PostgreSQL connection URL |
--migrate | No | true | Run 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:
| Endpoint | Description |
|---|---|
| System | |
GET /health | Health check |
GET /api/docs | Interactive API documentation (Scalar) |
| Specs | |
POST /specs | Upload spec (multipart) |
GET /specs | List specs |
GET /specs/{id} | Get spec metadata |
DELETE /specs/{id} | Delete spec |
GET /specs/{id}/history | Revision history |
GET /specs/{id}/content | Download spec content |
POST /specs/{id}/compile | Start async compilation |
GET /compilations/{id} | Poll compilation status |
| Plugins | |
POST /plugins | Register plugin (multipart) |
GET /plugins | List plugins |
GET /plugins/{name}/{version} | Get plugin metadata |
DELETE /plugins/{name}/{version} | Delete plugin |
GET /plugins/{name}/{version}/download | Download WASM binary |
| Artifacts | |
GET /artifacts | List artifacts |
GET /artifacts/{id} | Get artifact metadata |
GET /artifacts/{id}/download | Download .bca file |
| Projects | |
POST /projects | Create a new project |
GET /projects | List all projects |
GET /projects/{id} | Get project details |
PUT /projects/{id} | Update project |
DELETE /projects/{id} | Delete project |
GET /projects/{id}/plugins | List plugins configured for project |
POST /projects/{id}/plugins | Add plugin to project |
PUT /projects/{id}/plugins/{name} | Update plugin config |
DELETE /projects/{id}/plugins/{name} | Remove plugin from project |
POST /projects/{id}/deploy | Deploy artifact to connected data planes |
| Data Planes | |
GET /projects/{id}/data-planes | List connected data planes |
GET /data-planes/{id} | Get data plane status |
| API Keys | |
POST /projects/{id}/api-keys | Create API key for data plane auth |
GET /projects/{id}/api-keys | List 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
| Extension | Location | Required | Purpose |
|---|---|---|---|
x-barbacane-upstream | Server | No | Define backend connection |
x-barbacane-dispatch | Operation | Yes | Route to dispatcher |
x-barbacane-middlewares | Root / Operation | No | Apply middleware chain |
x-barbacane-observability | Root / Operation | No | Configure 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
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | - | Unique identifier for this upstream |
timeout | duration | No | 30s | Request timeout |
retries | integer | No | 0 | Number of retry attempts |
Duration Format
Durations support:
5s- seconds100ms- milliseconds1m- minutes1h- 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
| Property | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Name of the dispatcher (e.g., mock, http) |
config | object | No | Configuration 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.
| Scheme | Example | Description |
|---|---|---|
env:// | env://API_KEY | Read from environment variable |
file:// | file:///etc/secrets/key | Read 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
| Property | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Name of the middleware plugin |
config | object | No | Configuration 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 statusRetry-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 cacheMISS: 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
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
trace_sampling | number | No | 1.0 | Trace sampling rate (0.0 = none, 1.0 = all) |
detailed_validation_logs | boolean | No | false | Include validation error details in logs |
latency_slo_ms | integer | No | - | 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
| Code | Message | Cause |
|---|---|---|
| E1010 | Routing conflict | Same path+method in multiple specs |
| E1020 | Missing dispatch | Operation 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
| Field | Type | Description |
|---|---|---|
barbacane_artifact_version | integer | Format version (currently 1) |
compiled_at | string | ISO 8601 timestamp of compilation |
compiler_version | string | Version of barbacane compiler |
source_specs | array | List of source specifications |
bundled_plugins | array | List of bundled WASM plugins (optional) |
routes_count | integer | Number of compiled routes |
checksums | object | SHA-256 checksums for integrity |
source_specs entry
| Field | Type | Description |
|---|---|---|
file | string | Original filename |
sha256 | string | Hash of source content |
type | string | Spec type (openapi or asyncapi) |
version | string | Spec version (e.g., 3.1.0) |
bundled_plugins entry
| Field | Type | Description |
|---|---|---|
name | string | Plugin name (kebab-case) |
version | string | Plugin version (semver) |
plugin_type | string | Plugin type (middleware or dispatcher) |
wasm_path | string | Path to WASM file within artifact |
sha256 | string | SHA-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
| Field | Type | Description |
|---|---|---|
index | integer | Unique operation index |
path | string | OpenAPI path template |
method | string | HTTP method (uppercase) |
operation_id | string | Operation ID (optional) |
dispatch | object | Dispatcher configuration |
specs/
Directory containing the original source specifications. These are embedded for:
- Serving via
/__barbacane/openapiendpoint - Documentation and debugging
- Audit trail
Files retain their original names.
Version History
| Version | Changes |
|---|---|
| 1 | Initial 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
| Field | Type | Description |
|---|---|---|
status | string | Always "healthy" if responding |
artifact_version | integer | .bca format version |
compiler_version | string | barbacane version that compiled the artifact |
routes_count | integer | Number 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
| Metric | Type | Labels | Description |
|---|---|---|---|
barbacane_requests_total | counter | method, path, status, api | Total requests processed |
barbacane_request_duration_seconds | histogram | method, path, status, api | Request latency |
barbacane_request_size_bytes | histogram | method, path, status, api | Request body size |
barbacane_response_size_bytes | histogram | method, path, status, api | Response body size |
barbacane_active_connections | gauge | - | Current open connections |
barbacane_connections_total | counter | - | Total connections accepted |
barbacane_validation_failures_total | counter | method, path, reason | Validation errors |
barbacane_middleware_duration_seconds | histogram | middleware, phase | Middleware execution time |
barbacane_dispatch_duration_seconds | histogram | dispatcher, upstream | Dispatcher execution time |
barbacane_wasm_execution_duration_seconds | histogram | plugin, function | WASM 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:
| Endpoint | Purpose |
|---|---|
/__barbacane/ready | Readiness probe (after warm-up) |
/__barbacane/config | Runtime configuration |
/__barbacane/routes | Route table inspection |
Security Considerations
Reserved endpoints are public by default. In production, consider:
- Network segmentation: Only expose port 8080 to your load balancer
- Firewall rules: Block
/__barbacane/*from public access - 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 metadataOperation- Single API operation with dispatch/middleware configDispatchConfig- Dispatcher name and configurationMiddlewareConfig- Middleware name and configurationChannel- 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 trieRouteEntry- Points to compiled operation indexRouteMatch- 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
.bcaarchive
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 artifactvalidate- Validate specs without compilationserve- Run the gateway
barbacane (serve)
Data plane binary - the actual gateway.
Startup flow:
- Load artifact from disk
- Load compiled routes from artifact
- Load bundled plugins from artifact
- Compile WASM modules (AOT)
- Resolve secrets - scan configs for
env://andfile://references - Create plugin instance pool with resolved secrets
- Start HTTP server
If any secret cannot be resolved in step 5, the gateway exits with code 13.
Request flow:
- Receive HTTP request
- Check reserved endpoints (
/__barbacane/*) - Route lookup in trie
- Apply middleware chain
- Dispatch to handler
- Apply response middlewares
- Send response
barbacane-wasm
WASM plugin runtime built on wasmtime.
Key types:
WasmEngine- Configured wasmtime engine with AOT compilationInstancePool- Instance pooling per (plugin_name, config_hash)PluginInstance- Single WASM instance with host function bindingsMiddlewareChain- Ordered middleware execution
Host functions:
host_set_output- Plugin writes result to host bufferhost_log- Structured logging with trace contexthost_context_get/set- Per-request key-value storehost_clock_now- Monotonic time in millisecondshost_http_call- Make outbound HTTP requestshost_http_read_result- Read HTTP response datahost_get_secret- Get a resolved secret by referencehost_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,Actiontypes#[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 configon_request(ptr, len) -> i32- Process request (0=continue, 1=short-circuit)on_response(ptr, len) -> i32- Process responsedispatch(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/openapialways 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
| Target | Description |
|---|---|
| Build & Test | |
make | Run check + test (default) |
make test | Run all workspace tests |
make test-verbose | Run tests with output |
make test-one TEST=name | Run specific test |
make clippy | Run clippy lints |
make fmt | Format all code |
make check | Run fmt-check + clippy |
make build | Build debug |
make release | Build release |
make plugins | Build all WASM plugins |
make seed-plugins | Build plugins and seed registry |
make clean | Clean all build artifacts |
| Development | |
make control-plane | Start control plane server (port 9090) |
make ui | Start UI dev server (port 5173) |
make dev | Show instructions to start both |
make dev-tmux | Start both in tmux session |
| Database | |
make db-up | Start PostgreSQL container |
make db-down | Stop PostgreSQL container |
make db-reset | Reset 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
-
Create a branch
git checkout -b feature/my-feature -
Make changes and test
cargo test --workspace -
Format code
cargo fmt --all -
Check lints
cargo clippy --workspace -- -D warnings -
Commit
git commit -m "feat: add my feature"
Commit Messages
Follow Conventional Commits:
feat:- New featurefix:- Bug fixdocs:- Documentationrefactor:- Code refactoringtest:- Adding testschore:- 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
-
Create the crate directory:
mkdir -p crates/barbacane-mycrate/src -
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 } -
Add to workspace in root
Cargo.toml:[workspace] members = [ # ...existing crates... "crates/barbacane-mycrate", ] [workspace.dependencies] barbacane-mycrate = { path = "crates/barbacane-mycrate" } -
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
-
Create page component in
src/pages/:// src/pages/my-feature.tsx export function MyFeaturePage() { return <div>...</div> } -
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 casesrouter_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 timepath_param_validation- Validates path parameters against schemasquery_param_validation- Validates query parametersbody_validation- Validates JSON request bodiesfull_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
- Update version in workspace
Cargo.toml - Update CHANGELOG.md
- Create git tag:
git tag v0.1.0 - Push:
git push origin main --tags - 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:
| Type | Purpose | Exports |
|---|---|---|
| Middleware | Process requests/responses in a chain | init, on_request, on_response |
| Dispatcher | Handle requests and generate responses | init, dispatch |
Prerequisites
- Rust stable with
wasm32-unknown-unknowntarget barbacane-plugin-sdkcrate
# 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:
| Plugin | Type | Description |
|---|---|---|
mock | Dispatcher | Return static responses |
http-upstream | Dispatcher | Reverse proxy to HTTP backends |
lambda | Dispatcher | Invoke AWS Lambda functions |
jwt-auth | Middleware | JWT token validation |
apikey-auth | Middleware | API key authentication |
oauth2-auth | Middleware | OAuth2 token introspection |
rate-limit | Middleware | Sliding window rate limiting |
cache | Middleware | Response caching |
cors | Middleware | CORS header management |
Use these as references for your own plugins.
Best Practices
- Keep plugins focused - One plugin, one responsibility
- Validate configuration - Use JSON Schema to catch config errors at compile time
- Handle errors gracefully - Return appropriate error responses, don’t panic
- Document capabilities - Only declare host functions you actually use
- Test thoroughly - Unit test logic, integration test with the gateway
- Use semantic versioning - Follow semver for plugin versions
Resource Limits
Plugins run in a sandboxed WASM environment with these limits:
| Resource | Limit |
|---|---|
| Linear memory | 16 MB |
| Stack size | 1 MB |
| Execution time | 100 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.