Kora/developer documentation/Routes
Routes
API endpoints for your module, with permissions, rate limits and signed responses.
A route is an endpoint on the API port. Put each one in its own folder under src/routes/ as route.js.
modules/example/src/routes/items/route.js
import { Routes } from "#kora/modules";
export class ItemsRoute extends Routes {
constructor(kora) {
super(kora, {
name: "items",
path: "/items",
permissions: { GET: "example.view", POST: "example.edit" }
});
}
async GET(request) {
const items = this.kora.modules.models.get(this.module, "example_items");
return items.page(items.query(request.query));
}
async POST(request) {
const created = await this.kora.modules.handlers.get(this.module, "items").create(request.body.identifier, request.body.name);
await this.audit(request, "items.create", created.id);
return created;
}
}This answers GET and POST on /api/modules/example/items.
Add a method for each HTTP verb you need: GET, POST, PUT, PATCH or DELETE. Whatever it returns is sent as JSON. Returning nothing sends 204. A thrown error with a status, such as from fail(), is sent as that status with { error }.
Options
| Key | Default | What it does |
|---|---|---|
name | Required | The route name. |
path | Required | The path. Supports Express parameters such as /items/:id. |
absolute | false | Mount path as is instead of under /api/modules/<module>. Use it for public /api/v1/ endpoints. |
aliases | [] | Extra full paths for the same route. |
access | private | public lets anyone call it. private needs a dashboard session or an API token. |
permissions | {} | A permission for every method, or one per method. |
limit | None | Rate limit per IP, such as { window: 60, max: 30 } for 30 a minute. |
raw | false | Skip JSON body parsing, for webhooks that need the raw body. |
When the module is turned off, its routes answer 404.
Helpers
| Helper | What it does |
|---|---|
this.can(request, permission) | Whether the caller has the permission. |
this.require(request, permission) | Throws 403 if they do not. |
this.actor(request) | Who is calling. kind is staff, token, public or system. |
this.ip(request) | The caller's IP, behind proxies too. |
this.audit(request, action, target, detail) | Adds an entry to the audit log. |
this.signed(response, data, status) | Sends data with an x-kora-signature header. |
this.listing(request, name, page) | Wraps a page() result as { success, total, [name] } on /api/v1/ paths. |
Signed Responses
Anything your product reads to make a licensing decision should be signed, so it cannot be faked:
async POST(request, response) {
this.signed(response, { valid: true, timestamp: Date.now() });
}signed sends the response itself, so return nothing after it. The SDKs check the header with the public key. See Signed Responses.