vow-web-server
vow-web-server v0.3.0 is an Express-like HTTP framework for Vow. Handlers are fn(Request) -> Response; vws.serve(app, rt, port) validates grants before listen.
| Layer | Location | Role |
|---|---|---|
| Runtime | lang/runtime.c |
http_accept_once, HTTP/1.1, keep-alive, chunked (1MB+), timeouts |
| Stdlib | lang/stdlib/http.vow |
Query/path helpers, typed replies |
| Framework | vow-frameworks/vow-web-server/ |
Server, router, middleware, serve loop |
| Examples | vow-examples/vow-web-server/ |
Monorepo demos + packaged projects |
Scaffold a new API
Section titled “Scaffold a new API”vow create my-api --webcd my-apivpm installvow run src/main.vowcurl http://127.0.0.1:8787/healthvow new my-api --web is equivalent. The template adds vow-web-server@0.3.0, /health + /hello routes, and a grants.toml (auto-loaded on run).
Install (vpm)
Section titled “Install (vpm)”curl -fsSL https://install.vowlang.dev | shvpm init my-api && cd my-apivpm add vow-web-server@0.3.0vpm installExpress → vow-web-server
Section titled “Express → vow-web-server”Express
const express = require('express');const app = express();app.use(express.json());app.get('/health', (req, res) => res.json({ ok: true }));app.listen(8787);vow-web-server
import vws from vow_web_serverimport vow_web_server.requestimport vow_web_server.response
fn health(_req: request.Request) -> response.Response { return vws.json("{\"ok\":true}");}
fn main(caps: Caps) -> int { let rt = vws.runtime(caps); var app = vws.server(); app = vws.use_middleware(app, vws.logger()); app = vws.get(app, "/health", health); return vws.serve(app, rt, 8787);}vow run src/main.vow -- --grant net:curl http://127.0.0.1:8787/healthReassign the handle after each registration step — get, post, and use_middleware all return an updated server or router handle.
Async I/O from sync handlers
Section titled “Async I/O from sync handlers”Route handlers are fn(Request) -> Response. For database or file I/O without blocking the whole process on worker threads manually, use async fn + await + block_on:
async fn list_rows() -> String { return await db_query(g_handle, "SELECT id, title FROM todos")?;}
fn list_todos(_req: request.Request) -> response.Response { let rows = block_on(list_rows); return vws.json("{\"todos\":" + rows + "}");}See Async / await and the hello-app demo (Postgres + static UI).
Express mapping (v0.3)
Section titled “Express mapping (v0.3)”| Express | vow-web-server |
|---|---|
express() |
server() |
express.Router() |
router() |
app.use(mw) |
use_middleware(app, mw) |
app.use('/api', router) |
use_middleware(app, "/api", router) |
express.json() |
json() |
express.urlencoded() |
urlencoded() |
cors({ origin }) |
cors(origin) |
app.get/post/… |
get(app, path, h) — reassign app = … |
Custom (req, res, next) |
middleware(fn) + next(req) / halt(resp) |
app.listen(port) |
serve(app, rt, port) |
Legacy v0.2 app() / use_log / mount still works — see Legacy API below.
Monorepo quickstart
Section titled “Monorepo quickstart”./vow run vow-examples/vow-web-server/http_api.vow -- --grant net:curl http://127.0.0.1:8787/healthcurl http://127.0.0.1:8787/helloImport styles:
| Style | When |
|---|---|
import vws from vow_web_server |
After vpm install |
import lib.handle / lib.serve |
Monorepo / framework dev |
Static files are not re-exported from the barrel — import vow_web_server.staticfiles or lib.staticfiles separately.
Architecture
Section titled “Architecture”flowchart LR Client --> Accept["serve / http_accept_once"] Accept --> App["app.handle"] App --> MW["middleware.run_chain"] MW --> Router["router.dispatch"] Router --> Handler["fn(Request) -> Response"] Handler --> Deliver["response.deliver"]serve(app, rt, port)— blocking accept loop (one connection at a time).handle(app, raw)— parse raw request line, run middleware, dispatch router, deliver response.try_handle(app, raw)— same pipeline without I/O; returns HTTP status only (unit tests).
Legacy v0.2 API
Section titled “Legacy v0.2 API”Immutable builder — each call returns a new App:
let a = vws.get(vws.use_log(vws.app()), "/health", health);return vws.serve(a, rt, 8787);| v0.3 | v0.2 legacy |
|---|---|
server() |
app() |
use_middleware(a, logger()) |
use_log(a) |
use_middleware(a, json()) |
use_json(a) |
use_middleware(a, prefix, router) |
mount(a, prefix, sub) |
Documentation
Section titled “Documentation”| Topic | Page |
|---|---|
| Methods, params, mount, 404/405 | Routing |
| Request / Response API | Request & response |
| Middleware pipeline | Middleware |
| Static files | Static files |
| Net grants & deployment | Net grants |
| Unit + e2e tests | Testing |
| Tier-1 stack walkthrough | Integration |
| Async & future work | Roadmap |
Tutorials
Section titled “Tutorials”- HTTP CRUD — JSON POST body + in-memory store
- HTTP mounting — sub-router under
/api/v1 - HTTP middleware — CORS + path-scoped auth
- HTTP packaged —
vpm install+ barrel import - HTTP API (intro) — first health/hello API
Examples index
Section titled “Examples index”| File | Demonstrates |
|---|---|
vow-examples/vow-web-server/http_api.vow |
v0.3 server + logger + routes |
vow-examples/vow-web-server/json_crud.vow |
POST body + JSON CRUD |
vow-examples/vow-web-server/middleware_chain.vow |
CORS + path-scoped auth |
vow-examples/vow-web-server/mounted_api.vow |
Mount + :id params |
vow-examples/vow-web-server/static_site.vow |
Static file serving |
vow-examples/vow-web-server/file_upload.vow |
Multipart upload |
vow-examples/vow-web-server/integration_rest/ |
body-parser, cors, rbac, postgres |
vow-examples/vow-web-server/http_api_packaged/ |
Packaged import vws from vow_web_server |