Public endpoints
Not every function in an api/ file should be reachable over HTTP — internal helpers, write-side mutations, anything that bypasses auth. Mark functions [api_public: true] to expose them. 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 entirely.
# api/user.rat
> get_users[] [api_public: true]
<< main_db.user.list()
> 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 both public and private functions side by side. Page handlers freely 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.get(id)
> delete_user[id]
# private — pages can call, network can't
main_db.user.delete(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. GET to the same URL fires the function with no args — 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() Next section: Forms — collecting user input and wiring it through the reactive graph.