Middleware
Middleware runs before route dispatch. Each slot can halt the chain and return a response immediately (e.g. 401 unauthorized).
Registration (v0.3)
Section titled “Registration (v0.3)”| Function | Scope |
|---|---|
use_middleware(app, mw) |
All paths on server or router |
use_middleware(app, prefix, router) |
Mount sub-router (with its middleware) under prefix |
Middleware factories return a Middleware value:
| Factory | Express equivalent |
|---|---|
logger() |
access logger / morgan |
json() |
express.json() |
urlencoded() |
express.urlencoded() |
cors(origin) |
cors({ origin }) |
middleware(fn) |
custom (req, res, next) |
Express → vow-web-server
Section titled “Express → vow-web-server”Express
const app = express();app.use(express.json());app.use('/api', requireAuth);app.get('/api/secret', (req, res) => res.json({ secret: true }));vow-web-server
import vws from vow_web_serverimport vow_web_server.requestimport vow_web_server.responseimport vow_web_server.middleware
fn require_auth(req: request.Request) -> middleware.MwResult { if len(vws.header(req, "Authorization")) == 0 { return vws.halt(vws.json(401, "{\"error\":\"unauthorized\"}")); } return vws.next(req);}
fn secret(_req: request.Request) -> response.Response { return vws.json("{\"secret\":true}");}
fn main(caps: Caps) -> int { let rt = vws.runtime(caps); var app = vws.server(); app = vws.use_middleware(app, vws.cors("*"));
var api = vws.router(); api = vws.use_middleware(api, vws.middleware(require_auth)); api = vws.get(api, "/secret", secret); app = vws.use_middleware(app, "/api", api);
return vws.serve(app, rt, 8787);}See vow-examples/vow-web-server/middleware_chain.vow and the HTTP middleware tutorial.
Grant middleware (tier 2)
Section titled “Grant middleware (tier 2)”Separate from auth/json middleware — declares capability requirements for path prefixes. See Net grants.
| Function | Scope |
|---|---|
use_grant(app, kind) |
All paths (v0.3 handle API) |
use_grant_at(a, prefix, kind) |
Paths under prefix (legacy app()) |
use_grant_at_scope(a, prefix, kind, scope) |
Path prefix + attenuation hint (legacy) |
var app = vws.server();app = vws.use_grant(app, vws.kind_fs_read());Built-in factories
Section titled “Built-in factories”| Factory | Behavior |
|---|---|
logger() |
Prints METHOD path access log |
json() |
Parses JSON body into context_value (max 64 KiB) |
urlencoded() |
Reads application/x-www-form-urlencoded into context |
cors(origin) |
CORS headers + OPTIONS preflight |
Legacy enum kinds (kind_logger(), use_log(a), etc.) remain on the v0.2 app() builder.
Auth via custom middleware
Section titled “Auth via custom middleware”Built-in auth header checking is available via legacy use_auth(a) or a custom function:
Express
function requireAuth(req, res, next) { if (!req.headers.authorization) return res.status(401).json({ error: 'unauthorized' }); next();}vow-web-server
fn require_auth(req: request.Request) -> middleware.MwResult { if len(vws.header(req, "Authorization")) == 0 { return vws.halt(vws.json(401, "{\"error\":\"unauthorized\"}")); } return vws.next(req);}
var api = vws.router();api = vws.use_middleware(api, vws.middleware(require_auth));api = vws.get(api, "/x", health);app = vws.use_middleware(app, "/api", api);Unit tests:
assert vws.try_handle(app, "GET /api/x") == 401;assert vws.try_handle(app, "GET /other") == 404; // no auth on /otherJSON body
Section titled “JSON body”When Content-Type contains application/json, json() reads and validates JSON, then stores the raw JSON string on the request via with_context. Handlers read it with context_value(req).
Invalid JSON → 400. Body too large → 413.
Express
app.use(express.json());app.post('/items', (req, res) => { /* req.body */ });vow-web-server
var api = vws.router();api = vws.use_middleware(api, vws.json());api = vws.post(api, "/items", create_item);app = vws.use_middleware(app, "/api", api);// handler: let body = vws.context_value(req);Pipeline order
Section titled “Pipeline order”Slots run in registration order on the matched path prefix. Halting stops the chain:
var app = vws.server();app = vws.use_middleware(app, vws.logger());app = vws.use_middleware(app, vws.middleware(require_auth));app = vws.get(app, "/health", health);// Logger runs, then auth halts with 401 before the route.Legacy v0.2 API
Section titled “Legacy v0.2 API”Immutable app() builder with enum kinds:
| v0.3 | v0.2 legacy |
|---|---|
use_middleware(a, logger()) |
use_log(a) |
use_middleware(a, json()) |
use_json(a) |
use_middleware(a, urlencoded()) |
use_urlencoded(a) |
use_middleware(a, cors("*")) |
use_cors(a, "*") |
use_middleware(a, prefix, router) |
mount(a, prefix, sub) + use_at |
try_handle
Section titled “try_handle”try_handle(app, raw) runs the full middleware + router pipeline without delivering HTTP I/O. Returns the HTTP status code:
assert vws.try_handle(app, "GET /health") == 200;assert vws.try_handle(app, "GET /api/x") == 401;Raw format: "METHOD /path" optionally with query (GET /items?q=1). See Testing for testutil helpers.