Custom APIs¶
A custom API is a TypeScript function behind a path and a method. Save it in the admin panel (API Info → Custom API) or in your editor through the local client, and it answers at /api/custom-api/<user-path>/<path> right away, in a sandbox, with the whole of API Maker available through the global object g.
| URL | /api/custom-api/<user-path>/<path of the settings> |
| Method | the requestMethod of the settings : GET, POST, PUT or DELETE |
| Body, query, params, headers, files | g.req.body, g.req.query, g.req.params, g.req.headers, g.req.body.files |
| Answer | what main returns, in data of the envelope, or a file, or any content type |
| Runs in | the sandbox of the account ; the native process with runOnNativeProcess: true |
| Access | apiAccessType : TOKEN_ACCESS (default), IS_PUBLIC, NO_ACCESS (only from other code) |
| From code | g.sys.system.callExternalApi over HTTP, or g.sys.test.runCustomApi in a test |
Hello world¶
Every custom API has two files : the basic info (its settings) and the code.
| Basic info | |
|---|---|
| Code | |
|---|---|
- The path and the method must match exactly :
/hello-worldwithGET. Variables go in the query string or the body, not in the path. path+requestMethodis unique in the account ;nameis unique too and names the folder in Git.
The settings¶
| Key | Meaning |
|---|---|
name, path, requestMethod |
Identity and URL. |
apiAccessType |
TOKEN_ACCESS : the API user token, plus the person token when authProviders names one. IS_PUBLIC : no token. NO_ACCESS : not reachable over HTTP, only from other code and the testing page. |
authProviders |
Names of the auth providers whose token the person must send. Absent : the providers of the default secret. [] : the API user token only. |
enableCaching |
Cache the answer in Redis, per URL, body and headers that matter, until resetCacheOnModificationOf says otherwise or the reset custom API cache system API runs. |
resetCacheOnModificationOf |
What resets the cache : 'DB:instance:database:table' when that table is written through API Maker, 'CA:name' when that custom API is called, 'TP:bundle:version' when a third party API of that version writes. |
acceptOnlyEncryptedData |
Refuse plain bodies : the body must be an encrypted payload. |
reqBodySchema, reqQueryParametersSchema |
A schema for the body and for the query params : converted and validated before the code runs, every error at once with 400. |
errorList |
The messages your API throws, listed so they can be translated with i18n and shown in the docs of the API. |
runOnNativeProcess |
Run in the API Maker process instead of the sandbox : native modules and the packages of API Maker, no isolation. Use with care. |
customApiTimeoutInSeconds |
How long the code may run, in seconds (10 by default). Sent as x-am-sandbox-timeout. |
separateSandboxSettings |
A sandbox of its own for this API, with its own packages and memory. |
fileUpload |
enable, allowFileUploadFields, and per field minFileSizeBytes, maxFileSizeBytes, allowedExtensionsArr. |
swaggerDocs |
What the Swagger document of the API users shows for this API. |
See Custom API settings for every key with its example.
Validate the request with a schema¶
- The body and the query params reach your code converted (types, trims, defaults) and checked (required, min, enum…). A wrong request never reaches the code.
- The is valid data for custom API system API runs the same check without calling the API.
Reach your data and the rest of API Maker¶
awaiteveryg.syscall. The second argumenttruereturns the whole envelope instead of throwing.import * as db from 'db-interfaces'gives the interfaces generated from your schemas,db.<instance>.<database>.I<Table>.- Every method of
ghas a page in the code examples.
Errors and status codes¶
- A thrown error answers
success: falsewith the message inerrors; a message listed inerrorListis translated by i18n. g.res.statusCodesets the status of a normal answer ;g.res.warningsadds warnings.
Files¶
Upload. Send multipart/form-data with the files in the field files (or files1, files2… up to files41 to keep groups apart). They are on disk when the code runs, in g.req.body.files :
fileUpload.validations.files.maxFileSizeBytesandallowedExtensionsArrin the settings refuse a wrong file before the code runs. Uploaded files are cleaned from the uploads folder afteruploadedFileRemoveOlderThanThisTimeInSeconds(30 minutes by default).
Download. Return an object with the __am__ keys of IDownloadResponse : the file (or a zip of several) is streamed to the caller.
__am__downloadFileOrFolderPathswith several paths, or{ fsSource, archiveDestination }objects, answers a zip.
Any content type¶
Set g.res.contentType and return the content : HTML, text, XML, YAML, or bytes as base64 for any other MIME type.
| A tiny gif | |
|---|---|
g.res.headersadds response headers. See Content types.
Around the code¶
- Hooks : pre and post hooks on the custom API itself, see Pre hooks.
- Events and WebSockets : an event can trigger automatically after the API, and WebSocket clients subscribed to the API get its answer.
- Versions : several versions of the code, one active ; switch back in one click.
- Docs tab : notes for the people who use the API, shown in the API testing page and the Swagger of the API users.
- Test cases :
g.sys.test.runCustomApiruns the code with mocks and measures its coverage. - Git :
src/Custom APIs/<name>/holds the basic info, the code and the docs. - Groups : an API user calls a custom API only when a group grants it, see API group permission.
Native process¶
runOnNativeProcess: true runs the function inside API Maker itself : no sandbox start, access to the packages of API Maker and to native modules such as a browser for Playwright. A bug there can hurt the whole server, so keep it for the few APIs which need it.
Samples in every account¶
A new account comes with custom APIs under /default/… which show the features at work : deep populate, find and join, caching, a WebSocket emitter, S3 upload and download, a login which returns both tokens, a captcha, data isolation with hooks. Open them on the Custom API page and read the code.