Synsema docsENES

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")

db_open("./store.db")   -- `require db` grants the capability; `db_open` opens the connection

task check_token(token)   -- the auth task receives the bearer token (stripped), not the request
    give when token == "secret" then {"user": "admin"} otherwise nothing   -- give an identity to allow, `nothing` to reject (401)

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

serve.syn
-- 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")

vs. FastAPI

No framework to install, no Pydantic models, no Uvicorn, no requirements.txtone 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.