Build a REST API
A full CRUD API — routes, auth, validation, pagination, a real database — in one file, with the production HTTP server built in. No framework, no ASGI server, no requirements.txt.
The whole thing
require serve(8080)
require db("./store.db")
task check_token(req)
give header_of(req, "authorization") == "Bearer secret" -- your real check here
serve on 8080
auth with check_token
route "GET /products"
give paged("SELECT id, name, price FROM products ORDER BY id") -- paginated + total
route "GET /products/:id"
let rows be sql("SELECT * FROM products WHERE id = ?", [params.id])
give when length(rows) == 0 then not_found("no such product") otherwise rows[0]
route "POST /products" requires auth
expect body {name: text, price: number} -- 400 automatically if it doesn't match
let b be json of request
sql_exec("INSERT INTO products (name, price) VALUES (?, ?)", [b["name"], b["price"]])
give created(b)
route "DELETE /products/:id" requires auth
sql_exec("DELETE FROM products WHERE id = ?", [params.id])
give ok({"deleted": params.id})
Run it: synsema serve api.syn. That's a production server — async, true multi-core, a single static binary with zero runtime.
What you got for free
-- Doc example: the serve response contract. Helpers return {status, value}; the
-- runtime renders them. (A real `serve on` block doesn't terminate, so the doctest
-- asserts the response shapes the handlers give — see the prose for a full server.)
intent: "doc example: serve response contract"
print("ok → " + text(status of ok({"a": 1})) + ", fail(400) → " + text(status of fail(400, "bad")))
test "uniform response helpers carry a status + value"
assert_eq(status of ok({"a": 1}), 200)
assert_eq(status of created({"id": 1}), 201)
assert_eq(status of fail(400, "bad input"), 400)
assert_eq(status of not_found("missing"), 404)
assert_eq((value of fail(400, "bad input"))["error"], "bad input")
- Uniform responses —
ok/created/fail/not_foundcarry the right status; a bare value becomes200 {json}. - Validation —
expect body {…}returns400with detail when the body doesn't match; no manual checks. - Auth —
auth with <task>+requires authper route. - Pagination —
paged(...)pushesLIMIT/OFFSETinto SQL and computes an exact total. - Secure by default —
require db/serve, secrets redacted, capability-scoped.
vs. FastAPI
No framework to install, no Pydantic models, no Uvicorn, no requirements.txt — one binary, one file. Validation and auth are language keywords, not decorators you wire up by hand. And it's secure by default and deployed with one flag. See HTTP server for the full route/SSE/CORS reference and Frontend to also serve HTML.