moonapi
A typed web framework for MoonBit

Build services where the route, the request and the response are all types.

moonapi is a web framework for MoonBit. You describe an application from one object, and every route handler receives a typed context and returns a typed response. The same application generates an OpenAPI document automatically, and runs on a native server or in WebAssembly.

$ moon add moonbitstack/moonapi
app.mbt
let app = @moonapi.App::new()
app.get("/", _ctx =>
  @moonapi.text(200, "Hello from moonapi"))
app.get("/users/{id}", ctx =>
  @moonapi.text(200,
    "user " + ctx.param("id").unwrap_or("")))
app.post("/users", _ctx =>
  @moonapi.text(201, "created"))

// run a request in-process
let response = app.handle({
http_method: "GET", path: "/users/42",
query_string: b"", headers: [], body: b"",
})
response.status  // 200
recorded run · @moonapi.App::handle
GET /users/42
200 OK
user 42

POST /users
201 Created
created

GET /users/abc/orders
404 Not Found
{"detail":"Not Found"}

DELETE /
405 Method Not Allowed
{"detail":"Method Not Allowed"}
13
packages, one coherent API
544
documented public items
3.1
OpenAPI documents generated
4
backends: native, wasm, wasm-gc, js

What you get from a single application object

Everything below is part of the public API. The guide walks through each, and the API reference documents every function, method and parameter.

Typed routes and path parameters

Declare routes with {id} placeholders. The framework matches the path, binds the parameter, and returns the right status when nothing matches — no separate router config.

Request extraction

Read the path, query string, headers and typed JSON body from a single context. Each extractor returns an option you handle inline.

Dependency injection

Register shared services once by name and list them on a route with dependencies=[...]. The container resolves each once per request and tears them down in reverse order.

OpenAPI documents

Each route carries a summary and tags. Call one method to emit an OpenAPI 3.1 document you can serve at /openapi.json or hand to a documentation UI.

Security schemes and auth

Declare API keys, bearer tokens, OAuth2 and other schemes. Attach an enforcer per scheme and the framework verifies each request before your handler runs.

Streaming, WebSockets and SSE

Return server-sent events or hold a WebSocket connection alongside ordinary request handling in the same application.

Templates and static files

Render HTML templates and serve static assets, mounting them at their own prefixes without leaving the application object.

Native and WebAssembly

Compile the same application to a native server or to WebAssembly. The request and response types are identical across both.

A small set of packages that fit together

The root @moonapi package is where you start. The others are imported by name when you need them.

@moonapi
The application object, response helpers and the top-level API.
@ctx
The request context: path, query, headers and body extraction.
@route
The router, path matching and named routes for URL building.
@status
Response helpers, streams, server-sent events, cookies and status constants.
@schema
Typed bodies, field constraints and JSON schema.
@openapi
OpenAPI document building and serialisation.
@security
Security schemes and request-time enforcers.
@di
The dependency-injection container.
@socket
The live WebSocket connection.
@templates
HTML template rendering.
@static
Static file serving and mounting.
@exceptions
Typed HTTP exceptions and handlers.
@endpoint
Reusable endpoint and operation descriptors.
New here? The guide takes you from an empty application to a documented service in a few short steps, with every code fragment shown against its real output. When you need the exact signature of a function or method, open the API reference.
Start the guide See the request lifecycle