API Maker

The framework for AI era

Your code

Custom APIs

Write a TypeScript function, save it, and the API is live.

For logic that goes beyond the generated APIs, write a main function in the editor of API Maker. It gets the request in g.req and every database, cache and system API in g.sys. Save it and it answers at /api/custom-api/<your path>, with tokens, validation, hooks and logs like every other API.

See it live

Step through it, slow it down, or open the full canvas.

api-maker/features/custom-apiLive
  • Request
  • Your code
  • Data
  • Error
Deploy steps
0after save
Calls
0received
Sandbox runs
0of the code
Last status
–HTTP

Your logic is a TypeScript function. main(g) gets the request in g.req and API Maker in g.sys: databases, cache, system APIs, events. Return what the API answers.

How it works

  1. Your logic is a TypeScript function.

    main(g) gets the request in g.req and API Maker in g.sys: databases, cache, system APIs, events. Return what the API answers.

  2. Save it and the API is live.

    The TypeScript is compiled on save and POST /api/custom-api/admin/order-total answers at once. No build, no deployment.

  3. Every call is checked first.

    The token is verified, the pre hooks run and the body is validated against the schema of the API, before your code.

  4. Your code runs in the sandbox.

    In a Docker container, apart from API Maker, it queries MongoDB through g.sys.db like any API, and computes the total.

  5. The answer has the usual shape.

    After the post hooks, the returned object becomes { success, statusCode, data }. The call is logged with its execution time.

  6. Errors are yours to shape.

    No orders for customer 99: g.res.errors sets the message and the status code, and the API answers 404.

  7. Keep versions, run the active one.

    Save a new version next to the old one, each with its own pre and post hooks. Activate it and the next call runs it; activate the old one to roll back.

What you get

All your data through g.sys

g.sys.db calls every generated and schema API of every instance, g.sys.cache works with Redis, and g.sys.system encrypts, hashes, emits events and calls external APIs.

Input checked before your code

Give reqBodySchema and reqQueryParametersSchema in the settings: the body and query are converted and validated before main runs.

Uploads and downloads

Accept files with size and extension rules per field, and return a file or a zip of folders for the client to download.

Secured like the rest

A token is required by default. Make an API public, or callable only from your own code, and choose its auth providers.

Your npm packages

Add packages in the sandbox settings and import them. A heavy API can get a sandbox group of its own, with its own packages and Dockerfile.

Caching when it helps

Turn on enableCaching for a custom API and clear it when the tables or APIs it depends on change.

Versions

Keep several versions of a custom API, each with its own pre and post hooks. Calls run the active one: activate another to switch, or the old one to roll back.

An example

Checkout

A checkout API reads the cart, checks stock in one database, saves the order in another, calls the payment provider with a key from your secret and emits an event for the receipt email, all in one TypeScript function.

POST /api/custom-api/admin/order-totalorder-total.ts
import * as T from 'types';async function main(g: T.IAMGlobal) {    const orders = await g.sys.db.query<{ total: number }>({        instance: 'mongodb', database: 'shop', collection: 'orders',        find: { customer_id: g.req.body.customerId, status: 'paid' },        select: { total: 1 },    });    if (!orders.length) {        g.res.errors = [{ code: 404, message: 'No paid orders for this customer.' }];        return;    }    return { orders: orders.length, total: orders.reduce((sum, o) => sum + o.total, 0) };}module.exports = main;

The returned object becomes { success, statusCode, data }. g.sys.db calls throw on an error, or return the full response when you pass true as second argument.

Its settingscustom-api-settings.ts
import * as T from 'types';import { EType } from 'types';let customApi: T.ICustomApiSettingsTypes = {    name: 'Order Total',    requestMethod: T.ERequestMethod.POST,    path: '/order-total',    apiAccessType: T.EAPIAccessType.TOKEN_ACCESS,    customApiTimeoutInSeconds: 5,    reqBodySchema: {        customerId: { __type: EType.number, validations: { required: true } },    },    errorList: ['No paid orders for this customer.'],};module.exports = customApi;

Good to know

  • runOnNativeProcess skips the sandbox: faster and with the packages of API Maker itself, but code that blocks or leaks affects the whole server. Use it only for code you trust.
  • A call that passes its time limit is answered with a timeout error. Raise customApiTimeoutInSeconds for long work, or move it to a scheduler.

Questions

Do I need to deploy after saving?

No. The TypeScript is compiled when you save and the next call runs the new code. Git deployment moves your custom APIs between environments.

Can a custom API call other custom APIs?

Yes, through g.sys, and it can import your utility classes to share code with them.

How do I test it?

Run it from the API testing page of API Maker with any body and headers, write test cases with mocks for its logic, and read its console output in the logs.