Octopus
1.x
Docs/Octopus/Middleware
Open

Reading4 min
Updated31 Jul 2026
Sourcev1/concepts/middleware.mdx

Middleware

Middleware processes requests before they reach upstreams and responses before they return to clients.

Overview01

Middleware in Octopus is Rust code that wraps the request/response path. Each middleware runs in registration order on the way in and reverse order on the way out:

Request → M1 → M2 → M3 → Upstream → M3 → M2 → M1 → Response
Warning

There is no middleware: configuration array. The global chain is assembled in code (crates/octopus-runtime/src/server.rs) and contains at most two entries: compression (when gateway.compression.enabled, the default) and the auth gateway (when auth providers are configured or auth.global_enforce is on). Compression is registered first, so it is the outermost wrapper and compresses the response on the way out. The octopus-middleware crate ships many more middleware (CORS, rate limiting, caching, security headers, WAF, …), but they are builder-only — not wired to gateway config. Per-route rate_limit and cors are parsed and stored but not enforced in the live chain. See Middleware reference for the full catalogue and wiring status.

How Middleware Works02

Execution Order

The chain is built in code, not from config. The live order is:

Request
  → [Compression]        (if gateway.compression.enabled)
    → [Auth gateway]     (if auth_providers non-empty OR auth.global_enforce)
      → Route match → Upstream proxy
    ← Auth gateway (pass-through on the way out)
  ← Compression (compresses the response body)
Response

Each middleware is configured through its own config block (gateway.compression and auth / auth_providers), not through a middleware: list.

Short-Circuiting

Middleware can stop the chain early — for example, the auth gateway returns 401/403 without proxying:

Request → Auth gateway (401/403) ──┐

                                  Response

Built-in Middleware03

Note

Of the middleware below, only authentication (via the auth gateway and auth_providers) and compression (via gateway.compression) run in the live chain today. Rate limiting and CORS are implemented but builder-only — their config is parsed but not enforced at request time. The YAML examples here are illustrative; see the linked reference pages for the exact, source-verified schema.

Authentication

middleware:
  - auth

auth:
  type: jwt
  secret: ${JWT_SECRET}
  algorithm: HS256
  header: Authorization
  scheme: Bearer
  excluded_paths:
    - "/api/auth/login"
    - "/_/health"

See Authentication Middleware for details.

Rate Limiting

middleware:
  - rate_limit

rate_limit:
  strategy: token-bucket
  requests_per_second: 100
  burst: 200
  key_by: ip  # or: user_id, api_key, header

See Rate Limiting Middleware for details.

CORS

middleware:
  - cors

cors:
  allowed_origins: ["https://example.com"]
  allowed_methods: [GET, POST, PUT, DELETE]
  allowed_headers: ["Content-Type", "Authorization"]
  exposed_headers: ["X-Request-ID"]
  allow_credentials: true
  max_age: 3600

See CORS Middleware for details.

Compression

middleware:
  - compression

compression:
  enabled: true
  level: 6
  min_size: 1024
  types:
    - "application/json"
    - "text/html"

See Compression Middleware for details.

Custom Middleware04

Create custom middleware via plugins:

use octopus_middleware::prelude::*;

pub struct CustomMiddleware;

#[async_trait]
impl Middleware for CustomMiddleware {
    async fn call(
        &self,
        mut req: Request<Body>,
        next: Next,
    ) -> Result<Response<Body>> {
        // Modify request
        req.headers_mut()
            .insert("X-Custom-Header", "value".parse()?);
        
        // Continue to next middleware
        let mut resp = next.run(req).await?;
        
        // Modify response
        resp.headers_mut()
            .insert("X-Processed-By", "octopus".parse()?);
        
        Ok(resp)
    }
}

See Writing a Plugin for details.

Request Context05

Middleware can access and modify request context:

// Set context value
req.extensions_mut().insert(UserId("123".to_string()));

// Read context value
let user_id = req.extensions().get::<UserId>();

Next Steps06

Learn about specific middleware: