ahiru
availableHTTP • WebSocket • Migrations • Auth
Framework
Overview
ahiru is the backend framework for Niao. You define routes as regular functions, attach middleware, and start an HTTP or WebSocket server. Handlers compile to bytecode like any other Niao code; the networking stack itself is native (Tokio + Axum), so you're not paying for a slow interpreter on the hot path.
There's a CLI for scaffolding new services, routes, config, migration folders, the usual layout, so you don't reinvent project structure every time. It works with the Postgres, SQLite, and Mongo drivers if you need persistence.
- Bytecode route handlers
- Project scaffolding CLI
- SQL migrations
- /health and /ready probes
Import
import "std/ahiru/v3" |
Quick start
import "std/ahiru/v3" |
|
let app = ahiru.new() |
app.get("/health", fn(req) { return ahiru.json({ status: "ok" }) }) |
app.listen(8080) |
Capabilities
High-level overview of what ahiru is for.
Route handlers
Register GET, POST, PUT, PATCH, and DELETE endpoints. Each handler gets a request object with params, headers, and body already parsed. Return JSON, plain text, or build a custom response.
WebSocket support
Upgrade an HTTP connection and keep it open for bidirectional messages. Handy for chat, live feeds, or anything that needs push instead of polling.
Middleware pipeline
Run logging, CORS, auth checks, or rate limits before your handler sees the request. Middleware composes in order, same idea as Express or Axum layers.
SQL migrations
Keep schema changes in versioned up/down scripts. Tracks what's been applied so deploys stay repeatable across environments.
CLI scaffolding
Spin up a new service from the command line with routes, config stubs, and migration directories already laid out.
Multi-database support
Plug in npg, nsqlite, or nmongo using the same connection and migration patterns the framework expects.
API reference
106 functions and methods in ahiru. Grouped by category from the standard library docs.
CLI
| Signature | Description |
|---|---|
| niao ahiru create <name> | Interactive wizard - DB, auth, WebSocket, security |
| niao ahiru serve | Run project entry with VM bytecode (default) |
| niao ahiru serve --mode interp | Interpreter mode (multi-file imports, dev side-effects) |
| niao ahiru serve --dev | Auto-reload on file changes |
| niao ahiru serve --net | Bind `0.0.0.0` and show LAN URL |
| niao ahiru serve --port 3000 | Use port 3000 (prompts if busy) |
| niao ahiru bench --routes health,ping | Handler throughput micro-benchmark |
| niao ahiru migrate | Apply SQL migrations from `migrations/` |
| niao ahiru routes | Show `ahiru.config.toml` server/DB/auth settings |
ahiru v2 helpers (`stdlib/ahiru/v2.niao`)
| Signature | Description |
|---|---|
| ahiru_v2_create_app_from_config(path) | Load `ahiru.config.toml` |
| ahiru_v2_use_dev_middleware(app) | request_id + logging + CORS |
| ahiru_v2_use_standard_middleware(app) | dev middleware + secure headers |
| ahiru_v2_use_quiet_middleware(app) | request_id only, no access log |
| ahiru_v2_use_production_middleware(app) | JSON logs + secure headers + skip health/ping |
| ahiru_v2_set_quiet(app, bool) | Runtime toggle for logs and handler print() |
| ahiru_v2_mount_health(app, path) | `GET /health` - native Rust handler when `native_routes` enabled |
| ahiru_v2_mount_ping(app, path) | `GET /ping` - native Rust handler when `native_routes` enabled |
| ahiru_v2_ok_json(body) | Response builders |
| ahiru_v2_error_json(...) | Response builders |
| ahiru_v2_get/post(app, path, handler) | Public routes shorthand |
| ahiru_v2_version() | Returns `"2.2.0"` (matches ahiru lib 0.2.2) |
Niao API (builtins)
| Signature | Description |
|---|---|
| ahiru_app_new() | Create app handle |
| ahiru_app_from_config(path) | Create app handle |
| ahiru_app_get/post/put/delete/patch(app, path, handler, opts?) | Register routes |
| ahiru_app_ws(app, path, handler, opts?) | WebSocket route |
| ahiru_app_use(app, middleware, opts?) | Middleware: `cors`, `rate_limit`, `request_id`, `logging`, `secure_headers` |
| ahiru_app_set_logging(app, opts?) | Runtime log control: `access_log`, `json_logs`, `quiet_handlers`, `skip_paths` |
| ahiru_app_init_db(app) | Connect pools from config |
| ahiru_app_listen(app, host?, port?) | Start server (blocking) |
| ahiru_app_routes(app) | List registered routes |
| ahiru_native_routes() | Whether native health/ping routes are enabled |
| ahiru_native_mount_health(app, path) | Register native `GET /health` |
| ahiru_native_mount_ping(app, path) | Register native `GET /ping` |
| ahiru_response(status, content_type, body) | Build response object |
| ahiru_json_response(status, json) | JSON response helper |
Handler `ctx` object
| Signature | Description |
|---|---|
| method | HTTP method |
| path | Request path |
| body | Request body |
| query | Query parameters |
| params | Path parameters (`:id` routes) |
| headers | Lowercase header names |
| user | Authenticated user (when auth enabled) |
| request_id | Request correlation ID |
CLI
| Signature | Description |
|---|---|
| niao ahiru db migrate | Apply migrations |
| niao ahiru db status | Applied vs pending |
| niao ahiru db seed | Run `seeds/*.sql` |
| niao ahiru db rollback | Roll back last migration (`.down.sql`) |
| niao ahiru db reset --force | Drop SQLite + re-migrate |
| niao ahiru doctor | Config + DB + port checks |
| niao ahiru add <feature> | auth, db, websocket, cache |
| niao ahiru generate resource <name> | Handler + migration scaffold |
| niao ahiru openapi | Emit `public/openapi.json` |
| niao ahiru test | Run `tests//*.niao` |
| niao ahiru console | Project REPL stub |
| niao ahiru worker | Job worker entry |
Project commands
| Signature | Description |
|---|---|
| niao ahiru create <name> | Interactive project wizard |
| niao ahiru create <name> --yes | Defaults, no prompts |
| niao ahiru serve | Run project (VM mode, default) |
| niao ahiru serve --mode vm | Explicit VM (same as default) |
| niao ahiru serve --mode interp | Interpreter fallback |
| niao ahiru serve --dev | Auto-reload on `.niao` / config changes |
| niao ahiru serve --net | Bind `0.0.0.0`, show LAN URL |
| niao ahiru serve --port 3000 | Fixed port (prompts if busy when explicit) |
| niao ahiru serve --project . | Project root (default `.`) |
| niao ahiru serve --file path.niao | Override entry file |
| niao ahiru migrate | Run SQL migrations from `migrations/` |
| niao ahiru routes | Show config summary |
App lifecycle
| Signature | Description |
|---|---|
| ahiru_app_new(config?) | Create app handle |
| ahiru_app_from_config(path) | Load from `ahiru.config.toml` |
| ahiru_app_listen(app, host?, port?) | Start server (blocking) |
| ahiru_app_routes(app) | List registered routes |
| ahiru_app_init_db(app) | Connect DB pools from config |
Routes
| Signature | Description |
|---|---|
| ahiru_app_get(app, path, handler, opts?) | GET route |
| ahiru_app_post(app, path, handler, opts?) | POST route |
| ahiru_app_put(app, path, handler, opts?) | PUT route |
| ahiru_app_delete(app, path, handler, opts?) | DELETE route |
| ahiru_app_patch(app, path, handler, opts?) | PATCH route |
| ahiru_app_ws(app, path, handler, opts?) | WebSocket route |
Middleware and logging
| Signature | Description |
|---|---|
| ahiru_app_use(app, name, opts?) | `cors`, `rate_limit`, `request_id`, `logging`, `secure_headers` |
| ahiru_app_set_logging(app, opts?) | Runtime log control |
Native routes (new in 0.2.2)
| Signature | Description |
|---|---|
| ahiru_native_routes() | Returns whether native health/ping is enabled |
| ahiru_native_mount_health(app, path) | Native `GET /health` → `{"status":"ok"}` |
| ahiru_native_mount_ping(app, path) | Native `GET /ping` → `{"pong":true}` |
Responses and database
| Signature | Description |
|---|---|
| ahiru_response(status, content_type, body) | Build response object |
| ahiru_json_response(status, json) | JSON response helper |
| ahiru_db_exec(app, db_name, sql, params?) | Run SQL on named pool |
v2 helpers (`stdlib/ahiru/v2.niao`)
| Signature | Description |
|---|---|
| ahiru_v2_version() | Returns `"2.2.0"` |
| ahiru_v2_create_app_from_config(path) | Load `ahiru.config.toml` |
| ahiru_v2_use_dev_middleware(app) | request_id + logging + CORS |
| ahiru_v2_use_standard_middleware(app) | dev middleware + secure headers |
| ahiru_v2_use_quiet_middleware(app) | request_id only, no access log |
| ahiru_v2_use_production_middleware(app) | JSON logs + secure headers + skip health/ping |
| ahiru_v2_set_quiet(app, bool) | Runtime toggle for logs and handler `print()` |
| ahiru_v2_mount_health(app, path) | Native or Niao `GET /health` |
| ahiru_v2_mount_ping(app, path) | Native or Niao `GET /ping` |
| ahiru_v2_get(app, path, handler) | Public GET shorthand |
| ahiru_v2_post(app, path, handler) | Public POST shorthand |
| ahiru_v2_listen(app) | Start server |
| ahiru_v2_listen_on(app, host, port) | Start on host/port |
| ahiru_v2_ok_json(body) | 200 JSON response |
| ahiru_v2_error_json(status, message, code) | Error JSON response |
| ahiru_v2_health_ok() | Standard health response object |
| ahiru_v2_not_found(ctx) | 404 JSON response |
| ahiru_v2_ctx_query(ctx, key, default) | Query param with default |
| ahiru_v2_ctx_param(ctx, key, default) | Path param with default |
| ahiru_v2_rate_limit(app, rps) | Rate limit middleware |
Notes
- Route handlers compile to .niaobc, on a warm start you skip lex/parse/IR and go straight to the VM.
- /health and /ready are built in for k8s and Docker health checks.
