Prism/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 "#prism/modules";

export class ItemsRoute extends Routes {
    constructor(prism) {
        super(prism, {
            name: "items",
            path: "/items",
            permissions: { GET: "example.view", POST: "example.edit" }
        });
    }

    async GET(request) {
        const items = this.prism.modules.models.get(this.module, "example_items");
        return items.page(items.query(request.query));
    }

    async POST(request) {
        const created = await this.prism.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

KeyDefaultWhat it does
nameRequiredThe route name.
pathRequiredThe path. Supports Express parameters such as /items/:id.
absolutefalseMount path as is instead of under /api/modules/<module>. Use it for public /api/v1/ endpoints.
aliases[]Extra full paths for the same route, such as an /api/v1/ path for API tokens.
accessprivatepublic lets anyone call it. private needs a signed-in session or an API token.
permissions{}One permission for every method, or one per method.
limitNoneRate limit per IP, such as { window: 60, max: 30 } for 30 a minute.
rawfalseKeep the raw body on request.rawBody, for webhooks that check a signature.

When the module is turned off, its routes answer 404. Routes with fewer :params are mounted first, so /items/key wins over /items/:id.

Public Endpoints

Endpoints that products, the store or an SDK read are public, versioned and signed:

export class CatalogRoute extends Routes {
    constructor(prism) {
        super(prism, { name: "catalog", path: "/api/v1/example/items", absolute: true, access: "public", limit: { window: 60, max: 120 } });
    }

    async GET(request, response) {
        const items = this.prism.modules.models.get(this.module, "example_items");
        this.signed(response, this.listing(request, "items", await items.page(items.query(request.query))));
    }
}

The site on the web port forwards every /api/v1/ request to the API, so these work on the store's own address.

Helpers

HelperWhat 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. See Actors.
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-prism-signature header.
this.listing(request, name, page)Wraps a page() result as { success, total, [name] } on /api/v1/ paths.
this.versioned(request)Whether the request came in on an /api/v1/ path.

Signed Responses

async GET(request, response) {
    this.signed(response, { success: true, item });
}

signed sends the response itself, so return nothing after it. Clients check the header against GET /api/v1/public-key. See Signed Responses.