Set once, apply everywhere
A hook on an instance runs for every table in it. A hook on a table runs for all its generated and schema APIs.
API Maker
The framework for AI era
Your code
Run your own code before and after any API, without touching the API itself.
A pre hook runs before an API: it can check the request, change the body, or answer on its own. A post hook runs after it and can change the output. Hooks are TypeScript, work on generated, custom and system APIs, and apply on the next request after you save them.
For a database API: the pre hooks of the instance, then of the database, then of the table, then of the API itself. Several hooks at one level run from top to bottom.
Read and modify g.req.body, check the user in g.req.auth, or throw an error to stop the call with a message.
When a hook returns something, that becomes the response and the API does not run. A plain return only leaves that hook.
The generated query or your custom code runs with the request as the hooks left it.
API level first, then table, database and instance. They read the result and can replace it with g.res.output.
A hook on an instance runs for every table in it. A hook on a table runs for all its generated and schema APIs.
Give a hook group names and it runs only for API users in one of those groups, for example audit logs for partners.
Hooks query other tables, read secrets, call external APIs, emit events and import your utility classes.
Every hook has its own active flag. Turn one off to test without it: no restart, no deployment.
g.req.isApiRequestFromUser tells a real client call from an internal one, so a hook can skip calls made by your own code.
Hooks run in the sandbox like custom APIs, or on the native process when you allow it for a trusted hook.
Orders must have lines, prices must come from the product table and not from the client, and every change must record who made it. Three pre hooks on the orders table enforce it for the generated APIs, the schema APIs and every app that calls them.
import * as T from 'types';async function main(g: T.IAMGlobal) { if (!g.req.isApiRequestFromUser) return; // calls from your own code pass through const order = g.req.body; if (!order.lines?.length) throw 'An order needs at least one line.'; order.created_by = g.req.auth.authAMDB?.username;}module.exports = main;import * as T from 'types';async function main(g: T.IAMGlobal) { const output = g.res.output; const rows = Array.isArray(output) ? output : [output]; for (const row of rows) delete row.internal_cost; g.res.output = output; // the answer the client gets}module.exports = main;Every generated and schema API, at the instance, database, table or API level, and every system API. Custom APIs get hooks per version.
Pre hooks: instance, database, table, API, and from top to bottom inside a level. Post hooks: the other way round, API first and instance last.
Throw in the pre hook. The call stops and the client gets your message in errors.
Documentation