Public endpoints
Not every function in an api/ file should be reachable over HTTP: internal helpers, write-side mutations, anything that bypasses auth. Mark a function [api_public: true] to expose it. The default is private. In-process callers still see the function, but a POST to its URL returns 403.
Opt in per function
api/user.rat
[api_public: true] next to the function name flips the gate. Private functions stay callable from inside Rat code (other API files, pages, services) but disappear from the HTTP surface.
# api/user.rat
> get_users[] [api_public: true]
<< main_db.user.all()
> add_user[name]
# no api_public - internal only
<< main_db.user.add({name: name}) Mixed namespace
Same file, different exposure
A single file can ship public and private functions side by side. Page handlers call user.add_user(...) in-process; external POSTs to /api/user/add_user hit the 403.
# api/user.rat
> get_profile[id] [api_public: true]
<< main_db.user.first({id: id})
> delete_user[id]
# private - pages can call, network can't
main_db.user.remove({id: id}) HTTP methods
POST args, GET reads
Public function endpoints accept POST with a JSON body. A JSON array destructures to positional args; any other JSON value becomes the single argument. A GET to the same URL calls the function with no args, which is handy for zero-arg reads.
# POST /api/user/add_user
# body: ["Ada", "ada@example.com"]
# → add_user("Ada", "ada@example.com")
# GET /api/user/get_users
# → get_users() See also API files · Middleware · Threat model