# API Maker Documentation : Operate > The pages of https://docs.apimaker.dev in the order of the navigation, each with its title, its description and its URL. The code is in TypeScript : the Markdown of a page (its URL with .md) has every language. --- # Operate > Run API Maker after the APIs are built - the configuration of a server and the settings of databases, tables, APIs and sandboxes, caching and Index Maker, logs and dashboards, Git and upgrades, team work, internationalization, the management API and the connection strings of every database. Source: https://docs.apimaker.dev/v4/docs/guides/index.html The **Build** tab tells how to make APIs, code and websites. This tab tells how to run them : set a server up, keep it fast, watch it, ship changes and work as a team. - [Configuration and settings](https://docs.apimaker.dev/v4/docs/am-resources/api-maker-configurations.html) : The configuration of a server, then the settings of each database, table, API, system API and sandbox. - [Performance](https://docs.apimaker.dev/v4/docs/features/automatic-caching.html) : Answers from Redis with automatic caching, and the missing indexes found and made by Index Maker. - [Logs and dashboards](https://docs.apimaker.dev/v4/docs/logs/logs-and-dashboards.html) : Log profiles, the log explorer, the servers of the cluster and the Redis dashboard. - [Git and deployment](https://docs.apimaker.dev/v4/docs/Git/git.html) : Your project in Git, deployment hooks for CI, and a new version of API Maker on every server. - [Team work](https://docs.apimaker.dev/v4/docs/features/team-work.html) : One account per developer, database names masked per developer, the code finder and the compare editor. - [Connection strings](https://docs.apimaker.dev/v4/docs/Database-connection-string/mongodb-connection-strings.html) : MongoDB, MySQL, MariaDB, PostgreSQL, Oracle and SQL Server, with TLS and cloud examples. ## Read in this order 1. [API Maker configuration](https://docs.apimaker.dev/v4/docs/am-resources/api-maker-configurations.html) : what a server starts with. 2. [Connection strings](https://docs.apimaker.dev/v4/docs/Database-connection-string/mongodb-connection-strings.html) : how API Maker reaches your databases. 3. [Database settings](https://docs.apimaker.dev/v4/docs/settings/databaseSettings.html), then the settings of tables, APIs and [sandboxes](https://docs.apimaker.dev/v4/docs/settings/sandboxSettings.html). 4. [Automatic caching](https://docs.apimaker.dev/v4/docs/features/automatic-caching.html) and [Index Maker](https://docs.apimaker.dev/v4/extensions/index_maker/introduction.html) : keep it fast. 5. [Logs and dashboards](https://docs.apimaker.dev/v4/docs/logs/logs-and-dashboards.html) : watch it run. 6. [Git integration](https://docs.apimaker.dev/v4/docs/Git/git.html) and [Deploy API Maker](https://docs.apimaker.dev/v4/docs/features/deploy-api-maker.html) : ship changes and upgrades. 7. [Before you go live](https://docs.apimaker.dev/v4/docs/security/go-live.html) : the checklist of the Security tab. Two more pages : [Internationalization](https://docs.apimaker.dev/v4/docs/i18/i18.html) answers errors in the language of the caller, and [Operate API Maker using its API](https://docs.apimaker.dev/v4/docs/am-resources/operate-api-maker-using-api.html) creates admin accounts from a script. --- # API Maker Configuration > Every setting of an API Maker server - logs, databases, Redis, security, sandboxes, limits and uploads - set from the Deployment Settings page of the root user, a settings file, the .env file of each server, the environment or the command line. Export and import with sealed secrets. Source: https://docs.apimaker.dev/v4/docs/am-resources/api-maker-configurations.html A server of API Maker is one process. It reads its settings, the `am` block, from six layers when it starts : each one wins over the ones above it. 1. The defaults built into API Maker. 2. The `am` object of a settings file : `--settingsPath=`, else the `package.json` of the folder API Maker runs in. 3. The settings of the servers kept by the root user : the page **Settings → Deployment Settings** of the admin panel, kept in the main database. Every server of the installation reads the same values. 4. The `.env` file : `--envPath=`, else the `.env` of that folder. `--envPath` is an argument of the command line only : a `.env` file or the environment can not name another file. 5. The environment of the process. 6. The command line. | | | |---|---| | The page | **Settings → Deployment Settings**, for the root user alone : Logging, Databases, Redis, Security, API Access, Sandboxes, SSR websites, Requests and limits, and Uploads, then the servers, their environment and the history of the changes. | | When it applies | A setting of the servers (a setting with a path below, such as `sandbox.sandboxReqTimeout`) applies when each server starts again : the page says which values wait for a restart, and restarts the servers. The other settings of the page (the database of the logs, the Redis of the cache, the tokens of your APIs...) apply at once. | | What wins | A value of a server's `.env` file, environment or command line wins over the page : the installer writes the address, ports, database and secrets of each server in its `.env`. The page shows on which servers its value is not taken. | | Each server | The settings of [each server](https://docs.apimaker.dev/v4/docs/am-resources/api-maker-configurations.html#server) (its port, its address, its main database, the secret of the encrypted values...) are only read from its `.env` file, its environment or its command line : a server needs them before it reads its database. | | Override by name | A setting is named by its path : `am__port=48246` in `.env` or the environment, `--am.port=48246` on the command line. Levels join with `__` or `.` : `am__jwtOptions__issuer=AM_JWT`. `BE_HOST_PORT` and `logFilePath` are read without the prefix too. | | Values | Text which starts with `{` or `[` is read as JSON5, a number as a number, everything else as text : `am__redisInternal__nodes=[{"host":"127.0.0.1","port":6379}]`. An empty value overrides nothing. | | Required | `mongo_db_connection`, `passCommunication`, `passJWT`, `passDBEncryptDecrypt`, `redisInternal.nodes`. A missing or wrong value stops the start with one line per problem. | | Encrypted values | A connection string of MongoDB or of Redis, or a password of Redis, may stand encrypted in the `.env` file : the page **Security → Encrypt Strings** of the admin panel writes such a value. This hides the value (in the file, in a terminal, on a shared screen), it does not protect it : every copy of API Maker holds the key which reads it, so whoever has the program and the file reads the value. Protect the file itself (`chmod 600`, owned by the user of the service), or give the values as environment variables from the secret store of your platform. | | Log | `AM_LOG` sets what the process writes to its log : `info` by default, `debug`, or a filter per part of API Maker (`info,am_sandbox=debug`). It is read from the environment of the process only, before anything else. | ## The Deployment Settings page 1. **Find a setting** The links at the top of the page go to each card. The help of a setting shows when the pointer is on its name : what it does, its default, its limits, its unit and its variable of the `.env` file. 2. **Change it** A change which is not saved is marked on its row and in the bar at the top, with what was saved and **undo**. **default** leaves a setting of the servers to the layers of each server again. 3. **Save** **Save** (or Ctrl+S) lists every change of the settings of the servers, and asks every server what it would do with it : applied after a restart, or not taken because the server's own `.env`, environment or command line names it. A change a server could not start with is not saved. 4. **Restart** Saved values of the servers apply when a server starts. The page counts the values which wait for a restart, and restarts one server or all of them. Under each setting of the servers, the page shows what each server runs with, and where that value comes from : the default, the settings file, the page, the `.env` file, the environment or the command line. The **Servers** card shows each server, its folder, its `.env` file and its settings file; **Server environment** shows the [variables](https://docs.apimaker.dev/v4/docs/am-resources/api-maker-configurations.html#process-environment) each server has, without changing them. A value of the page which a server can not start with never keeps it down : such a server starts with its files and its environment only, says why in its log, and the page shows it in red until the values are set right and saved. The page keeps the last 50 changes of the settings of the servers : who saved them, when, and each value before and after. A secret is written `••••••` there, never its value. ## Export and import **Export** writes the saved values of the settings of the servers into a JSON file, to keep them or to set up another installation. **Import** reads such a file back into the page. - A value which is no secret is written as it is. The secrets are sealed with a password asked when the file is made : PBKDF2-HMAC-SHA256 with 600,000 rounds and a random salt makes the key, AES-256-GCM seals the secrets. Without that password nobody reads them, API Maker neither. - Import asks for the same password when the file has secrets. A wrong password is refused; a setting this version of API Maker does not know is left out and named. - Nothing is saved by an import : its values come into the page as changes to review. **Keep their values** changes only the settings of the file; **Go back to their defaults** also clears the settings the file does not have. **api-maker-server-configuration-2026-10-12.json** ```json { "format": "api-maker-server-configuration", "version": 1, "exportedAt": "2026-10-12T09:35:50.309Z", "apiMakerVersion": "4.0.0", "settings": { "sandbox.sandboxReqTimeout": 20000, "bodyLimit": 1048576 }, "secrets": { "paths": ["passJWT"], "sealed": { "kdf": "PBKDF2-HMAC-SHA256", "iterations": 600000, "salt": "…", "cipher": "AES-256-GCM", "nonce": "…", "data": "…" } } } ``` ## Settings Every setting of the page, by card. A setting with a path is a setting of the servers : its Default is what applies when no layer names it. A setting without a path is kept with the other deployment settings and applies at once. ### Logging The logs of the calls of your APIs, where they are kept and their clean up. | Setting | Default | What it does | |---|---|---| | Log DB Connection String
secret | none | The MongoDB database the logs of the calls go to. Empty : `logs.mongo_db_connection_logs` of the `.env` file of each server; without either, calls are not logged. | | Log Remove CRON | `logs.logRemoveSchedulerInterval` of the `.env` file : `0 0 0 * * *` | When old logs are removed : a cron expression of six fields, the first one being the seconds. | | Max Logs Count | `logs.maxLogsCount` of the `.env` file : `100,000` logs | The logs each account keeps : older ones are removed each time the clock above ticks. | | `logs.enableLogs`
Log the calls | `true` | Whether calls are logged, as the log profile of each account says. Off : no call is logged. | | `cron_job_time_zone`
Time zone of the log clean up | the zone of the server | The time zone the clock which removes old logs reads its cron expression in. Your schedulers have a zone each. | ### Databases How API Maker reaches the databases of your instances. | Setting | Default | What it does | |---|---|---| | `oracleClientPath`
Oracle Instant Client | none | The folder of the Oracle Instant Client, which the instances of Oracle are reached with. LD_LIBRARY_PATH, when the process has it, is taken instead. Also read as `LD_LIBRARY_PATH`. | ### Redis The Redis of the cached answers of your APIs and of the keys your code keeps, and what API Maker keeps on its own Redis. | Setting | Default | What it does | |---|---|---| | Redis for Cache & Code
secret | none | The Redis the cached answers of your APIs and the keys your code sets (`g.sys.cache`) are kept on : its host, its port and its password. Named here, it wins over `redisExternal` of the `.env` file of each server; no node here : the one of each server, if it names one, else nothing is cached. One node : API Maker caches nothing on a cluster of several nodes. Servers and sandboxes take a change at once. | | Cached Answers Kept For | `7200` seconds | Every cached answer expires after this many seconds. | | Longest Cached Answer | `1,000,000` characters | An answer longer than this many characters is not cached. | | `redisInternal.maxCharsToStoreInConsoleLogs`
Console kept per account | `15,000,000` characters | What the code of an account prints is kept on the Redis of API Maker, for its console, up to this many characters : then it is emptied. 0 : 15,000,000. | ### Security In two parts : what protects API Maker itself, and what the APIs of your accounts use. #### API Maker The security of API Maker itself : the sign in to its admin panel, and the secrets of the installation, the same on every server. | Setting | Default | What it does | |---|---|---| | Universal Login Captcha | none | A captcha value every sign in to the admin panel accepts : for automated sign ins of your own. Empty : the captcha drawn on the page only. | | `passCommunication`
Communication secret · secret · required | none | The secret of the values the admin panel and API Maker exchange outside the encrypted channel of the panel : passwords and code sent by an older panel, by the API of Operate API Maker using API, and by a git pull. Required, the same on every server. | | `passJWT`
Secret of the admin panel's tokens · secret · required | none | The secret the tokens of the people of the admin panel are signed with, and the key of the tickets of its encrypted channel. Required, the same on every server. A new value signs everybody out of the admin panel. | | `nodeJsCompatibleTokens`
Tokens a Node.js backend reads | off | On while a Node.js backend of API Maker (version 3) still answers requests of this installation next to this one : the tokens of the admin panel then say the password of their person as the database keeps it, which is what that backend compares. Off, they say a keyed hash of it, and nobody who holds a token learns anything of the password. Tokens of either kind are taken. Leave it off unless a Node.js backend shares the installation : a token is read by whoever holds it. | | `sealedSecrets`
Sealed secrets in the database | off | On : what API Maker encrypts for its own database with `passDBEncryptDecrypt` (the passwords of the people and of the API users, the secrets and their code, the second factors, git addresses with their credentials, the secrets of the deployment settings) is written sealed : AES-256-GCM with a key derived from that secret, so a value which was changed in the database is refused where it would be read as something else. Off : written as the Node.js backend writes it. Both are read, whatever this says, and a value is written anew when it is saved the next time. A Node.js backend does not read sealed values : turn it on once no Node.js backend shares the installation. People, and the tokens of API users, sign in once more after their password was saved sealed for the first time. | #### Your APIs The tokens API Maker signs for the users of your APIs and of your databases, and the encrypted data your apps send. The tokens of the admin panel are made the same way. | Setting | Default | What it does | |---|---|---| | Secret of the API Users' Tokens
secret | made when the settings of the root user are made | Signs the tokens of the API users and of the users of your databases. A new value signs out every user of your apps. | | API User's Token Across Admin Users | off | Accepts the `x-am-authorization` token of an API user, and the `x-am-user-authorization` token of a user of a database, in other admin user accounts, but only where a user with the same username and password exists there. Off keeps every token to the admin user that issued it. | | Tokens Expire After | `259200` seconds | How long the tokens of the API users and of the users of your databases are valid, and the tokens of the admin panel too : 259200 is 3 days. From 60 to 103680000. Empty : `jwtOptions.expiresIn` of the `.env` file, 259,200 by default. | | `refreshTokenValidForS`
Refresh token extra lifetime | `900` seconds | A refresh token stays valid this many seconds longer than the token it came with. | | `jwtOptions.issuer`
Token issuer | `AM_JWT` | Written into every token API Maker signs (the admin panel and the API users), and checked when a token is read. Empty : none. | | `jwtOptions.algorithm`
Token algorithm | HS256 | The HMAC the tokens are signed with. One of `HS256`, `HS384`, `HS512`. | | `jwtOptions.audience`
Token audience | none | Written into every token API Maker signs (aud), and checked when a token is read : a token signed for another audience is refused. One value or several. | | `jwtOptions.subject`
Token subject | none | Written into every token API Maker signs (sub), and checked when a token is read. | | `jwtOptions.keyid`
Token key id | none | The kid of the header of every token API Maker signs. | | `feTransferDataValidityInSecondsDefault`
Encrypted payloads valid for | `15` seconds | Seconds encrypted data sent by a web or mobile app stays valid, when the secret of the account sets no feTransferDataValidityInSeconds. | ### API Access | Setting | Default | What it does | |---|---|---| | Operate API Maker Using API | off | Lets your scripts operate API Maker through its API : see [Operate API Maker using API](https://docs.apimaker.dev/v4/docs/am-resources/operate-api-maker-using-api.html). | | Communication Token
secret | none | Authenticates the calls of that API. At least 48 characters. | ### Sandboxes Where the code of the accounts runs : its time and its memory. The sandbox count of each account is in its [Sandbox settings](https://docs.apimaker.dev/v4/docs/settings/sandboxSettings.html), and a sandbox opens as many runners of a language as the machine has [cores](https://docs.apimaker.dev/v4/docs/am-resources/api-maker-configurations.html#one-process). | Setting | Default | What it does | |---|---|---| | `sandbox.sandboxReqTimeout`
Code timeout | `13000` milliseconds | Milliseconds a run of code may take when the item it belongs to names no time of its own ([time of a run](https://docs.apimaker.dev/v4/docs/settings/sandboxSettings.html#time-of-a-run)). The header x-am-sandbox-timeout changes it for one request. At least 1. | | `sandbox.removeSandboxInactiveSinceMinutes`
Idle sandboxes stop after | `5` minutes | A sandbox nothing used for this many minutes is stopped; the next request starts it again. Fractions are allowed, half a minute at the least. | | `sandbox.sandboxMaxOldSpaceMB`
Heap of a Node.js runner | the memory of the machine ÷ its cores, at least 2500 | The heap of a runner of Node.js in a sandbox (--max-old-space-size). Empty or 0 : the memory of the machine divided by its cores, at least 2500. | | `sandbox.codeInServer`
Code in the server | on | Code in TypeScript which needs nothing of a sandbox (a hook which only reads and changes its request) runs inside API Maker. Off : every piece of code runs in its sandbox. | ### SSR websites The [SSR websites](https://docs.apimaker.dev/v4/docs/ssr/index.html) your accounts write in TSX are rendered by API Maker itself : threads of their own, each with an engine (QuickJS) per website it renders. A website can ask for less or more in its `site.config.ts` (`limits`). | Setting | Default | What it does | |---|---|---| | `ssr.threads`
Render threads | one per core | Threads which render the pages of the websites, each with the engines of the websites it renders. 0 : one per core of the machine. From 0 to 256. | | `ssr.memoryMb`
Memory of a website | `64` MB | The memory of the engine of one website on one render thread. A page which takes more fails alone, and its engine is made anew. From 8 to 4096. | | `ssr.cpuMs`
Time of the code of a page | `2000` milliseconds | The time the code of one render may run. The waits for the databases and the APIs do not count. From 10 to 600000. | | `ssr.timeoutMs`
Time of a page | `30000` milliseconds | The time one render may take in all, the waits for the databases and the APIs counted. From 100 to 3600000. | | `ssr.cacheMb`
Cache of the pages | `64` MB | The memory of the answers of pages each server keeps (the pages which say `config.cache`). 0 : none is kept. From 0 to 65536. | | `ssr.enginesPerThread`
Engines per thread | `64` | The engines of websites one render thread keeps : the one used longest ago goes for a new one. From 1 to 10000. | ### Requests and limits Sizes, counts and caches of the requests a server answers. | Setting | Default | What it does | |---|---|---| | `bodyLimit`
Largest request body | `16,777,216` bytes | A body is kept in memory while its request is answered (JSON, a text, a form without files) : a request whose body is longer is refused before it is read. Files are sent in a form, which has a limit of its own (`uploadLimit`). 0 : 536,870,912 (512 MiB), what the Node.js backend takes. Where the setting is not given, the Node.js backend takes 512 MiB and this server 16 MiB : give it where the APIs are sent more in one body. | | `uploadLimit`
Largest form with files | `536,870,912` bytes | The longest form of several parts (multipart) a request may send. Its files are written to the folder of the uploads while they arrive, never kept in memory. 0 : 536,870,912 (512 MiB). | | `uploadMaxFiles`
Most files of a form | `1000` files | A form with more files is refused, and what it wrote is removed. 0 : 1,000. | | `bodyMemoryLimit`
Memory of all request bodies | `1,073,741,824` bytes | The memory the bodies which are read at the same time may take together. A body which finds none waits for the others, then is answered 503. Never less than the largest body one request may send (`bodyLimit`, `uploadLimit`). 0 : no limit. | | `maxConnections`
Most open connections | `0` connections | The most connections a server holds open at the same time, the web sockets among them : one more waits until one closes. 0 : as many as the process may have open files (`ulimit -n`), less what it keeps for its own files and databases. The web sockets take no more than their share of them : a sixteenth of the connections (64 at the least, 4,096 at the most) is kept for the calls of the APIs, and one more WebSocket client is answered `503` with `Retry-After`. | | `tcpMemoryPercent`
Memory of the network, at most | `25` % of the memory | Linux gives all its TCP connections together a part of the memory of the machine (`net.ipv4.tcp_mem`, about 9 % as it sets it up), and slows every one of them down past it : the ones to the databases and to Redis too. A server which holds tens of thousands of connections raises that part as they come, two pages for each connection, never above this share of the memory, and never lowers it ; a server with fewer connections than the kernel has room for writes nothing. It says so in its log, and when it may not (it is not root, or runs in a container) it says the line to run by hand. 0 : the kernel is left as it is. See [many clients](https://docs.apimaker.dev/v4/docs/pages/web-socket-event-page.html#many-clients). | | `compressThreshold`
Compress answers from | `51200` bytes | Answers longer than this many bytes are compressed, when the client accepts it. | | `maximum_test_user_count`
Test users read | `1000` users | The most test users read from a table when its schema gives no count : the tokens the API Testing page and the test cases sign in with. | | `dbTokenCache.ttlSeconds`
Database token users kept for | `60` seconds | How long the person behind a database token is trusted without reading the table again. 0 : the table is read on every call. | | `dbTokenCache.maxEntries`
Database token users kept | `100,000` users | The most people behind database tokens a server keeps in memory. At least 1. | ### Uploads The clean up of the files sent to your APIs. | Setting | Default | What it does | |---|---|---| | `uploadedFileCleaningSchedulerCron`
Uploads cleaned at | `0 */30 * * * *` | When each server removes old uploaded files from its uploads folder : a cron expression of six fields, the first one being the seconds. | | `uploadedFileRemoveOlderThanThisTimeInSeconds`
Uploads kept for | `1800` seconds | Uploaded files older than this are removed when the clock above ticks. From 60 to 864000 (10 days). | ## One process, every core A server is one process of API Maker, with as many threads as its machine has cores : every request, web socket and job of the server is shared between them. A sandbox opens one runner of a language, and one more while all of its runners are busy, up to as many as the machine has cores. Neither is a setting. ## The settings of each server Set in the `.env` file of each server (the installer writes them there), its environment or its command line. The page does not show them : a server reads them before it reads its database. | Setting | Default | What it does | |---|---|---| | `port`
Port | `48246` | The port of the APIs and of the web sockets of the server : one port for both. It also tells the servers of one machine apart : their containers and folders of sandboxes are named after it. The installer writes 38246. Change `BE_HOST_PORT` with it. From 1 to 65535. | | `BE_HOST_PORT`
Public address | `http://__ip_address__:48246` | Where the admin panel and the URLs API Maker prints reach the server. `__ip_address__` is replaced by the host the browser opened the admin panel with. Behind a proxy : `https://api.example.com`. The web sockets are on the same address : `ws://` for `http://`, `wss://` for `https://`. | | `serverName`
Server name | `server1` | The name of the server on the dashboard, in the Server column of the Schedulers page, in the details of a git pull and in the runs of test cases. | | `logFilePath`
Log file | none | The file the log of the process goes to : the service the installer makes appends the output of API Maker to it. The dashboard shows, downloads and empties this file. | | `adminPanel.folder`
Admin panel | none : no admin panel on this server | The folder of the built admin panel. API Maker serves its files on the port below, and writes `BE_HOST_PORT` and its version into them as it sends them. | | `adminPanel.port`
Port of the admin panel | `4626` | The port the admin panel is served on, when the folder above is set. Behind Caddy, the panel is on port 80 or on its domain. | | `mongo_db_connection`
MongoDB of API Maker · secret · required | none | The MongoDB database which holds API Maker's own data : accounts, schemas, code, settings. A replica set. | | `passDBEncryptDecrypt`
Encryption secret of the data · secret · required | none | The secret of every value API Maker keeps encrypted, in MongoDB and in Git : 32 characters. The same on every server, and in every installation which shares a Git repository. The secrets of the Deployment Settings page are encrypted with it. | | `sandbox.sandboxCountForAdmin`
Sandboxes per account | `2` sandboxes | The sandboxes of one language an account has at most on each server, unless its Sandbox settings say otherwise. From 1 to 5. | ## Variables of the process Read before a server reaches its database. The **Server environment** card of the page shows the variables of the `.env` file and the environment, and what each server has. | Variable | Default | What it does | |---|---|---| | `uniqueServerId`
Server id | the name of the machine and the port : machine:48246 | What tells this server from the others of the installation, the same after a restart. Servers which share a .env file are told apart by their machine and port when it is not set. | | `LD_LIBRARY_PATH`
Library path | not set | When set, it is the folder of the Oracle Instant Client (oracleClientPath). | | `AM_SANDBOX_HOST`
Sandboxes on the machine | not set | local : the sandboxes are processes of the machine instead of Docker containers. The runtimes of every language have to be installed, and nothing keeps the code of an account apart from the machine : for development and for a machine of one account. | | `AM_SANDBOX_UNIX`
Sockets of the sandboxes | not set | 0 : the sandboxes are reached by their ports only. The absolute path of a folder : the Unix sockets of the sandboxes are made there (for a server in a container which has that folder of the machine at the same path). | | `AM_SANDBOX_DIRECT`
Sandboxes on their ports | not set | 0 : every sandbox is reached on its published port, without a Unix socket. | | `AM_SANDBOX_CORE`, `--sandboxCore`
Core of the agents | not set | The library of API Maker the agents of the sandboxes load, or the folder of those libraries. Unset : next to the program of API Maker, as the releases deliver it. On macOS and Windows the `api-maker` command and API Maker Launchpad set it to the sandbox package of the processor (`@sava-info-systems/api-maker-engine-sandbox-linux-x64` or `-arm64`). | | `AM_SANDBOX_CORE_ANY`
Core of another build | not set | Set (and not 0) : the agents use a core of another build than the one of the server. For who builds the two apart and knows that they match. | | `AM_NATIVE_CORE`, `--nativeCore`
Core of the native process | not set | The library of API Maker the runners of the native process load (code with `runOnNativeProcess: true`), built for the machine of the server, or the folder of those libraries. Unset : the libraries of the sandboxes when they are built for this machine (a release on Linux), else the ones cargo built next to the program of API Maker (a debug build of the program takes an optimized build of them first : `target/fast`, `target/release`). | | `AM_SANDBOX_AGENT`, `--sandboxAgent`
Agent of the sandboxes | not set | The program put into the containers of the sandboxes : the launcher `am_agent`. Unset : the one next to the program of API Maker, else one built inside Docker once. A program which is not the launcher (the server `api_maker_be`, an agent library) is refused with a warning, and the next of these places is taken. On macOS and Windows the `api-maker` command and API Maker Launchpad name the `am_agent` of the sandbox package. | | `AM_SANDBOX_AGENT_BUILDER`
Image the agent is built in | rust:1-alpine | The image of Docker the agent of the sandboxes is compiled in, when it has to be built. | | `AM_TOOLS_PROGRAM`, `--toolsProgram`
Program of the tools | not set | The program `am_tools` : the compiler of TypeScript and its declarations, the reader of code (whether code can run inside API Maker is found when it is saved, what the hooks of the security report do), quicktype, postman, the audit of packages and the encoders of images, which API Maker starts when code is saved or a page asks for one, and which ends when nothing asked for a while. Unset : the one next to the program of API Maker, as the releases deliver it. | | `AM_TOOLS_IDLE_SECONDS`
Idle time of the tools | 30, and 300 once it loaded the compiler of TypeScript or a library | `am_tools` ends when nothing was asked of it for this many seconds, and what its compilers and libraries took goes back to the system ; the next save starts it again. Unset : 30 seconds, and 300 once it loaded what takes seconds to load (the compiler of TypeScript of the declarations, quicktype, postman, the audit). | | `AM_LOCAL_RUN_TOKEN`
Token of Launchpad | not set | Enables the API of API Maker Launchpad when it has at least 24 characters : the app sets it when it starts API Maker on a computer. | Arguments of the command line : | Argument | Default | What it does | |---|---|---| | `--appRoot`
Folder of API Maker | the folder API Maker is started in | The folder API Maker runs in : its package.json, its .env file, uploads and license file. | | `--envPath`
.env file | .env of the folder of API Maker | The .env file to read. A file named here must exist; the default one may be missing. Only the command line names it. | | `--settingsPath`
Settings file | package.json of the folder of API Maker | A file whose am object, or the whole file when it has none, is the lowest layer of the settings after the built-in defaults. | | `--ACCESS_TOKEN`
Access token of tests | not set | A value of the authorization header accepted without any check, as the installation itself. For tests and development only : never on a server people use. | ## Removed settings Older `.env` files and settings files may name these. A server starts with them, and does nothing with them. | Setting | Now | |---|---| | `BE_WS_HOST_PORT` | The web sockets are on the port of the APIs : the admin panel reaches them at the address of `BE_HOST_PORT`, with `ws://` or `wss://`. | | `workerThreads` | The threads of a server are the [cores](https://docs.apimaker.dev/v4/docs/am-resources/api-maker-configurations.html#one-process) of its machine. | | `cpuCount` | A sandbox opens up to as many runners of a language as the machine has [cores](https://docs.apimaker.dev/v4/docs/am-resources/api-maker-configurations.html#one-process). | | `docker.socketPath`, `docker.host`, `docker.port`, `docker.protocol` | API Maker reaches Docker where the system has it : `/var/run/docker.sock` on Linux; on macOS that socket, else the one of Docker Desktop, Colima, OrbStack or Rancher Desktop in the home folder; the named pipe of Docker Desktop on Windows. | | `db.mongo.max_rows_return` | A read of MongoDB returns as many rows as the request asks for, up to 100,000,000,000,000. | | `ACCESS_TOKEN` in `.env` or the environment | Read from the command line only : `--ACCESS_TOKEN`. | | `envPath` in `.env`, the environment or the `am` block | The `.env` file is named on the command line only : `--envPath`. | | `PGSSLMODE`, `PGSSLNEGOTIATION` | The connection string of a PostgreSQL instance says whether it uses TLS (`sslmode`, `sslnegotiation`). | | `RUST_BACKTRACE` | Every panic writes its backtrace in the log. | | `processTitle`, `integrity`, `wsPort` | Not used. | | `debugging.portStart`, `debugging.portEnd` | Not used. | | `redisInternal.otherRedisClusterOptions`, `redisExternal.otherRedisClusterOptions` | Not used. | | `db.common.start_with_test_data`, `db.mongo.default_id` | Not used. | | Server Startup Script (deployment settings) | Not used. | ## A `.env` file **.env** ```bash BE_HOST_PORT=https://api.example.com am__serverName=api-1 am__port=38246 am__mongo_db_connection=mongodb://…/api_maker?replicaSet=rs0 am__redisInternal__nodes=[{"host":"127.0.0.1","port":6379}] am__passCommunication=… am__passJWT=… am__passDBEncryptDecrypt=… ``` A cluster is several servers, each with its process, behind a reverse proxy. They share MongoDB and Redis : [schedulers](https://docs.apimaker.dev/v4/docs/apis-all/schedulers/user-created-schedulers-api.html) are spread over them and run once per tick, a change saved on one server reaches the others at once, and they all read the same Deployment Settings. The three secrets must be the same on every server of an environment, and `passDBEncryptDecrypt` the same in every environment which shares a Git repository : values encrypted with one can not be read with another. ## Related - [Server dashboard](https://docs.apimaker.dev/v4/docs/logs/logs-and-dashboards.html#servers) · [How API Maker works](https://docs.apimaker.dev/v4/docs/getting-started/how-it-works.html) · [Sandbox settings](https://docs.apimaker.dev/v4/docs/settings/sandboxSettings.html) · [Operate API Maker using API](https://docs.apimaker.dev/v4/docs/am-resources/operate-api-maker-using-api.html) · [Install on a server](https://docs.apimaker.dev/v4/docs/getting-started/install-on-server.html) · [Deploy API Maker](https://docs.apimaker.dev/v4/docs/features/deploy-api-maker.html) --- # Database Settings > Settings which apply to every table of a database in API Maker - access type, auth providers, caching, encrypted payloads - inherited by the tables and the APIs which do not override them. Source: https://docs.apimaker.dev/v4/docs/settings/databaseSettings.html The settings of a database apply to every table of it, and to every API of those tables, unless a table or an API sets the same key itself. | | | |---|---| | Page | `APIs & Logic → Instance API (DB API)` → select the database → **Add Database Settings**. | | Type | `T.IInstanceApiSettingsTypes` | | Written in | TypeScript, as all settings are, whatever [language](https://docs.apimaker.dev/v4/docs/languages/index.html#basic-info) your code is written in. API Maker [runs it itself](https://docs.apimaker.dev/v4/docs/languages/index.html#settings-run) when you save : no sandbox, no packages. | | Applies to | The APIs of every table of the database. | **Database settings** ```typescript import * as T from 'types'; // Remove properties which you want to apply from parent level let instanceColSetting: T.IInstanceApiSettingsTypes = { enableCaching: false, acceptOnlyEncryptedData: false, apiAccessType: T.EAPIAccessType.TOKEN_ACCESS, // authProviders: ['users_tg'], // absent : common.authProviders of the secret ; [] : API user token only }; module.exports = instanceColSetting; ``` ## The keys | Key | Values | Meaning | |---|---|---| | `apiAccessType` | `TOKEN_ACCESS` (default), `IS_PUBLIC`, `NO_ACCESS` | Who may call : with the token of an API user, anybody, or only your own code and the admin panel. | | `authProviders` | names of [auth providers](https://docs.apimaker.dev/v4/docs/authorization/AMDB.html) | The person tokens the call must carry. Absent : `common.authProviders` of the secret. `[]` : the API user token alone. | | `acceptOnlyEncryptedData` | `true` / `false` | Refuse plain bodies and query strings : see [encrypted payloads](https://docs.apimaker.dev/v4/docs/features/security-features.html#encrypted-request-payloads). | | `enableCaching` | `true` / `false` | Cache the answers of the reads in Redis until a write of the table : see [automatic caching](https://docs.apimaker.dev/v4/docs/features/automatic-caching.html). Table and database level only. | - A setting is used when it is present : leave a key out to inherit it. The order is **API settings → table settings → database settings → secret → default**. ## Related - [Collection settings](https://docs.apimaker.dev/v4/docs/settings/collectionSettings.html) · [API settings](https://docs.apimaker.dev/v4/docs/settings/apiSettings.html) · [Auth of a database user](https://docs.apimaker.dev/v4/docs/authorization/AMDB.html) --- # Collection Settings > Settings of one table or collection in API Maker - access type, auth providers, caching, encrypted payloads - over the settings of its database, under the settings of its APIs. Source: https://docs.apimaker.dev/v4/docs/settings/collectionSettings.html The settings of a table apply to every API of the table. They override the settings of the database, and an API can override them in turn. | | | |---|---| | Page | `APIs & Logic → Instance API (DB API)` → select the table → **Add Collection Settings**. | | Type | `T.IInstanceApiSettingsTypes` | | Written in | TypeScript, as all settings are, whatever [language](https://docs.apimaker.dev/v4/docs/languages/index.html#basic-info) your code is written in. API Maker [runs it itself](https://docs.apimaker.dev/v4/docs/languages/index.html#settings-run) when you save : no sandbox, no packages. | | Applies to | The APIs of this table. | **Collection settings** ```typescript import * as T from 'types'; // Remove properties which you want to apply from parent level let instanceColSetting: T.IInstanceApiSettingsTypes = { enableCaching: true, // the reads of this table are cached until a write acceptOnlyEncryptedData: false, apiAccessType: T.EAPIAccessType.TOKEN_ACCESS, authProviders: ['users_tg'], // every API of the table needs a person of users_tg }; module.exports = instanceColSetting; ``` ## The keys | Key | Values | Meaning | |---|---|---| | `apiAccessType` | `TOKEN_ACCESS` (default), `IS_PUBLIC`, `NO_ACCESS` | Who may call : with the token of an API user, anybody, or only your own code and the admin panel. | | `authProviders` | names of [auth providers](https://docs.apimaker.dev/v4/docs/authorization/AMDB.html) | The person tokens the call must carry. Absent : `common.authProviders` of the secret. `[]` : the API user token alone. | | `acceptOnlyEncryptedData` | `true` / `false` | Refuse plain bodies and query strings : see [encrypted payloads](https://docs.apimaker.dev/v4/docs/features/security-features.html#encrypted-request-payloads). | | `enableCaching` | `true` / `false` | Cache the answers of the reads in Redis until a write of the table : see [automatic caching](https://docs.apimaker.dev/v4/docs/features/automatic-caching.html). Table and database level only. | - A setting is used when it is present : leave a key out to inherit it. The order is **API settings → table settings → database settings → secret → default**. ## Related - [Database settings](https://docs.apimaker.dev/v4/docs/settings/databaseSettings.html) · [API settings](https://docs.apimaker.dev/v4/docs/settings/apiSettings.html) · [Automatic caching](https://docs.apimaker.dev/v4/docs/features/automatic-caching.html) --- # API Settings > Settings of one generated or schema API of a table in API Maker - access type, auth providers, encrypted payloads - the most specific level, over the table and the database. Source: https://docs.apimaker.dev/v4/docs/settings/apiSettings.html The settings of one API of a table, for example the get all of `products` : the most specific level. A key set here wins over the table and the database. | | | |---|---| | Page | `APIs & Logic → Instance API (DB API)` → select the table → the API → **Add API Settings**. | | Type | `T.IInstanceApiSettingsTypesForAPI` | | Written in | TypeScript, as all settings are, whatever [language](https://docs.apimaker.dev/v4/docs/languages/index.html#basic-info) your code is written in. API Maker [runs it itself](https://docs.apimaker.dev/v4/docs/languages/index.html#settings-run) when you save : no sandbox, no packages. | | Applies to | This API only. Caching is not set here : it belongs to the table or the database. | **Make one read public, keep the writes behind tokens** ```typescript import * as T from 'types'; // Remove properties which you want to apply from parent level let instanceColSetting: T.IInstanceApiSettingsTypesForAPI = { acceptOnlyEncryptedData: false, apiAccessType: T.EAPIAccessType.IS_PUBLIC, }; module.exports = instanceColSetting; ``` ## The keys | Key | Values | Meaning | |---|---|---| | `apiAccessType` | `TOKEN_ACCESS` (default), `IS_PUBLIC`, `NO_ACCESS` | Who may call : with the token of an API user, anybody, or only your own code and the admin panel. | | `authProviders` | names of [auth providers](https://docs.apimaker.dev/v4/docs/authorization/AMDB.html) | The person tokens the call must carry. Absent : `common.authProviders` of the secret. `[]` : the API user token alone. | | `acceptOnlyEncryptedData` | `true` / `false` | Refuse plain bodies and query strings : see [encrypted payloads](https://docs.apimaker.dev/v4/docs/features/security-features.html#encrypted-request-payloads). | - A setting is used when it is present : leave a key out to inherit it. The order is **API settings → table settings → database settings → secret → default**. - `NO_ACCESS` hides an API from HTTP while your custom APIs keep using it through `g.sys.db` : a way to expose a narrow custom API instead of the raw table. ## Related - [Collection settings](https://docs.apimaker.dev/v4/docs/settings/collectionSettings.html) · [Database settings](https://docs.apimaker.dev/v4/docs/settings/databaseSettings.html) · [Security features](https://docs.apimaker.dev/v4/docs/features/security-features.html) --- # System API Settings > Settings of one system API of API Maker - open it over HTTP with TOKEN_ACCESS or IS_PUBLIC, require person tokens with authProviders, cache its answers, refuse plain payloads. Source: https://docs.apimaker.dev/v4/docs/settings/systemApiSettings.html Each [system API](https://docs.apimaker.dev/v4/docs/apis-all/overview.html#system-apis) has its own settings. Without settings, a system API is `NO_ACCESS` : your code calls it through `g.sys`, the admin panel tests it, and an HTTP call is refused with `401`. The token API is the exception : public unless its settings say otherwise. | | | |---|---| | Page | `APIs & Logic → System API` → the plus button of the API. | | Type | `T.ISystemApiSettingsTypes` | | Written in | TypeScript, as all settings are, whatever [language](https://docs.apimaker.dev/v4/docs/languages/index.html#basic-info) your code is written in. API Maker [runs it itself](https://docs.apimaker.dev/v4/docs/languages/index.html#settings-run) when you save : no sandbox, no packages. | | Default | `NO_ACCESS` for every system API but the token API. | **Open the hash data API to the applications** ```typescript import * as T from 'types'; let systemApi: T.ISystemApiSettingsTypes = { enableCaching: false, acceptOnlyEncryptedData: false, apiAccessType: T.EAPIAccessType.TOKEN_ACCESS, // authProviders: ['users_tg'], }; module.exports = systemApi; ``` ## The keys | Key | Values | Meaning | |---|---|---| | `apiAccessType` | `NO_ACCESS` (default), `TOKEN_ACCESS`, `IS_PUBLIC` | Who may call it over HTTP : nobody, an API user whose group grants the system API, anybody. | | `authProviders` | names of [auth providers](https://docs.apimaker.dev/v4/docs/authorization/AMDB.html) | The person tokens the call must carry. Absent : `common.authProviders` of the secret. `[]` : the API user token alone. | | `enableCaching` | `true` / `false` | Cache the answers in Redis. Reset them with [reset system API cache](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-reset-redis-cache-system-api.html). | | `acceptOnlyEncryptedData` | `true` / `false` | Refuse plain bodies : [encrypted payloads](https://docs.apimaker.dev/v4/docs/features/security-features.html#encrypted-request-payloads). | - Open only what applications really need : execute plain query, get secret, create indexes and the cache resets change or reveal a lot. The [APIs Security Report](https://docs.apimaker.dev/v4/docs/apis-security/api-security-report.html) lists the sensitive ones which are open. ## Related - [All system APIs](https://docs.apimaker.dev/v4/docs/apis-all/overview.html#system-apis) · [System APIs from code](https://docs.apimaker.dev/v4/examples/sys/system/system.html) --- # Sandbox Settings > Where the code of an API Maker account runs - the runtime and version of each language, its packages from npm, PyPI, Packagist, NuGet, Go modules, crates.io and Maven Central, your own Dockerfile, the images on every server, the sandbox count, the automatic restart and the allowed origins. Source: https://docs.apimaker.dev/v4/docs/settings/sandboxSettings.html The code of an account runs in sandboxes : Docker containers of the account, one kind per [language](https://docs.apimaker.dev/v4/docs/languages/index.html). This page says what each one is made of. Page : `Operations → Sandbox Settings`. | | | |---|---| | Languages | TypeScript / JavaScript, Python, PHP, C#, Go, Rust, Java, Kotlin : each with its own runtime, version, packages and Dockerfile | | Images | built in the background on every server when you save, shared by every account with the same settings | | Sandbox count | the most sandboxes of one language at a time, on each server | | Restart every | sandboxes start anew after this many seconds, without dropping a request | | Allowed origins | the web origins allowed to call the APIs from a browser | > Diagram : Where code runs : sandboxes per account and language, and the native process > > One API Maker process per server hands the code of each account to the sandboxes of that account : Docker containers, one kind per language, more of them while they are busy, up to the sandbox count. Code marked runOnNativeProcess runs on the machine instead, beside API Maker. The containers run privileged and without a memory limit : they guard against faulty code, not against hostile code. > **Warning : A guard against faulty code, not hostile code** > > The containers run privileged and without a memory limit : they keep API Maker running when code fails, but code which wants to can reach the server, and the secrets of the other accounts on it. Run only code you trust, and use separate servers for clients who must not see each other's data. See [the sandboxes](https://docs.apimaker.dev/v4/docs/security/overview.html#sandboxes) in the security overview. ## Languages The list on the left has one row per language, with the image its sandboxes are built from and a dot for the state of that image : green ready, amber building, red failed, grey not built yet. Select a language to edit it. ### Runtime and version - **TypeScript / JavaScript** runs on **Node.js** or **Bun**. The code does not change with the runtime. - **Each runtime has its own settings** : click a runtime to edit its version and its Dockerfile. The packages are the ones of the language, shared by its runtimes. - **Use by default** : the runtime marked with a star runs every piece of code which names no runtime. Code can [name its runtime itself](https://docs.apimaker.dev/v4/docs/languages/index.html#choosing), so one API runs on Node.js and another on Bun in the same account ; each runtime in use gets an image of its own. - **Settings use no sandbox** : the Basic Info of a custom API, the settings of APIs, schemas, the texts of internationalization and secrets are TypeScript which [API Maker runs itself](https://docs.apimaker.dev/v4/docs/languages/index.html#settings-run) when you save them. They need no runtime, no image and no packages : an account which runs its code on Bun has no image of Node.js for them. - A runtime no code names and you never opened uses its default version : nothing has to be set for it. - The **version** is picked from a list : the released versions of the official image which API Maker runs, newest first (`24` or `22.20.0` for Node.js, `3.13` for Python, `8.4` for PHP). The list is read from Docker Hub (C# : from the registry of Microsoft) and has a search field when it is long. Clear the choice for the default version. - API Maker runs the versions released after January 2023 : see [the oldest version of each runtime](https://docs.apimaker.dev/v4/docs/languages/index.html#versions). An older version is not in the list, and is refused when the settings are saved : `Python 3.10 is too old : API Maker runs Python 3.12 and later.` A version saved before, which is not offered any more, is shown as *not offered* until you pick another one. - **PHP** : only its released versions are offered (`8.4`, `8.4.12`, no release candidate). The runner of PHP loads API Maker with the FFI extension, which the official images are built without : the image of the sandboxes gets it when it is built, and the build fails rather than give a sandbox without it. - **Java and Kotlin** : the version is the one of the JDK (`25`, `21`). Kotlin runs on the JDK too, in an image of its own which gets [the compiler of Kotlin](https://docs.apimaker.dev/v4/docs/languages/kotlin.html#the-compiler) when it is built. - The image the version gives is shown next to it. Without a version : `node:24-slim`, `oven/bun:1-slim`, `python:3.13-slim`, `php:8.4-cli`, `mcr.microsoft.com/dotnet/sdk:10.0`, `golang:1.27`, `rust:1-slim`, `eclipse-temurin:25-jdk` (Java and Kotlin). ### Packages Nothing is installed unless you add it. Search the registry of the language, pick a package and a version, and **Add**. The version is one of the list or one you type (a range as `^4.17.0`) ; empty is the latest. A package can be switched off without removing it. | Language | Registry | Name | Version | |---|---|---|---| | TypeScript | npm | `lodash`, `@types/node` | `4.17.21`, `^4.17.0`, `latest` | | Python | PyPI | `requests`, `uvicorn[standard]` | `2.32.3`, `>=2,<3`, `~=2.32` | | PHP | Packagist | `guzzlehttp/guzzle` | `7.9.2`, `^7.9` | | C# | NuGet | `Newtonsoft.Json` | `13.0.3`, `13.*`, `[1.0,2.0)` | | Go | Go modules | `github.com/google/uuid` | `v1.6.0`, `1.6.0`, `latest` | | Rust | crates.io | `serde[derive]`, `tokio[rt-multi-thread,macros]` | `1`, `^1.40` | | Java | Maven Central | `com.google.code.gson:gson` (`group:artifact`) | `2.11.0`, `33.4.0-jre`, `[1.0,2.0)` | | Kotlin | Maven Central | `org.jetbrains.kotlinx:kotlinx-coroutines-core` | `1.10.2`, `[1.9,2.0)` | - PyPI and Go modules have no search : type the exact name, the versions come from the registry. - Maven Central is searched by words (`gson`), or by the whole name of a package (`com.google.code.gson:gson`). Java and Kotlin each have a list of their own. - A name or a version which can not be one is refused when you save, in words : `'requests; rm' is no name of a package of the Python Package Index…`. - While code runs nothing is downloaded : a package which is not in the list is not there. ### Dockerfile Every language has a default Dockerfile. Switch **Customize** on to write your own : it is one file with three markers API Maker fills in. **A Dockerfile of Python with a system library** ```dockerfile FROM {{AM_BASE_IMAGE}} # What your code needs from the system : built once, above the packages. RUN apt-get update && apt-get install -y --no-install-recommends libpq5 && rm -rf /var/lib/apt/lists/* {{AM_PACKAGES}} {{AM_RUNNER}} ``` | Marker | Becomes | |---|---| | `{{AM_BASE_IMAGE}}` | the image of the runtime in the version of the settings | | `{{AM_PACKAGES}}` | the tools of the registry, the folder the code runs in and your packages. PHP : the FFI extension first | | `{{AM_RUNNER}}` | the program of the sandbox, the runner of the language, and what starts them | - Order matters for the time of a build : the lines above `{{AM_PACKAGES}}` are built once, a change of packages does not install the system again, and the runner comes last. - Without `{{AM_PACKAGES}}` the packages come right before the runner; without `{{AM_RUNNER}}` the runner comes at the end. - `ENTRYPOINT` and `CMD` are API Maker's; a marker in a comment is no marker; a marker written twice is refused. - A variable the code reads (`process.env.TZ`, `os.environ['TZ']`, `getenv('TZ')`, `System.getenv("TZ")`) is an `ENV` line : `ENV TZ=UTC` above `{{AM_PACKAGES}}`. It is part of the image : keep secrets in [Secrets](https://docs.apimaker.dev/v4/docs/secrets/secrets.html). - Kotlin : `ENV AM_KOTLIN_VERSION=2.3.0` above `{{AM_PACKAGES}}` names [the compiler](https://docs.apimaker.dev/v4/docs/languages/kotlin.html#the-compiler) the image gets. - PHP : a Dockerfile which starts from another image than `{{AM_BASE_IMAGE}}` needs the FFI extension, or the tools which install it (`docker-php-ext-install`, as the official images have) : without the extension the image is not built, and the log of the build says why. - **Final Dockerfile** shows the file as it is built, with the markers filled in and the steps API Maker adds for its own library. **Reset to default** brings the default back. ### Images and sandboxes The state of the image of the language on every server : building (since when), ready (when, or *was there already* when another account built the same image), failed (the error, and **Log** for the end of the build). Below it, the sandboxes which run on the server the page asked : their port, runners, the requests running, how long they have been up and idle. - **Saving** builds the images which changed, on every server, in the background. The sandboxes of the account start anew with the new image; requests which were running finish on the old one. - **⟳** in the title of the language starts its sandboxes anew on every server, with the same image. - An image is named after what it is made of : two accounts with the same runtime, version, packages and Dockerfile share one image. Images no account uses any more are removed every hour. ## Sandbox count The most sandboxes one language of the account has at a time, on each server (1 to 5). By default one sandbox runs on a server, for the whole API Maker process : a sandbox does not belong to a thread, every thread hands its code to the same one. The first request starts it; while it is busy, another starts in the background, up to this count. Each sandbox also opens more runners of its own while all of them are busy, up to as many as the server has cores. 1 or 2 per CPU core of the server is plenty. A [separate sandbox](https://docs.apimaker.dev/v4/docs/settings/customApiSettings.html#separate-sandbox) of custom APIs has its own count. ## Time of a run Every runner gives each piece of code it is handed the time of the item the code belongs to : the first runner of a sandbox, each runner a busy sandbox opens, and the runner of the server which runs the code marked `runOnNativeProcess`. Code which needs nothing of a sandbox runs in the server itself, and is given the same time. When the time is over, the request ends with the error `API didn't respond in ms.`, and the runner which holds the code is set aside : it takes no more requests, and is ended once the other requests it runs are over, each in its own time. Only the code which did not end in time is cut short : a request which runs beside it on the same runner ends as it would have, or when its own time is over. The other runners of the sandbox go on, and the next code marked `runOnNativeProcess` meets a new runner of the server. The time a sandbox or a runner takes to start is not counted. | Code of | Its time | When it names none | |---|---|---| | a custom API, and the hooks of its versions | `customApiTimeoutInSeconds`, in seconds | `sandboxReqTimeout` of the [configuration](https://docs.apimaker.dev/v4/docs/am-resources/api-maker-configurations.html) (`13000` ms) | | the hooks of the APIs of instances, databases, tables and system APIs | the time of the request | `sandboxReqTimeout` | | an [event listener](https://docs.apimaker.dev/v4/docs/apis-all/events/user-created-events-api.html) | `eventListenerTimeoutInMinutes` | `sandboxReqTimeout` | | a [scheduler](https://docs.apimaker.dev/v4/docs/apis-all/schedulers/user-created-schedulers-api.html) | `schedulerTimeoutInMinutes` | 10 minutes | | a [migration script](https://docs.apimaker.dev/v4/docs/features/database-migration.html) | `dbMigrationTimeoutInMinutes` | 10 minutes | | a [process initializer](https://docs.apimaker.dev/v4/docs/features/process-initializers.html), in each runner it runs in | `processInitializerTimeoutInMinutes` | `sandboxReqTimeout` | - A request names a time of its own with the header [`x-am-sandbox-timeout`](https://docs.apimaker.dev/v4/docs/apis-all/header/requestHeader.html#x-am-sandbox-timeout) : it wins over `customApiTimeoutInSeconds`. - The API testing page tries a scheduler, a migration script or a process initializer with the time it runs with. - A runner whose process initializer did not end in time stops waiting for it and takes requests. - A sandbox whose last runner was set aside takes no more requests : the next request starts a new one, and the old one goes once its requests are over. ## Restart every Sandboxes start anew after this many seconds, one after the other : a new one starts first and takes the requests, the old one finishes what it runs. Use it for code which holds memory it does not give back. Empty : never. ## Allowed origins With one origin listed, a browser request from any other origin is refused with `403` before anything runs. Add the origins of your web apps. Empty : every origin. ## What is saved The settings are part of the admin user (`settings.sandbox.environments`, `sandboxCountOverrideAdmin`, `automaticSandboxRestartInSeconds`, `allowedOrigins`), so they have a history (the git button of the page) and travel with the project through [git](https://docs.apimaker.dev/v4/docs/Git/git.html). ## Related - [Languages and runtimes](https://docs.apimaker.dev/v4/docs/languages/index.html) · [Custom API settings](https://docs.apimaker.dev/v4/docs/settings/customApiSettings.html) · [Process initializers](https://docs.apimaker.dev/v4/docs/features/process-initializers.html) · [Security features](https://docs.apimaker.dev/v4/docs/features/security-features.html#allowed-origins) --- # Automatic Caching > Turn caching on for a table, a database, a custom API or a system API and API Maker answers the reads from Redis, drops the cached answers on every write through it, and lets you reset them from code or per request. Source: https://docs.apimaker.dev/v4/docs/features/automatic-caching.html Turn caching on and the reads of a table are answered from Redis, for every server of the cluster. API Maker knows when the table changes, because the writes go through it too, so it drops the cached answers itself : no stale reads, no code. > Diagram : Automatic caching : reads served from Redis, writes drop the cached answers > > Automatic caching : a read of a table with caching on is answered from Redis when the same request was answered before ; otherwise the database answers and the answer is stored. Any write to the table through API Maker drops its cached answers. A custom API with caching does the same, and resetCacheOnModificationOf ties it to the tables it reads. | | | |---|---| | Turn on | `enableCaching: true` in the [collection settings](https://docs.apimaker.dev/v4/docs/settings/collectionSettings.html) or the [database settings](https://docs.apimaker.dev/v4/docs/settings/databaseSettings.html) ; in the settings of a [custom API](https://docs.apimaker.dev/v4/docs/settings/customApiSettings.html) or a [system API](https://docs.apimaker.dev/v4/docs/settings/systemApiSettings.html). | | Key | The URL, the query, the body and the tokens of the request : two callers with different rights never share an answer, tenants never share one. | | Lifetime | Until a write of the table, or `redisValueExpireInSeconds` (7200 by default) of the [configuration](https://docs.apimaker.dev/v4/docs/am-resources/api-maker-configurations.html). Answers longer than `maxCharsResToCache` are not cached. | | Reset | A write through any API of the table ; the [reset cache system APIs](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-reset-redis-cache-db-api.html) ; the header `x-am-cache-control: reset_cache` on one request. | | See it | The [Redis dashboard](https://docs.apimaker.dev/v4/docs/logs/logs-and-dashboards.html#redis) lists the keys ; the API testing page says whether an answer came from the cache. | ## Tables - Set it on the table, or on the database for all its tables. The setting is not per API : every read of the table is cached, every write of the table resets. - Data changed outside API Maker is not seen : reset the table with [reset database cache](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-reset-redis-cache-db-api.html) from the job which changed it, or send `x-am-cache-control: reset_cache` with the next read. - Cached answers run no hook : a pre hook which scopes rows to the caller still holds, because the caller is part of the key. ## Custom APIs **Basic Info** ```typescript enableCaching: true, resetCacheOnModificationOf: [ 'DB:mongodb:shop:products', 'DB:mongodb:shop:categories' ], ``` - The answer of the API is cached per body, query and caller. `resetCacheOnModificationOf` names the tables (`DB:instance:database:table`), custom APIs (`CA:name`) and bundle versions (`TP:bundle:version`) whose writes drop it. - Without the list, reset it yourself with [reset custom API cache](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-reset-redis-cache-custom-api.html). ## System APIs - `enableCaching: true` in the settings of the system API ; reset with [reset system API cache](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-reset-redis-cache-system-api.html). ## Per request | Header | Effect | |---|---| | `x-am-cache-control: no_action` | The default : the answer comes from the cache when it is there, else it is kept there. | | `x-am-cache-control: reset_cache` | Drop the cached answers of the API, then answer from the database and cache that. | ## Related - [Request headers](https://docs.apimaker.dev/v4/docs/apis-all/header/requestHeader.html#x-am-cache-control) · [Redis dashboard](https://docs.apimaker.dev/v4/docs/logs/logs-and-dashboards.html#redis) · [Multi-tenant caching](https://docs.apimaker.dev/v4/docs/features/multi-tenant.html#caching) --- # Index Maker > Record the database queries of your APIs during a scanning period, see which ones use no index with explain, and create the missing indexes. Source: https://docs.apimaker.dev/v4/extensions/index_maker/introduction.html - Index Maker records the database queries of your APIs, groups them by the shape of their condition, and asks your database with explain whether each one uses an index. - It is in the **Index Maker** menu of the admin panel. - Since v3.3.0 it can do all of it on its own : the [automatic mode](https://docs.apimaker.dev/v4/extensions/index_maker/automatic_indexes.html) records at regular intervals, creates the indexes the slow or frequent queries of big tables need, and writes them into the migration script `am_index_maker` so every environment gets them on deploy. ## 1. Start a scanning period - Give it a name, a start and an end. - Pick what to watch: the database APIs of every instance, or of some instances, databases and tables, and system APIs. - Turn on internal queries to also record the queries API Maker runs on its own while serving a call, like deep populate and unique checks. ## 2. Use your app - While the period runs, every watched call that succeeded and did not come from the cache is recorded. - Calls are grouped by API, table, tenant and the shape of their condition: the `find` and `deep` of the query without their values. - Paging, sorting and selected fields do not split a group. ```json [ { "find": { "status": "paid", "customer_id": 42 }, "limit": 10 }, { "find": { "customer_id": 7, "status": "new" }, "sort": { "_id": -1 } } ] ``` - Both calls above are one query shape, `find { customer_id, status }`. - For each shape you see how often it ran, the rows returned, the rows saved or updated and its time, with up to 100 samples that keep the real values. ## 3. Run the index analysis - For each query shape, Index Maker runs explain on its database with a recorded sample of the query. - Each shape is marked as using a full index, part of an index, or no index. - Supported for MongoDB, MySQL, MariaDB, SQL Server, PostgreSQL and Oracle. ## 4. Create the missing indexes - **Suggestions** lists the query shapes that use no index. Each one opens the index form of its table, and **Add to script** puts the selected shapes into the migration script `am_index_maker` in one go, with the fields chosen the way the automatic mode chooses them. - The index form shows every field of the table with whether a plain index can hold it (and why not), the indexes the table already has and its size. The name is built from the fields, the same in every environment. Pick the fields and the options of your database, and create the index. For a multi-tenant API, the index goes to the database of the tenant of that query. - **Also write it to the migration script** (on by default in the form) adds the index to `am_index_maker`, so every environment which deploys the repository creates it too. | Database | Options | |---|---| | MongoDB | unique, ascending, descending, hashed, text | | MySQL, MariaDB | FULLTEXT, SPATIAL, UNIQUE, with BTREE, HASH or RTREE | | SQL Server | CLUSTERED, NONCLUSTERED, XML, SPATIAL, unique or not | | PostgreSQL | btree, hash, gist, gin, spgist, brin, unique or not, NULLS FIRST or LAST | | Oracle | unique, ASC, DESC | - Every index created or removed from API Maker is logged with its table, fields, date and source : the form, a suggestion, the automatic mode, custom code (`g.sys.system.createIndexes`) or the migration script on deploy. ## Automatic mode - Switch it on in the **Automatic indexes** panel and Index Maker starts its own scanning periods, evaluates them when they end and creates the indexes that pass its thresholds (table size, average time, number of calls). Everything it decides is written into the migration script `am_index_maker`, which can not be deleted, and every decision is kept on the period. See [Automatic indexes](https://docs.apimaker.dev/v4/extensions/index_maker/automatic_indexes.html). ## From your code - `g.sys.system.createIndexes`, `g.sys.system.dropIndexes` and `g.sys.system.getIndexes` create, drop and list indexes on any database of the account, in the same words for every database : see the [examples](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-create-indexes-api.html#from-code). ## One run from the API testing page - Run a custom API (or an event, a scheduler, a hook...) from the API testing page. Its **Index Maker** tab shows every database call of that run, with no scanning period to start. - **Summary**: what matters most in one line, then the run in numbers: the calls and their query shapes, the time in the databases and its share of the request, the rows read and written, and how many calls an index served. **What to look at** lists, the most serious first, the queries that read a whole table, a query in a loop (one table asked many times with different values), the same query asked again, a slow call, a big read, and calls that ran one after another. - **Timeline**: each call where it ran in the run, how long it took and how much of it the database took, how many calls ran at once, and the time before the first call. Click a call to see its query. - **DB Calls**: every query shape with its index use, calls, time, rows and samples, filtered by index use or searched. - **Suggestions**: the queries that use no index, the costliest first. Each one opens the index form filled from the query, which can also write the index into the migration script `am_index_maker`. - The data of a run is read once, right after the run, and then removed. ## Good to know - Each watched call adds a few writes to the database of API Maker, after its response. Run scanning periods when you need them, not all the time. - Without Index Maker too, the index list of a table on the instances page shows, creates and removes indexes. 👉 Index Maker is part of API Maker : there is nothing more to install. --- # Automatic indexes > Switch on the automatic mode of Index Maker - it records the queries of your APIs on its own, decides which slow or frequent queries on big tables deserve an index, creates it, and writes it into the migration script am_index_maker so every environment gets it on deploy. Source: https://docs.apimaker.dev/v4/extensions/index_maker/automatic_indexes.html ### Automatic indexes (v3.3.0+) - Switch the automatic mode on and Index Maker works on its own : it records the database queries of your APIs at regular intervals, asks the database with explain which ones use no index, and gives an index to the queries that are slow or frequent on tables that are big enough. - Every index it decides on goes to two places : the database of the server that decided it (optional), and the migration script **`am_index_maker`**, so every other environment creates the same index on its next deploy. - It is in the **Index Maker** menu of the admin panel : the **Automatic indexes** panel next to the scanning periods. ## The panel - **The switch** turns the mode on and off for the account (an admin or a developer account has its own periods, script and settings). - **Scan now** starts an automatic scanning period at once instead of waiting for the next one. - **Evaluate last period** runs the evaluation of the last automatic period again. - **Script** opens the entries of `am_index_maker` : remove one, open the code, run the script on this server. - **Run here** runs the script on this server, like the play button of the migrations page. - The panel shows the period recording right now, when the next one is due, the last evaluation with its decisions, and how many indexes were written and created. ## What it does, step by step 1. **Record.** A scanning period named `Automatic ` records the database APIs of every instance for `scanWindowMinutes`. It costs what a scanning period costs : a few writes to the database of API Maker after each watched call, only while it records. 2. **Explain.** When the period ends, every recorded query shape is run through `explain` on its database, like the index analysis of a scanning period. Only the shapes that use no index go on (`includePartialIndexQueries` adds the ones that use part of an index). 3. **Decide.** For every shape, in the order of the queries that matter most (calls × time) : - the collection is not in `excludedCollections` ; - the query is worth it : slower than `minAvgQueryTimeMS` on average, **or** called at least `minQueryCount` times ; - the table is big enough : `minTableRows` rows or more. The size comes from the catalog and a count bounded by `minTableRows`, so a big table is never counted to its end ; - the fields of the index : the equality fields first, then the `$in` fields, then one range or pattern field, at most `maxFieldsPerIndex`. A field of a type the database can not index (TEXT and BLOB on MySQL, json on PostgreSQL, CLOB on Oracle, `varchar(max)` on SQL Server...) is dropped ; - no existing index of the table starts with those fields, the script does not hold them already, and the table stays under `maxIndexesPerTable`. 4. **Create.** With `applyOnThisServer`, the index is created on the database of this server right away, with the name Index Maker gives it. An index the database refuses stays out of the script. 5. **Write.** The definitions are written into the JSON list of `am_index_maker`, and the script is marked "not executed" on this server so that every environment runs it on its next deploy. 6. **Keep going.** The next period starts `scanEveryMinutes` after the previous one ended. Old automatic periods are removed beyond `keepAutomaticPeriods`, with their recorded queries. Every decision is kept on the period : open it in the scanning periods grid, tab **Automatic indexes**, to see for each query shape what was decided and why (`APPLIED`, `WRITTEN`, `SMALL_TABLE`, `NOT_WORTH_IT`, `COVERED_BY_EXISTING_INDEX`, `ALREADY_IN_SCRIPT`, `TOO_MANY_INDEXES`, `NO_INDEXABLE_FIELD`, `UNSUPPORTED_SHAPE`, `EXCLUDED_COLLECTION`, `TABLE_NOT_READABLE`, `FAILED`). ## Settings - The settings are kept on the account (`settings.indexMaker`), so they travel with the project in git. A number outside its limits is brought back inside them, never refused. | Setting | Default | Limits | Meaning | |---|---|---|---| | `autoIndexEnabled` | `false` | | The master switch. Off, nothing runs on its own ; the script, the suggestions and the index form still work by hand. | | `applyOnThisServer` | `true` | | Besides the script, create the index on the database of this server as soon as it is decided. | | `scanEveryMinutes` | `360` | 5 to 43200 | A new automatic period starts this long after the previous one ended. | | `scanWindowMinutes` | `30` | 1 to 1440 | How long an automatic period records. | | `minTableRows` | `10000` | 0 to 10⁹ | A table with fewer rows gets no index : a scan of a small table is cheap and every index costs on writes. | | `minAvgQueryTimeMS` | `100` | 0 to 600000 | A query shape slower than this, on average, gets an index. | | `minQueryCount` | `50` | 1 to 10⁸ | A query shape called at least this often during the period gets an index even when it is fast : the table grows. | | `maxFieldsPerIndex` | `3` | 1 to 8 | Fields of a compound index : the equality fields first, then the ranges, the rest is dropped. | | `maxIndexesPerTable` | `12` | 1 to 64 | A table that already carries this many indexes gets no more. | | `includePartialIndexQueries` | `false` | | Also look at the shapes that use part of an index, not only the ones without any. | | `keepAutomaticPeriods` | `3` | 1 to 50 | Older automatic periods, with their recorded queries, are removed. | | `excludedCollections` | `[]` | | `instance:database:collection` patterns, `*` for any part. For a multi-tenant instance, the plain name of the instance. | | `logInternalQueries` | `false` | | Also record the queries API Maker runs on its own (deep populate, unique checks). | ## The migration script `am_index_maker` - It is a normal migration script of the account, on the **Databases migration** page, created the first time the mode is switched on (or the first time an entry is added by hand). It can not be deleted while Index Maker uses it ; remove its entries from the Index Maker page instead. - Index Maker only rewrites the JSON between the two markers. Edit the code outside them as you like, or add your own entries to the list (keep the JSON valid). - Every environment that pulls the repository runs the script on deploy. An index which exists already is reported as `EXISTS` and left alone, so the script can run again and again. A failed index is reported to the deploy after every other index of the list was created. ```ts import * as T from 'types'; // const INDEXES: T.IIndexMakerScriptEntry[] = [ { "instance": "mysql8", "database": "inventory", "collection": "orders", "name": "am_ix_orders_customer_id_status_3f9a1c", "fields": [{ "name": "customer_id" }, { "name": "status" }], "operation": "CREATE", "source": "AUTOMATIC", "reason": "Called 1,240 times, 310 ms on average, orders has 2,400,000 rows.", "addedAt": "2026-09-29T10:15:00.000Z", "scanningPeriodId": "6abbacb0bc471602b5f71099" } ]; // async function main(g: T.IAMGlobal) { const creates = INDEXES.filter(e => (e.operation || 'CREATE') === 'CREATE'); const results = await g.sys.system.createIndexes({ indexes: creates, ifNotExists: true, continueOnError: true, skipUnindexable: true, source: 'MIGRATION_SCRIPT', }); // ... DROP entries go through g.sys.system.dropIndexes, table by table } module.exports = main; ``` | Entry field | Meaning | |---|---| | `instance` | Instance name. `crm::acme` names the tenant `acme` of the multi-tenant instance `crm`. | | `database` | Database name, as the account sees it (database name masking is applied). | | `collection` or `table` | The table. PostgreSQL : `public.orders`, SQL Server : `dbo.orders`. | | `name` | Index name. Missing : Index Maker builds one (see below). | | `fields` | `[{ "name": "status", "order": "ASC" }]`. Orders : `ASC`, `DESC`, `HASHED` (MongoDB), `TEXT` (MongoDB) ; `nullsFirst: true` on PostgreSQL. | | `unique` | A unique index. | | `type` | MySQL : `FULLTEXT`, `SPATIAL` ; SQL Server : `CLUSTERED`, `XML`, `SPATIAL` ; PostgreSQL : `hash`, `gin`, `gist`, `spgist`, `brin`. Plain when missing. | | `method` | MySQL : `BTREE`, `HASH`, `RTREE`. | | `operation` | `CREATE` (default) or `DROP` (the name is enough). | | `source`, `reason`, `addedAt`, `scanningPeriodId` | Who added the entry and why ; for people, not for the database. | ### Index names - `am_ix___`, `am_ixu_` for a unique index. The same fields give the same name in every environment, so `EXISTS` is found by name first and by fields second. - The name is cut to the shortest limit of the database : 100 characters on MongoDB, 64 on MySQL and MariaDB, 128 on SQL Server, 63 on PostgreSQL, 30 on Oracle. The hash keeps cut names apart. ## By hand : suggestions and the index form - **Suggestions** of a scanning period : select the shapes and click **Add to script**. Index Maker turns each shape into a definition the way the automatic mode does (without the thresholds : you chose them) and adds it to the script. - **The index form** shows every field of the table with whether a plain index can hold it and why not, the indexes the table already has and its size. The name is built from the fields ; the switch **Also write it to the migration script** (on by default) adds the index to `am_index_maker` after creating it. - **Index logs** keep who created or dropped every index : the form (`UI`), a suggestion (`SUGGESTION`), the automatic mode (`AUTOMATIC`), custom code (`SYSTEM_API`) or the script on deploy (`MIGRATION_SCRIPT`), with the reason and the scanning period. ## From your code - The same three operations are system APIs, for custom APIs, schedulers and your own migration scripts : [createIndexes](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-create-indexes-api.html#from-code), [dropIndexes](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-drop-indexes-api.html#from-code) and [getIndexes](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-get-indexes-api.html#from-code). They are also HTTP APIs : `POST /api/system-api/user-path/create-indexes`, `/drop-indexes`, `/get-indexes`. - `createIndexes` and `dropIndexes` change the database : the APIs Security Report lists them with the other sensitive system APIs, so give them only to the groups that need them. ## Safe on every version - The statements Index Maker runs are the plain `CREATE INDEX` and `DROP INDEX` of each database, without `IF NOT EXISTS` (PostgreSQL 9.5+ only, MySQL never) : the existence check is made in code from the catalog, so the same script works on every version API Maker supports. - Identifiers are quoted on Oracle (`"INVENTORY"."am_ix_..."`) and bracketed on SQL Server (`[dbo].[orders]`), so tables with lower-case or mixed-case names work. - A field the database can not put in a plain index is `SKIPPED` before the database is asked, with the reason : TEXT and BLOB (a prefix is needed) and JSON on MySQL and MariaDB ; `text`, `ntext`, `image`, `xml`, the spatial types, `(n)varchar(max)`, `varbinary(max)` and keys over 900 bytes on SQL Server ; `json`, `xml`, the geometric types, `tsvector` on PostgreSQL ; LOBs, LONG, XMLTYPE and SDO_GEOMETRY on Oracle ; a primary key everywhere. ## Performance - Nothing changes for a request : the only cost is the recording of a scanning period while one runs, which is the cost Index Maker always had. - The loop wakes once a minute on every server, but one server of the whole cluster does the work (a Redis claim of the minute), and its tick is one small read of the accounts with the mode on. - The evaluation runs once per period, at its end. It reads the catalog of the tables, never the rows beyond `minTableRows`. 👉 Index Maker is part of API Maker : there is nothing more to install. --- # Logs and Dashboards > Watch API Maker run - log profiles which choose the calls to log, the log explorer which searches them, the servers of the cluster with their configuration, the Redis dashboard of the cache, and the ER diagram of the account. Source: https://docs.apimaker.dev/v4/docs/logs/logs-and-dashboards.html What the admin panel shows of API Maker at work : the calls it logged, the servers it runs on, its cache, and the tables it knows. ## Log profiles A log profile says which calls are written to the log database. Several profiles can be active ; a call is logged when any active profile selects its API. | | | |---|---| | Page | `Operations → Log Profile` : the profiles on the left, the tree of the account on the right. | | Selects | Tables and their APIs, custom APIs, system APIs, events, schedulers, WebSocket events. | | Per API | **Save this API's response in the log** keeps the answer next to the request. | | Active | Only active profiles log. **Clone** copies a profile ; a **default** profile can be marked. | | Read | [Log Explorer](https://docs.apimaker.dev/v4/docs/logs/logs-and-dashboards.html#log-explorer). | 1. **Add New**, give a name, check the APIs, decide per API whether the response is kept, **Save Log Profile**. 2. Make it active. From now on every call of those APIs, on every server, writes an entry : who called, from where, how long it took, the payload and the console output of your code. 3. Open the Log Explorer to search them. - Logs live in the log database of the [configuration](https://docs.apimaker.dev/v4/docs/am-resources/api-maker-configurations.html) (`logs.mongo_db_connection_logs`) and are trimmed to `maxLogsCount` by a daily job. - Log profiles go to Git. ## Log explorer `Operations → Log Explorer` is where the entries written by the [log profiles](https://docs.apimaker.dev/v4/docs/logs/logs-and-dashboards.html#log-profiles) are searched. | | | |---|---| | Columns | Time, method, status, duration, category, API and table, API user, tenant, server, client IP, user agent, request id, rows returned, payload size, size, cached response, log id. Pick the columns and the density ; save a search. | | Filters | A time window (relative or absolute), the duration between two values, a category, a status, a text ; **Exclude** removes what matches. | | One entry | The request (headers, query, path variables, payload), the response when the profile kept it, the console output of your code, the errors. **Copy this call as a cURL command**, **Copy the whole log as JSON**. | | Export | Every matching event as CSV or JSON. | | Delete | Every stored log of the account. | - The **request id** links every log of one request : copy it and search it to see the custom API and the calls it made. - **Has console output** filters the entries with `g.logger` lines. - **Log storage is not configured** means the server has no log database : set `logs.mongo_db_connection_logs`. ## Servers The **Servers** card of the dashboard of the root user lists every server of the cluster, one pill each : a server runs one process of API Maker, and the number on its pill is the threads of that process : as many as its machine has cores. Select a server to see what it runs with. It is the place to check that all servers run the same version and the same configuration after a change of `.env`. | | | |---|---| | Server information | Version of API Maker, the id of the server, the id of its process, its threads, the address it is reached at (`BE_HOST_PORT`), when it started and for how long it has run, its runtime, and the runtime and version of each language its sandboxes use. | | Platform information | Platform, machine name, home and temp folders, CPU count and model, how long the machine has been up. | | Configuration | The values it read from `package.json`, `.env`, the environment and the command line : the heap of a sandbox of Node.js, the `.env` path, the log path, the Oracle client path, logs on or off and their cleanup, the Redis expiry and largest cached answer, JWT expiry and issuer, the validity of encrypted data and of refresh tokens, the compression threshold, the body limit, the cron time zone, the most test users, the cleanup of uploaded files, the console output kept. | | DB connections | The connection pools the server has open, per instance : type, name, most connections, in use, free. | - The page asks every server through Redis and lists the ones which answer within three seconds : a server is there while its process runs. - [Schedulers](https://docs.apimaker.dev/v4/docs/apis-all/schedulers/user-created-schedulers-api.html) are spread over these servers : the Schedulers page shows the server running each one. - Learn what each value does in [API Maker configuration](https://docs.apimaker.dev/v4/docs/am-resources/api-maker-configurations.html). ## Redis dashboard `Operations → Redis Dashboard` shows the external Redis of the account : the answers cached by [automatic caching](https://docs.apimaker.dev/v4/docs/features/automatic-caching.html) and the keys your code stores with [set redis key](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-set-redis-key-api.html). | | | |---|---| | Tree | The keys grouped by their parts (account, kind, instance, database, table…) : **Expand All**, **Collapse All**, search. | | Per key | Its value and its TTL in seconds. **UpdateTTL** and the value are editable. **Delete** removes a key. | | New key | **Add New Key** : a name, a value and a TTL. Without a TTL the key lives until it is deleted. | | Flush | **Flush redis database** empties it : every cached answer and every key of yours. | | Refresh | Reloads the tree. | - A cached answer of a table reads as `…:::
:…`. Deleting it is a manual cache reset for that one request. - The internal Redis of API Maker (auto increment counters, cluster coordination) is not shown here : the [Auto Increments](https://docs.apimaker.dev/v4/docs/features/auto-increment.html) page manages the counters. ## ER diagram `Database → ER Diagram` draws the account : every active instance, its databases, their tables, and the relations the [schemas](https://docs.apimaker.dev/v4/docs/schema/schema.html#6-relations-and-virtual-fields) declare with `collection` and `column`. | | | |---|---| | Boxes | One per table, with its fields and their types, grouped by database and instance. **Expand All** and **Collapse All**. | | Lines | A relation from a field to the column of another table. Virtual fields draw the reverse. | | Marks | `PK` primary key · `AM+` auto increment by API Maker · `DB+` auto increment by the database · `R` required | | Zoom | Double click zooms in, `Shift` + double click zooms out, the mouse wheel does both. | - A table without a schema shows without relations : generate its schema to see them. ## Related - [API Maker configuration](https://docs.apimaker.dev/v4/docs/am-resources/api-maker-configurations.html) · [Automatic caching](https://docs.apimaker.dev/v4/docs/features/automatic-caching.html) · [Table schema](https://docs.apimaker.dev/v4/docs/schema/schema.html) --- # Git Integration > Your whole API Maker project in Git - branches, pull, push with a commit, status and diff of every change, revert, secrets kept out, migration scripts run after a pull, and deployment hooks for CI. Source: https://docs.apimaker.dev/v4/docs/Git/git.html Everything you build in API Maker is text : schemas, custom APIs, hooks, events, schedulers, settings, groups, test cases… API Maker keeps it in a Git repository of yours, branch by branch, and pulls it back on any other server. | | | |---|---| | Set up | **Connect a repository** on the Git page, or Profile → **User info** : the Git URL with credentials, and the email of the commit user. | | Branch | **Branches** on the Git page : a click makes a branch the **working branch**, the one commits go to and pulls come from. **New branch** from another one ; delete one from its row. | | Pull | Replaces the code of the account with the branch, then runs the [migration scripts](https://docs.apimaker.dev/v4/docs/features/database-migration.html) not yet executed here. | | Push | Shows the status, lets you compare and revert, then commits with your message. Pull requests are raised in your Git host. | | Never in Git | Secrets. | > Diagram : From a branch to live : pull request, pull, one transaction, migration scripts > > A change goes live through Git : it is committed to a branch and reviewed in a pull request, then pulled on the environment from the Git panel or a deployment hook. The pull replaces the items of the account in one MongoDB transaction, so a pull which fails changes nothing. The migration scripts not yet run on this environment run after it, in order, and the change is live. ## What goes to Git - One folder per kind in `src`, one folder per item in it, the item as YAML and its code in a file of its language : `.ts` for TypeScript, `.py` for Python, `.php`, `.cs` for C#, `.go`, `.rs` for Rust, `.java`, `.kt` for Kotlin. - Settings are always a `.ts` file, whatever language the code is written in : the Basic Info of a custom API, the settings of the APIs of a table and of a system API and a schema (`.config.ts`), the texts of internationalization and what a token generator is (`.ts`). See [settings are always TypeScript](https://docs.apimaker.dev/v4/docs/languages/index.html#basic-info). - The sandboxes of the account : `src/admin_user/data.yaml` holds the runtimes, versions, packages and variables of each language, and the Dockerfile written for a language is `src/admin_user/sandbox//Dockerfile`. - Secrets never leave the server. Each environment keeps its own, which is the point : the same code runs against another database because the secret differs. - The folder is what the [local client](https://docs.apimaker.dev/v4/docs/getting-started/local-run.html#your-code-in-your-editor-the-local-client) syncs to your disk, so the same files open in your editor. - `AGENTS.md` at the root is the guide of API Maker for AI agents (Codex, Claude Code, Cursor, Copilot) : where everything is, how code is written, the rules of security and how to fix the findings of the security report. Every commit writes its block again ; what you write around the block stays. See [AGENTS.md in your repository](https://docs.apimaker.dev/v4/docs/ai/llms.html#agents-md). **A repository with a custom API in TypeScript, one in Go and a scheduler in Python** ```text AGENTS.md the guide for AI agents package.json tsconfig.json TypeScript go.mod am/am.go am/methods.go Go : the module "apimaker" and the package your code imports pyproject.toml Python src/ custom_apis/ orders/ orders.yaml the item : name, versions, hooks (no code) orders.ts its code orders.config.ts its settings (path, method, access) : TypeScript in every language pre-hooks/check_stock.ts a hook before it stock/ stock.yaml stock.go package of its own : src/custom_apis/stock stock.config.ts pre-hooks/audit/audit.go a hook of Go is a package of its own too schedulers/ Daily_report/ Daily_report.yaml name: Daily report Daily_report.py collection_hooks/ Row_scope-customers/ Row_scope-customers.yaml the hook : its table, before or after the APIs, its place there (no code) Row_scope-customers.ts its code Check_access/ Check_access--orders/ a second hook named "Check access" : its table tells it apart schemas/ instances/ events/ web_socket_events/ utility_classes/ test_cases/ … admin_user/data.yaml ``` ### The names of the folders | What | Its folder | Example | |---|---|---| | A kind | Its name in small letters, `_` for a space | `custom_apis`, `schemas`, `instances`, `instance_api_settings`, `instance_api_hooks`, `instance_hooks`, `database_hooks`, `collection_hooks`, `system_api_settings`, `system_api_hooks`, `events`, `web_socket_events`, `schedulers`, `process_initializers`, `database_migrations`, `utility_classes`, `test_cases`, `auth_providers`, `i18ns`, `groups`, `api_users`, `log_profiles`, `api_testing_states`, `api_security_report`, `auto_increments`, `admin_user` | | An item, and the files in it | Its name ; what is no letter, digit, `.`, `-` or `_` is written `_` | The scheduler `Daily report` is `src/schedulers/Daily_report/Daily_report.py` | | A hook of an instance, a database, a table, an API of a table, a system API | A folder of its own, named by the hook | `src/collection_hooks/Row_scope-customers/Row_scope-customers.ts`, see [Hooks](https://docs.apimaker.dev/v4/docs/Git/git.html#hooks) | | A hook of a custom API, a version, a listener | The same rule, in the folder of the item | `pre-hooks/check_stock.ts`, `versions/2/Faster.ts`, `listeners/send_a_mail/send_a_mail.py` | - No folder has a space in its name : the tools of every language take the repository as it is (a folder is a package in Go, and its name is part of what code imports). - The name itself is in the YAML of the item (`name: Daily report`). Nothing is read back from the name of a folder, so two names are never mixed up by it. - Renaming an item shows as its files deleted and added under the new name. ### Hooks The hooks of an instance, a database, a table, an API of a table and a system API are a folder each, named by the name you gave the hook : `instance_hooks/`, `database_hooks/`, `collection_hooks/`, `instance_api_hooks/`, `system_api_hooks/`. The folder holds the code of the hook in its language and its YAML. **src/collection_hooks/Row_scope-customers/Row_scope-customers.yaml** ```yaml _id: 6a39057e8e907bb90f6971e7 # the hook active: true collectionName: customers # where it runs : instanceName, databaseName, collectionName, apiId databaseName: shop groupNames: [shop_app] guid: 01M5RRJ7P2SVB20TX2QA4HE78R # the hooks of the table are kept together under this guid hookType: pre # pre : before the APIs, post : after them instanceName: mongodb isActive: true name: Row scope - customers order: 1 # its place among the pre hooks of the table ``` - **Two hooks of one name.** The oldest keeps the name, the next one gets what tells it apart, then a number : `Check_access`, `Check_access--orders` (its table), `Check_access--orders--2`. A hook of a database is told apart by its database, of an instance by its instance, of an API by its table and its API (`Check_access--orders--GEN_GET_ALL`), of a system API by the API (`Check_access--GET_TOKEN`). Names are compared without case, as the disk of Windows or macOS does. A hook which is added never takes the folder of another one. - **The order** of the hooks of a list is `order` : change it there, or with the arrows of the list in API Testing. - **On your disk.** Write a folder with its YAML and its code, and the local client adds the hook to its table, at its `order` ; a YAML without `_id` is a new hook. Delete the folder of a hook and the hook goes ; a table, a database, an instance or an API whose last hook goes has no row of hooks left. Rename a hook in its YAML and the local client gets every file again : its folder moved. - A table (or any place) without hooks has no folder. ### A project of every language Besides `package.json` and `tsconfig.json`, a commit writes the file each language you use needs, with the packages of its environment in [Sandbox settings](https://docs.apimaker.dev/v4/docs/settings/sandboxSettings.html) as its dependencies, and what your code imports of API Maker as source. Open the repository in your editor and the code resolves, completes and compiles as it does in a sandbox. | Language | Written at the root | Check it yourself | |---|---|---| | TypeScript | `package.json`, `tsconfig.json`, `am-types/` | `npx tsc --noEmit` | | Python | `pyproject.toml` | `python -m compileall src` | | PHP | `composer.json` | `composer validate`, `php -l ` | | Go | `go.mod`, `am/am.go`, `am/methods.go` | `go build ./...`, `go vet ./...` | | Rust | `Cargo.toml`, `am/rust/` (the crate `am`, and `project.rs` which names every `.rs` file as a module) | `cargo check` | | C# | `ApiMaker.csproj`, `am/dotnet/` | `dotnet build` | | Java | `settings.gradle.kts`, `am/java/build.gradle.kts`, `am/jvm/am/` (what the code imports of API Maker : `G`, `Json`, `AmErrors`…) | `gradle check` | | Kotlin | `settings.gradle.kts`, `am/kotlin/build.gradle.kts`, `am/jvm/am/` | `gradle check` | - **Go : a package per folder.** Each piece of Go code is alone in its folder. Where a folder would hold two (the hooks of a list, the functions of a token generator), each is in a folder named as its file : `pre-hooks/audit/audit.go`, `users_tg/users_tg.tg/users_tg.tg.go`. The code a new item starts with says `package code` ; the sandbox builds it as a plugin whatever its package is named. A file is never named as Go reads names : `orders_test` is written `orders_test_.go`. - **C# : `file static class Api`.** A class marked `file` is known in its file only, so every file can have its own `Api` and they still compile as one project. The code a new item starts with is written that way. - **Rust** needs no care : every file is a module of the library `am/rust/project.rs` lists. - **Java and Kotlin : a folder per piece of code, a build of Gradle.** The files of a folder are compiled together, and every piece of code has its `main` (in Java, its class `Api` too). So a file which is not the only code of its folder is in a folder named as the file, as in Go : `pre-hooks/check/check.java`, `users_tg/users_tg.tg/users_tg.tg.kt`. Each folder of code is a source set of its own in the project of its language, compiled on its own with the utility classes, as a sandbox compiles it. `settings.gradle.kts` finds the projects there are : an account with code in both languages has both, and one `am/jvm/am/`. When the settings name a version of the JDK, the Java project compiles for it (`options.release`); the Kotlin project uses the plugin of Kotlin `2.4.20`, the compiler of the sandboxes. - **Utility classes resolve as in a sandbox.** A [utility class](https://docs.apimaker.dev/v4/docs/languages/index.html#utility-classes) is `src/utility_classes/---/.` (`utils---Tax/Tax.py` for the class `Tax` of the folder `utils/`), and the file of the project of its language makes the code find it by the name it imports : | Language | What the commit writes for the classes | The code | |---|---|---| | TypeScript | `tsconfig.json` : a path `utils/Tax` for each class | `import * as tax from 'utils/Tax';` | | Python | `pyproject.toml` : the folders of the classes for Pyright / Pylance, pytest and mypy | `from Tax import add` | | PHP | `composer.json` : the files of the classes under `autoload.files` | `Tax::add(100)` | | Rust | `am/rust/project.rs` : `pub mod Tax;` with the path of its file | `use crate::Tax::add;` | | Go | nothing : the folder is the package | `import tax "apimaker/src/utility_classes/utils---Tax"` | | C# | nothing : one project compiles every file | `Tax.Add(100)` | | Java, Kotlin | nothing : the project of Gradle compiles the folders of the classes together (the source set `utilities`), and every piece of code with them | `Tax.add(100)` | - `.gitignore` gets what those tools build : `/target/`, `/bin/`, `/obj/`, `/vendor/`, `/.venv/`, `__pycache__/`, `/.gradle/`, `/.kotlin/`, `/build/`, `/am/*/build/`. ### Repositories written before - A repository written by an earlier version has the kinds as they are named (`src/Custom APIs`, `src/Utility classes`) and the items by their names with spaces, and may keep code of every language in `.ts` files. It is **pulled as it is**. - The **next commit moves each kind you commit** to its folder of today and removes the old one : the status lists the files as deleted and added once. The history of an item goes on across the move. - Take the `localClient.js` of that commit : the local client of before does not know the new folders. - **Hooks in the folder of their row.** A branch written before the hooks had a folder each has the hooks of a table (an instance, a database, an API) in one folder, named by its guid or by its place (`src/collection_hooks/01M5RRJ7P2SVB20TX2QA4HE78R/pre-hooks/Row_scope-customers.ts`, `src/Collection hooks/mongodb -- shop -- customers/…`). It is pulled as it is. The status shows a hook which only moved to its own folder as no change, and a hook which changed since as modified, compared with what it was ; the next commit moves them all. - A file of code made on your disk names its language by its extension : `orders.py` in a new folder of `custom_apis` is a custom API in Python. A file of settings is read as `.ts` only : `orders.config.py` is not the settings of `orders`. ### Repositories and databases of API Maker 3 - A branch API Maker 3 wrote (`src/Custom APIs`…) is pulled as it is. The next commit writes it the way API Maker 4 does (`src/custom_apis`…). - **Hooks of API Maker 3** (`src/Collection hooks//pre-hooks/.ts`, `src/Instance API hooks/…`, `src/System API hooks//…`) are pulled with their code, their ids, their lists and their order ; a row of hooks without a hook (API Maker 3 kept many) is pulled too, and the next commit writes no folder for it. The next commit gives every hook a [folder of its own](https://docs.apimaker.dev/v4/docs/Git/git.html#hooks). - **UI Maker and third party APIs are not pulled** : API Maker 4 has neither. The folders `DB masters`, `DB master utils`, `UI maker styles`, `Third party APIs`, `Third party API settings`, and the WebSocket events of third party APIs, stay in the branch and nothing of them is saved. The pull panel lists them once the pull is over, and so does the log of the pull. The next commit removes them from the branch. - Every sandbox of API Maker 3 had npm packages of its own (`lodash`, `moment`, `crypto-js`…), which code could `require` without listing them. The ones the code of the branch takes become packages of the account, at the version API Maker 3 had. Code marked **Run on native process** finds the packages installed in the folder of the server instead : the log of the pull names the ones to install there (`npm install moment@2.29.4`). - A third party API installed from the store of API Maker 3 brought npm packages into the sandboxes of the account (`@aws-sdk/client-s3` of `aws-s3-bucket`), and its utility classes are in the branch (`utils/aws-s3-bucket/1.0.0/S3BucketUtility`). The utility classes are pulled with the others, and the packages of the third party API which the code takes become packages of the account, at the version the API had. - The enums of UI Maker which code of API Maker 3 reads (`EDBMasterFormControl.file_upload` in the `uim` of a schema property) are still there for that code : such a schema saves as it did. - Two items of a part which give one guid (a folder copied by hand : API Maker 3 could not pull such a branch either) are both pulled : the first keeps the guid, the next one gets its own, the same at every pull. The pull panel and the log of the pull name it, and the next commit writes it to the branch. - The Dockerfile of an API Maker 3 account (`src/Admin user/Dockerfile`) builds no sandbox in API Maker 4, and the next commit leaves it out. The sandboxes of API Maker 3 ran Alpine, those of API Maker 4 run Debian : a program of the system the code calls (`ping`…) goes in the Dockerfile of the JavaScript environment (`apt-get install -y iputils-ping`). - A server of API Maker 4 started on the database of an API Maker 3 installation does the same once, for every account : the packages its code takes are listed (those of its third party APIs too), and a WebSocket event whose code is in its versions only gets that code as the code which says who may connect. A pull of API Maker 3 left that code empty, so API Maker 3 never ran it. A database API Maker 3 never ran on is left as it is. ## Pull 1. Make the branch the working branch, click **Pull**. The panel shows the **Steps on the server** and a live log. 2. The items of the branch replace the ones of the account. The tag **last pulled** of a branch, and the line under the working branch, show what the account runs, also when a deployment hook or another browser pulled it. 3. The active migration scripts which never ran on this environment are listed : run them, in order. - **Pull without secret** (in the menu of the Pull button) : for a repository made on another installation, whose `passDBEncryptDecrypt` differs. The passwords of the API users can not be decrypted, so they are set to read their password from the secret (`common.apiUserPasswords.default`). Add those passwords to your secret. ## Push 1. **Check status** lists every file which differs from the branch : added, modified, deleted. Filter the list, expand all. 2. **Compare** opens one file in the compare editor ; **View all changes in one diff** shows them together. 3. **Tick** the changes to commit. A new status ticks every change except those of Auto Increments, which belong to one environment. The checkbox of a kind of item, of an item, or of the filter bar (every listed change) ticks all of its files ; a filter hides changes without unticking them. The line above the message says what the commit carries : `Commits 9 of 10 changes · Schemas 3 · API users 1 …`. 4. **Revert** puts a file back to the branch, in the account too ; **Revert N selected** puts back the ticked changes. Some files can not be reverted from here : the files written for the editors (`types/db-interfaces.d.ts`, the project files), `AGENTS.md`, the API Security Report and Auto Increments. They stay ticked. 5. Write the message and **Commit to** the working branch : the ticked changes are committed and pushed. The others stay out of the commit, and the next status still lists them. - Renaming a hook moves its folder : its two files show as deleted and added under the new name. ## The history of one item - The Git icon in the header of an item (a custom API in API Testing, a schema, a scheduler, an event, a group…) opens its **History** : the version live in the database, then every commit of the working branch which changed the item, with its author and date. **Load older versions** reads further back. - **Changes** compares the selected version with the **Previous** one, the **Database**, or a version pinned in the list ; **Full version** shows it whole. Each file of the item is a tab. - **Revert** writes the selected version into the database only : the database version shows **UNCOMMITTED** until it is committed. - **A hook** (the Git icon of a hook in API Testing, or of the form of a hook) has the history of its folder, and before it had one, of its file in the folder of its row. Its revert takes back that hook only, the other hooks of its table stay as they are. The history of the hooks of an API (the icon of the API) has the folders of all of them. ## Deployment hooks - A deployment hook is an URL of your server which pulls a branch, for a CI pipeline or the webhook of your Git host. Create it in the Git panel : a name, an access token and a secret, and the IPs allowed to call it. The name and the access token take letters, digits and `_` only ; the secret takes any character. ```text GET /api/sites/deploy//?token=&secret=&branch=main ``` - `syncMode=SYNC_WITHOUT_SECRET` pulls like the Pull Without Secret button ; `runMigrationScripts=false` skips the migration scripts. - The last callers are kept, so the panel can show where the deployments came from. ## Related - [Database migration scripts](https://docs.apimaker.dev/v4/docs/features/database-migration.html) · [Team work](https://docs.apimaker.dev/v4/docs/features/team-work.html) · [Secrets](https://docs.apimaker.dev/v4/docs/secrets/secrets.html) · [Local client](https://docs.apimaker.dev/v4/docs/getting-started/local-run.html) --- # Deploy API Maker > Upgrade API Maker v4 on every server of the cluster from the admin panel, from npm or from an uploaded package, with live progress for each server and an automatic way back. Source: https://docs.apimaker.dev/v4/docs/features/deploy-api-maker.html - Install another version of API Maker on every server of the cluster from the **Deploy API Maker** page of the admin panel. - This page upgrades API Maker itself. To deploy your APIs, use a Git pull. Learn more [Git](https://docs.apimaker.dev/v4/docs/Git/git.html). > Diagram : Deploy API Maker v4 : admin panel → Caddy → API Maker → Redis → every server installs the package of its machine (5 stages, live progress) → systemd starts it, wait for the new version, reload > > How Deploy API Maker upgrades a cluster of API Maker v4 : the admin panel sends the chosen version, or an uploaded package, through Caddy to API Maker, which sends it through Redis to every server. Each server gets the package of its own machine from npm (its SHA-512 checked) or takes the uploaded one, unpacks it next to the running version, checks its program, moves the current link to it and is started on it by systemd; a watchdog goes back to the version which ran before when the new one does not answer. Every stage is reported live over the WebSocket. When every server is done the page waits until they answer on the new version and reloads. A server which fails keeps its version and the page says why. ## Two ways - **Deploy from NPM**: pick a published version and click **Deploy**. Every server downloads the package of its own machine (`@sava-info-systems/api-maker-engine-linux-x64` or `-linux-arm64`) from the npm registry and checks its SHA-512 before anything is installed. A cluster of x64 and arm64 servers is upgraded in one go. - **Upload a package**: select the `.tgz` of a version (the npm package of one machine), or the `.tar.gz` of a release, up to 512 MB, and click **Upload**. The page sends it in pieces of 4 MB, a request each, so a slow connection or a package of more than 100 MB is no problem; a piece whose request fails on the way is sent again. The pieces wait in the Redis of the installation for an hour, every server reads the package from there, and each one checks its SHA-256 before using it. A server of another machine refuses it. ## What happens on each server 1. The package is downloaded (its SHA-512 checked) or received (its SHA-256 checked). 2. It is unpacked next to the running version, into `~/projects/api_maker/releases/`. 3. Its program is checked : built for this machine, and it starts (`api_maker_be --version`). 4. The `current` link moves to it, all at once. The 3 newest versions are kept, the older ones removed. 5. systemd starts API Maker on the new version. A watchdog outside of API Maker waits for it to answer; when it does not answer within two and a half minutes, `current` goes back to the version which ran before and that one is started again. The server which took the request from the page restarts last, once every server has answered, so the page gets the result of each server. - `.env`, `license.txt`, the uploads and the logs are outside of the versions : nothing has to be kept aside. - The page shows a card per server and the live progress of each stage, then waits until every server answers on the new version and reloads. - A server which fails keeps the version it runs, and the page says why : deploy again once the cause is gone. ## Good to know - The page works on servers installed by the installer of API Maker v4 and run by systemd. A server laid out otherwise refuses and is upgraded by running the [installer](https://docs.apimaker.dev/v4/docs/getting-started/install-on-server.html) again with the version. - Versions of the Node.js edition (v1 to v3) are not deployed from here : the installer moves a server to v4. - A deployment waits up to 20 minutes for the servers to finish. - If the WebSocket connection of the page is down, the deployment keeps running and the page reports the result when it ends. --- # Team Work > Several developers on one API Maker project - one account per developer with its own user path, secrets and branch, database names masked per developer, the code finder across every piece of code, and the compare editor before a push. Source: https://docs.apimaker.dev/v4/docs/features/team-work.html A team shares one Git repository. Each developer works in an account of their own, on databases of their own, and pushes to a branch for a pull request. Four tools of the admin panel make that easy. ## Developer accounts One admin user per developer. Each developer signs in with their own account, pulls the branch of the team, works, and pushes. The APIs of each account answer under its own user path. | | | |---|---| | Who creates them | The root user, on the **Accounts** page : name, email, API path, password, active. **Insert Default Data** (checked by default) adds sample custom APIs, schemas, hooks and migration scripts ; the default secret, group and API user are made either way. **Clone** copies one. | | Unique | The API path and the email. | | Own to each account | Its secrets, its Git branch and credentials, its masked database names, its sandbox processes, its Redis cache. | | Shared | The Git repository, and through it every item of the project. | | From a script | The [management API](https://docs.apimaker.dev/v4/docs/am-resources/operate-api-maker-using-api.html) creates, changes and deletes admin users. | A developer joins : 1. The root user creates the account and gives the credentials. 2. The developer sets the Git URL and commit email in their **User info**, pulls the branch of the team, and adds the connection strings and keys of their own databases to their secret. 3. When the database names of their machine differ from the ones in the code, they [mask](https://docs.apimaker.dev/v4/docs/features/team-work.html#mask-database-names) them. 4. They work under `/api/…//…`, test with their own API users, and push to a branch of their own for a pull request. ## Mask database names The code names the databases the way production does : `shop`. On a developer machine the same database may be `shop_dev`, or two developers may share one server with `shop_alice` and `shop_bob`. Masking maps one to the other, for one account, so nobody edits a database name before a pull request. | | | |---|---| | Where | Profile → **User info** → masked databases : instance, database name, masked database name. | | Scope | The account of the developer only. Git, schemas, settings and code keep the name of the project. | | Effect | Every API, hook, migration and query of the account runs on the masked name : the name in the URL and in the code stays the one of the project. | | Instance | Database name (in the code) | Masked database name (on this server) | |---|---|---| | `mysql8` | `shop` | `shop_alice` | - Add one row per database whose name differs. Names not listed are used as they are. - Table meta, migrations, and plain queries which name the database in the API also go through the mapping ; SQL text you write yourself does not. ## Code finder `APIs & Logic → Code Finder` searches a word in all the code of the account at once, and opens the hit for editing. | | | |---|---| | Searches | Custom APIs (their settings and every version), the pre and post hooks of instances, databases, tables, APIs and system APIs, events and listeners, schedulers, WebSocket events, migration scripts, process initializers, auth providers, utility classes, the settings of APIs, databases and tables, internationalizations, schemas, secrets, and the text files of [SSR websites](https://docs.apimaker.dev/v4/docs/ssr/index.html) : in every language the code is written in. | | Whose code | The account you are signed in with. | | Result | The item, its kind and where it lives (instance, database, table, API, version…), with the code open. | | Edit | Change the code in the result and **Save changes** : no need to open the page of the item. | 1. Type a word and press `Enter`. The options make the search case sensitive. 2. Each hit names its kind (custom API, hook and its type, listener, scheduler, secret, utility class…) and where it is. 3. Open a hit, edit, save. - Use it before renaming a field or a table : every custom API, hook and schema which names it shows up. - A piece of code is also found by its name (a scheduler, a listener, the table of a schema…), a file of a website by its path (`pages/blog`). - A file of an SSR website opens as its website shows it : TSX, with the types of `am-ssr` and the imports of its other files. **Save changes** compiles it and the website takes it at once ; **Open** shows the file in its website. ## Compare code The Git panel lists every item the account changed since the last pull, with its kind of change, and opens each one in a compare editor. | | | |---|---| | Where | The Git panel → **Git status of commit**. | | Per file | **Compare** or **Open in compare editor** : the version of the branch next to the version of the account, the differences highlighted line by line. | | All at once | **View all changes in one diff**. | | Undo | **Revert** puts the file back to the branch ; several files at once with **Revert selected**. | - The versions of a custom API, a hook or a listener are files of the item in Git, so a change of version shows in the same list. ## Related - [Git integration](https://docs.apimaker.dev/v4/docs/Git/git.html) · [Secrets](https://docs.apimaker.dev/v4/docs/secrets/secrets.html) · [Developer tools](https://docs.apimaker.dev/v4/docs/features/developer-tools.html) --- # Internationalization > Answer the errors and messages of API Maker in the language of the caller - an i18n item maps every message to its translation, and the header x-am-internationalization picks it per request. Source: https://docs.apimaker.dev/v4/docs/i18/i18.html An i18n item is a dictionary : the messages of API Maker and of your custom APIs on the left, their text in a language on the right. A request names the item in a header and gets its errors and messages translated. | | | |---|---| | Page | `APIs & Logic → i18N Management` : a name and a TypeScript file which exports the dictionary. | | Header | `x-am-internationalization: ` (its id works too). Without it, the messages are the ones of API Maker. | | Translates | The constant errors of API Maker (validation, authorization, not found…), the `errorList` of your [custom APIs](https://docs.apimaker.dev/v4/docs/settings/customApiSettings.html). | | Placeholders | A constant error keeps its `{field}`, `{value}`… placeholders in the translation. | ## 1. Create the item **hindi** ```typescript module.exports = { // constant errors of API Maker : keep the placeholders "Please provide valid '{field}' field with type '{type}'.": "कृपया '{field}' फ़ील्ड का सही मान दें ({type}).", "You are not authorized to access this API.": "आपको इस API की अनुमति नहीं है।", // the errorList of your custom APIs "Unable to process this request.": "यह अनुरोध पूरा नहीं हो सका।", }; ``` - The page lists the constant messages of API Maker to start from, and every message named in the `errorList` of a custom API. ## 2. Throw the message **TypeScript** **Custom API** ```typescript throw new Error('Unable to process this request.'); ``` ## 3. Ask for the language ```text POST /api/custom-api/admin/customers x-am-internationalization: hindi ``` ```json { "success": false, "statusCode": 500, "errors": [ { "code": 500, "message": "यह अनुरोध पूरा नहीं हो सका।" } ], "warnings": [] } ``` - A message the item does not have is answered as it is. - i18n items go to Git. ## Related - [Custom API settings](https://docs.apimaker.dev/v4/docs/settings/customApiSettings.html) · [Request headers](https://docs.apimaker.dev/v4/docs/apis-all/header/requestHeader.html) · [Error codes](https://docs.apimaker.dev/v4/docs/apis-all/error-codes.html) (The code of this page is also written in Python, PHP, C#, Go, Rust, Java, Kotlin : https://docs.apimaker.dev/v4/docs/i18/i18.md) --- # Operate API Maker Using API > Create, change and delete admin accounts of API Maker, and change their default secret, from a script - one route of the server, a communication token, four operations with their payloads, answers and errors. Source: https://docs.apimaker.dev/v4/docs/am-resources/operate-api-maker-using-api.html A script or another system can create the admin accounts of API Maker, change them, delete them and change their default secret, without the admin panel. A hosting company gives each client an account this way, for example. ## Turn it on 1. **Open the setting** **Root Settings → Deployment Settings → API Access**, and tick **Operate API Maker Using API**. 2. **Set the communication token** 48 characters at least : **Generate** makes one. 3. **Save** The route answers from now on. > **Warning : The token is the only key** > > The route asks for no session and no other token : whoever has the communication token can create and delete accounts. Keep it in a secret store, send it over HTTPS only, and change it when it may have leaked. A new token ends the integrations which use the old one at once. ## The route ```text POST https://api.example.com/api/sites/root-user-settings/operate-api-maker-using-api Content-Type: application/json ``` | Field of the body | What it is | |---|---| | `token` | The communication token, a text of 48 characters or more. | | `operation` | `CREATE_ADMIN_USER`, `UPDATE_ADMIN_USER`, `DELETE_ADMIN_USER` or `UPDATE_SECRET`. | | `payload` | An object : what the operation needs, below. | ## Create an account `CREATE_ADMIN_USER` creates an admin account. It also pulls its Git repository when one is given, saves its secret, and makes its deployment hook : the answer holds all four. ```json { "token": "aBcDe_FgHiJ_KlMnO_PqRsT_UvWxY_ZaBcD_EfGhI_JkLmN_OpQrS", "operation": "CREATE_ADMIN_USER", "payload": { "user": { "name": "John Doe", "email": "john@example.com", "password": "securePassword123", "apiPath": "john_doe", "gitUrlWithCredentials": "https://username:access_token@github.com/username/repo.git", "gitCommitUserEmail": "john@example.com", "gitBranch": "main" }, "secret": { "name": "Default", "keysCode": "" } } } ``` | Field of `payload.user` | Rule | |---|---| | `name` | Required, a text. | | `email` | Required, a valid email, not used by another account. | | `password` | Required, 4 characters at least. Sent plain : API Maker encrypts it before it stores it. | | `apiPath` | Required, unique : `a-z`, `0-9`, `_` and `-`. The path of the APIs of the account : `/api/schema/john_doe/…`. | | `gitUrlWithCredentials` | Optional : the repository, with its credentials in the URL. Stored encrypted. | | `gitCommitUserEmail`, `gitBranch` | Optional : the email of its commits, and its branch. | | `insertDefaultData` | Optional, `true` by default. `false` leaves out the sample data of a new account (custom APIs, schemas, hooks, migration scripts) ; its default group and API user are made either way. | `payload.secret` is optional : `name` (required in it, `Default`) and `keysCode`, the TypeScript of the [secret](https://docs.apimaker.dev/v4/docs/secrets/secrets.html). **Answer** ```json { "success": true, "statusCode": 200, "data": { "userResponse": { "guid": "01KP2MCKX5DNBGM7RCAASM3BMQ", "name": "John Doe", "email": "john@example.com", "apiPath": "john_doe", "gitCommitUserEmail": "john@example.com", "gitBranch": "main", "userType": "ADMIN", "active": true, "_id": "69dc7c7ead52c49d2086d81e" }, "gitPullResponse": true, "secretSaveResponse": true, "deploymentHookResponse": { "hookUrl": "6MgUnOSSqR36JTU9M7LON4BcbSvwxn4r", "hookAccessToken": "ASIQ4BJOHDl9RRUE5DH6cIuyvCUJQwCM", "hookSecret": "lIfV52PsStG3Nq4Wx2tWqmFd3uL0QOSU", "deploymentUrl": "http://__ip_address__:38246/api/sites/deploy/john_doe/6MgUnOSSqR36JTU9M7LON4BcbSvwxn4r?token=ASIQ4BJOHDl9RRUE5DH6cIuyvCUJQwCM&secret=lIfV52PsStG3Nq4Wx2tWqmFd3uL0QOSU&branch=main" } } } ``` - `userResponse` is the account, without its password and its Git credentials. - `gitPullResponse` and `secretSaveResponse` say whether the pull and the secret worked. - `deploymentHookResponse` is the [deployment hook](https://docs.apimaker.dev/v4/docs/Git/git.html) of the account. In `deploymentUrl`, put the address of your server in place of `__ip_address__`. It carries the token and the secret of the hook : keep it out of client code. ## Change an account `UPDATE_ADMIN_USER` finds the account by its `apiPath` and changes the fields of `updateData`. The fields left out stay as they are, the password too. ```json { "token": "aBcDe_FgHiJ_KlMnO_PqRsT_UvWxY_ZaBcD_EfGhI_JkLmN_OpQrS", "operation": "UPDATE_ADMIN_USER", "payload": { "find": { "apiPath": "john_doe" }, "updateData": { "name": "John Doe", "email": "john.doe@example.com", "password": "newPassword123", "gitBranch": "main" } } } ``` - `find.apiPath` is required : the `apiPath` of the account as it is now. - `updateData` takes the fields of `payload.user` above, with the same rules, one of them at least. A new `apiPath` changes the path of every API of the account. - The answer is the account as it is after the change, in `data`. ## Delete an account `DELETE_ADMIN_USER` deletes the account of an `apiPath`, and everything it owns. > **Danger** > > There is no undo : the account and all its data are gone. ```json { "token": "aBcDe_FgHiJ_KlMnO_PqRsT_UvWxY_ZaBcD_EfGhI_JkLmN_OpQrS", "operation": "DELETE_ADMIN_USER", "payload": { "apiPath": "john_doe" } } ``` The answer is `{ "success": true, "statusCode": 200, "data": true }`. ## Change the secret of an account `UPDATE_SECRET` replaces the TypeScript of the default secret of the account of an `apiPath`. ```json { "token": "aBcDe_FgHiJ_KlMnO_PqRsT_UvWxY_ZaBcD_EfGhI_JkLmN_OpQrS", "operation": "UPDATE_SECRET", "payload": { "apiPath": "john_doe", "keysCode": "your-secrets-code-here" } } ``` Both fields are required. The answer is `{ "success": true, "statusCode": 200, "data": true }`. ## Errors | Status | Message | When | |---|---|---| | `401` | `Unauthorized. Invalid communication token.` | The token is not the one of the settings. | | `403` | `Operate API Maker using API feature is not enabled.` | The setting is off. | | `403` | `Please set communication token from root user settings.` | The setting is on, without a token. | | `404` | `User not found with apiPath : ''` | `UPDATE_ADMIN_USER` or `UPDATE_SECRET` for an `apiPath` no active account has. `Default secret not found in the system` : the account has no default secret. | | `400` | `User already exists with apiPath : ''` | `CREATE_ADMIN_USER` for an `apiPath` an active account has. | The answer of an error is the usual envelope : `{ "success": false, "statusCode": 401, "errors": [ { "message": "…" } ] }`. ## Related - [API Maker configuration](https://docs.apimaker.dev/v4/docs/am-resources/api-maker-configurations.html) · [Secret Management](https://docs.apimaker.dev/v4/docs/secrets/secrets.html) · [Git integration](https://docs.apimaker.dev/v4/docs/Git/git.html) --- # MongoDB Connection Strings > The MongoDB connection strings API Maker takes - mongodb:// and mongodb+srv://, replica sets, MongoDB Atlas, TLS - with examples, how to add one to an instance, and the common errors. Source: https://docs.apimaker.dev/v4/docs/Database-connection-string/mongodb-connection-strings.html API Maker connects to MongoDB with the official driver of MongoDB, so it takes the connection strings of the [MongoDB manual](https://www.mongodb.com/docs/manual/reference/connection-string/), with their options. ## The format ```text mongodb://user:password@host:port/?option=value&option=value mongodb+srv://user:password@cluster.example.net/?option=value ``` | Part | What it is | |---|---| | `mongodb://` | The hosts written out, one or several : `db1:27017,db2:27017`. | | `mongodb+srv://` | One name which DNS turns into the hosts. MongoDB Atlas gives this form. | | `user:password@` | The user and its password. Write the password as it is, even with `@` or `:` in it : API Maker encodes it before it connects. | | `host:port` | `27017` when no port is given. | | `?options` | Options of the driver : `authSource`, `replicaSet`, `directConnection`, `tls`, `readPreference`, `w`, `maxPoolSize`… | A database in the path only says where the user is defined, when `authSource` does not. An instance reaches every database its user may read. ## Examples ```text # 1. A MongoDB on the same computer, without users mongodb://127.0.0.1:27017 # 2. One member of a replica set, reached directly mongodb://user:password@127.0.0.1:27017/?authSource=admin&replicaSet=rs0&directConnection=true # 3. A replica set of three servers mongodb://user:password@db1.example.com:27017,db2.example.com:27017,db3.example.com:27017/?authSource=admin&replicaSet=rs0 # 4. MongoDB Atlas mongodb+srv://user:password@cluster0.abcde.mongodb.net/?retryWrites=true&w=majority # 5. TLS, with the certificate of your own authority mongodb://user:password@db.example.com:27017/?authSource=admin&tls=true&tlsCAFile=/root/certs/ca.pem ``` ## Add it to API Maker An instance never holds the connection string itself : it names a key of your [default secret](https://docs.apimaker.dev/v4/docs/secrets/secrets.html), where the string stays encrypted, out of Git. 1. **Put the string in the secret** **Security → Secret Management** → `Default`. Add it under `common.connectionString`, with a name of your choice, and save. 2. **Create the instance** **APIs & Logic → Instance API (DB API)** → add an instance : pick the database type, give it a name, and pick the key of the secret under **Connection**. 3. **Test it** **Test Instance** connects with the string. An instance which can not reach its database is not saved, and the form says why. **Connection String Sandbox** is optional : a second key, for code which runs in a sandbox and reaches the database by another address than API Maker does. ## Common errors | What you see | What to check | |---|---| | `Authentication failed` | The user, the password, and `authSource` : the database the user was created in, often `admin`. | | `Server selection timeout` | API Maker can reach the server : the firewall, and `bindIp` in `mongod.conf`. A replica set answers with the names of its members : API Maker must reach those names too, or add `directConnection=true` to talk to one member only. | | A timeout with MongoDB Atlas | The address of your API Maker server is in the IP access list of the cluster. | | An error about the replica set | `replicaSet` is the name of the replica set, as `rs.status()` shows it. | ## Related - [Secret Management](https://docs.apimaker.dev/v4/docs/secrets/secrets.html) · [Your first API](https://docs.apimaker.dev/v4/docs/getting-started/first-api.html) · [Connection strings in the MongoDB manual](https://www.mongodb.com/docs/manual/reference/connection-string/) --- # MySQL Connection Strings > The MySQL connection strings API Maker takes, for MySQL, Percona Server and TiDB - the five parts it reads, examples, how to add one to an instance, and the common errors. Source: https://docs.apimaker.dev/v4/docs/Database-connection-string/mysql-connection-strings.html This page also serves Percona Server and TiDB, which speak the protocol of MySQL. MariaDB has [its own page](https://docs.apimaker.dev/v4/docs/Database-connection-string/mariadb-connection-strings.html). ## The format ```text mysql://user:password@host:port/database ``` | Part | What it is | |---|---| | `mysql://` | `mariadb://` works too. | | `user:password@` | The user and its password. Write the password as it is, even with `@` or `:` in it : API Maker encodes it before it connects. | | `host:port` | `3306` when no port is given. TiDB listens on `4000`. | | `/database` | Optional : the database a connection starts in. An instance reaches every database its user may read. | API Maker reads the user, the password, the host, the port and the database, and nothing else : options after `?` are not read (`?multipleStatements=true` in the sample secret changes nothing). > **Warning : No TLS to MySQL and MariaDB** > > API Maker v4 connects to MySQL, MariaDB, Percona Server and TiDB without TLS. Keep the database on the same server or on a private network, or reach it through an SSH tunnel or a VPN. A server which requires TLS (`require_secure_transport=ON`, the default of some managed services) refuses the connection. ## Examples ```text # 1. MySQL on the same server mysql://root:password@127.0.0.1:3306 # 2. A database to start in mysql://app:password@10.0.0.5:3306/inventory # 3. A password with special characters, written as it is mysql://app:p@ss:w0rd!@10.0.0.5:3306/inventory # 4. Percona Server mysql://app:password@10.0.0.6:3306 # 5. TiDB mysql://root:password@10.0.0.7:4000 ``` ## Add it to API Maker An instance never holds the connection string itself : it names a key of your [default secret](https://docs.apimaker.dev/v4/docs/secrets/secrets.html), where the string stays encrypted, out of Git. 1. **Put the string in the secret** **Security → Secret Management** → `Default`. Add it under `common.connectionString`, with a name of your choice, and save. 2. **Create the instance** **APIs & Logic → Instance API (DB API)** → add an instance : pick the database type, give it a name, and pick the key of the secret under **Connection**. 3. **Test it** **Test Instance** connects with the string. An instance which can not reach its database is not saved, and the form says why. **Connection String Sandbox** is optional : a second key, for code which runs in a sandbox and reaches the database by another address than API Maker does. ## Common errors | What you see | What to check | |---|---| | `Access denied for user 'app'@'10.0.0.2'` | The password, and a user allowed from the address of API Maker : `CREATE USER 'app'@'10.0.0.2'`, or `'app'@'%'`. | | A timeout, or the connection refused | The server listens on the network (`bind-address`), the firewall lets API Maker in, the port is right. | | `Invalid URL : …` | The string starts with `mysql://` or `mariadb://` and names a host. | | The server asks for TLS | Not supported, see above. | ## Related - [Secret Management](https://docs.apimaker.dev/v4/docs/secrets/secrets.html) · [MariaDB connection strings](https://docs.apimaker.dev/v4/docs/Database-connection-string/mariadb-connection-strings.html) · [Execute plain query](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-execute-plain-query-api.html) --- # MariaDB Connection Strings > The MariaDB connection strings API Maker takes - the five parts it reads, examples for one server and a Galera cluster, how to add one to an instance, and the common errors. Source: https://docs.apimaker.dev/v4/docs/Database-connection-string/mariadb-connection-strings.html MariaDB takes the same connection strings as [MySQL](https://docs.apimaker.dev/v4/docs/Database-connection-string/mysql-connection-strings.html), with `mariadb://` or `mysql://` in front. ## The format ```text mariadb://user:password@host:port/database ``` | Part | What it is | |---|---| | `mariadb://` | `mysql://` works too. | | `user:password@` | The user and its password. Write the password as it is, even with `@` or `:` in it : API Maker encodes it before it connects. | | `host:port` | `3306` when no port is given. | | `/database` | Optional : the database a connection starts in. An instance reaches every database its user may read. | API Maker reads the user, the password, the host, the port and the database, and nothing else : options after `?` are not read (`?multipleStatements=true` in the sample secret changes nothing). > **Warning : No TLS to MySQL and MariaDB** > > API Maker v4 connects to MySQL, MariaDB, Percona Server and TiDB without TLS. Keep the database on the same server or on a private network, or reach it through an SSH tunnel or a VPN. A server which requires TLS (`require_secure_transport=ON`, the default of some managed services) refuses the connection. ## Examples ```text # 1. MariaDB on the same server mariadb://root:password@127.0.0.1:3306 # 2. A database to start in mariadb://app:password@10.0.0.5:3306/inventory # 3. Another port mariadb://app:password@10.0.0.5:3308/inventory # 4. One node of a Galera cluster mariadb://app:password@10.0.0.11:3306/inventory # 5. A password with special characters, written as it is mariadb://app:p@ss:w0rd!@10.0.0.5:3306/inventory ``` A connection string names one server. For a Galera cluster, give API Maker the address of one node, or of a load balancer in front of the nodes. ## Add it to API Maker An instance never holds the connection string itself : it names a key of your [default secret](https://docs.apimaker.dev/v4/docs/secrets/secrets.html), where the string stays encrypted, out of Git. 1. **Put the string in the secret** **Security → Secret Management** → `Default`. Add it under `common.connectionString`, with a name of your choice, and save. 2. **Create the instance** **APIs & Logic → Instance API (DB API)** → add an instance : pick the database type, give it a name, and pick the key of the secret under **Connection**. 3. **Test it** **Test Instance** connects with the string. An instance which can not reach its database is not saved, and the form says why. **Connection String Sandbox** is optional : a second key, for code which runs in a sandbox and reaches the database by another address than API Maker does. ## Common errors | What you see | What to check | |---|---| | `Access denied for user 'app'@'10.0.0.2'` | The password, and a user allowed from the address of API Maker : `CREATE USER 'app'@'10.0.0.2'`, or `'app'@'%'`. | | A timeout, or the connection refused | The server listens on the network (`bind-address`), the firewall lets API Maker in, the port is right. | | `Invalid URL : …` | The string starts with `mysql://` or `mariadb://` and names a host. | | The server asks for TLS | Not supported, see above. | ## Related - [Secret Management](https://docs.apimaker.dev/v4/docs/secrets/secrets.html) · [MySQL connection strings](https://docs.apimaker.dev/v4/docs/Database-connection-string/mysql-connection-strings.html) · [Execute plain query](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-execute-plain-query-api.html) --- # PostgreSQL Connection Strings > The PostgreSQL connection strings API Maker takes - the parts it reads, TLS with sslmode and your own certificate authority, examples, how to add one to an instance, and the common errors. Source: https://docs.apimaker.dev/v4/docs/Database-connection-string/postgres-connection-strings.html ## The format ```text postgresql://user:password@host:port/database?sslmode=require ``` | Part | What it is | |---|---| | `postgresql://` | `postgres://` works too. | | `user:password@` | The user and its password. Write the password as it is, even with `@` or `:` in it : API Maker encodes it before it connects. Do not encode it yourself. | | `host:port` | `5432` when no port is given. | | `/database` | The database a connection starts in. | | `?options` | The TLS options below. API Maker reads no other option. | ## TLS A connection string which says nothing of TLS connects without it. | Option | Effect | |---|---| | `sslmode=require`, `verify-ca` or `verify-full`, or `ssl=true` | TLS, and the certificate of the server is checked : its authority and its name. | | `sslrootcert=/path/ca.pem` | Trust this authority in place of the public ones : the file a managed service gives you, or your own. | | `sslcert=/path/client.pem&sslkey=/path/client.key` | A certificate of the client, when the server asks for one. | | `sslmode=no-verify` | TLS without the check. For tests only. | | `sslmode=disable` | No TLS. | `require` checks the certificate, as the `pg` package of Node.js does. Add `uselibpqcompat=true` for the meaning of libpq, where `require` encrypts without checking. ## Examples ```text # 1. PostgreSQL on the same server postgresql://postgres:password@127.0.0.1:5432/postgres # 2. A database of an application postgresql://app:password@10.0.0.5:5432/inventory # 3. A managed service, its certificate checked postgresql://app:password@db.example.com:5432/inventory?sslmode=require # 4. Your own certificate authority postgresql://app:password@db.internal:5432/inventory?sslmode=verify-full&sslrootcert=/root/certs/ca.pem # 5. A password with special characters, written as it is postgresql://app:p@ss:w0rd!@10.0.0.5:5432/inventory ``` ## Add it to API Maker An instance never holds the connection string itself : it names a key of your [default secret](https://docs.apimaker.dev/v4/docs/secrets/secrets.html), where the string stays encrypted, out of Git. 1. **Put the string in the secret** **Security → Secret Management** → `Default`. Add it under `common.connectionString`, with a name of your choice, and save. 2. **Create the instance** **APIs & Logic → Instance API (DB API)** → add an instance : pick the database type, give it a name, and pick the key of the secret under **Connection**. 3. **Test it** **Test Instance** connects with the string. An instance which can not reach its database is not saved, and the form says why. **Connection String Sandbox** is optional : a second key, for code which runs in a sandbox and reaches the database by another address than API Maker does. ## Common errors | What you see | What to check | |---|---| | `password authentication failed for user "app"` | The user and the password. | | `no pg_hba.conf entry for host "10.0.0.2"` | Add the address of API Maker to `pg_hba.conf`, then reload PostgreSQL. | | A timeout, or the connection refused | `listen_addresses` in `postgresql.conf`, the firewall, the port. | | `self-signed certificate` or `unable to verify the first certificate` | Give the authority with `sslrootcert`. `sslmode=no-verify` skips the check, for tests only. | ## Related - [Secret Management](https://docs.apimaker.dev/v4/docs/secrets/secrets.html) · [Execute plain query](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-execute-plain-query-api.html) · [Connection strings in the PostgreSQL manual](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING) --- # Oracle Connection Strings > How API Maker connects to Oracle - a connect string, a username and a password kept as three keys of the secret, Easy Connect examples, the privilege of an instance, and the common errors. Source: https://docs.apimaker.dev/v4/docs/Database-connection-string/oracledb-connection-strings.html An Oracle instance takes three keys of the secret : the connect string, the username and the password. The connect string goes to the client libraries of Oracle as it is, so it can be an Easy Connect string, the name of an entry of `tnsnames.ora`, or a whole connect descriptor. ## The format **In the default secret** ```typescript connectionString: { oracle: 'host:port/service_name', oracle_username: 'app', oracle_password: 'password', }, ``` | Part | What it is | |---|---| | `host:port` | The server, `1521` when no port is given. | | `/service_name` | The service of the database : a pluggable database such as `ORCLPDB1`, or `FREEPDB1` of Oracle Free. | | The username and the password | Two other keys of the secret. Any names work : you pick them on the instance form. | The **Privilege** of the instance (`SYSDBA`, `SYSOPER`…) is a setting of the instance, not of the secret. ## Examples ```text # 1. Oracle Free on the same server 127.0.0.1:1521/FREEPDB1 # 2. A pluggable database 10.0.0.5:1521/ORCLPDB1 # 3. A listener on another port 10.0.0.5:1522/ORCLPDB1 # 4. A whole connect descriptor (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=10.0.0.5)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCLPDB1))) # 5. An Oracle RAC through its SCAN address scan.example.com:1521/sales.example.com ``` ## Add it to API Maker An instance never holds the connection string itself : it names a key of your [default secret](https://docs.apimaker.dev/v4/docs/secrets/secrets.html), where the string stays encrypted, out of Git. 1. **Put the string in the secret** **Security → Secret Management** → `Default`. Add it under `common.connectionString`, with a name of your choice, and save. 2. **Create the instance** **APIs & Logic → Instance API (DB API)** → add an instance : pick the database type, give it a name, and pick the key of the secret under **Connection**. 3. **Test it** **Test Instance** connects with the string. An instance which can not reach its database is not saved, and the form says why. **Connection String Sandbox** is optional : a second key, for code which runs in a sandbox and reaches the database by another address than API Maker does. For Oracle, the form asks for three keys of the secret, the connect string, the username and the password, and for the privilege. ## Common errors | What you see | What to check | |---|---| | `ORA-01017: invalid username/password` | The username and the password keys, and the privilege of the instance. | | `ORA-12514` : the listener does not know the service | The service name : `lsnrctl status` on the server lists them. A pluggable database has its own. | | `ORA-12541` : no listener, or a timeout | The listener runs, the firewall lets API Maker in, the port is right. | | `DPI-1047` : the client libraries can not be loaded | The Oracle Instant Client is missing on the server of API Maker. The install script installs it in `/opt/oracle/instantclient`. | ## Related - [Secret Management](https://docs.apimaker.dev/v4/docs/secrets/secrets.html) · [Execute plain query](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-execute-plain-query-api.html) · [Easy Connect in the Oracle manual](https://docs.oracle.com/en/database/oracle/oracle-database/23/netag/configuring-naming-methods.html) --- # SQL Server Connection Strings > The SQL Server connection strings API Maker takes - the keys it reads, encryption and certificates, named instances, Azure SQL, examples, how to add one to an instance, and the common errors. Source: https://docs.apimaker.dev/v4/docs/Database-connection-string/sqlserver-connection-strings.html ## The format ```text Server=host,port;Database=name;User Id=user;Password=password;Encrypt=True;TrustServerCertificate=False; ``` | Key | What it is | |---|---| | `Server` (or `Data Source`) | `host,port`, or `host\instance` for a named instance. `1433` when no port is given. | | `Database` (or `Initial Catalog`) | Optional : the database a connection starts in. | | `User Id`, `Password` | A login of SQL Server. API Maker signs in with a user and a password : Windows sign-in is not used. | | `Encrypt` | `True` (the default) : the whole connection is encrypted. `False` : only the sign-in is. | | `TrustServerCertificate` | `True` : the certificate of the server is taken without a check, as with the self-signed certificate of a new SQL Server. `False` (the default) : it is checked. | | `Connection Timeout` | Seconds to connect, `15` by default. | | `ApplicationIntent=ReadOnly` | The connection only reads : an Always On group sends it to a readable secondary. | ## Examples ```text # 1. SQL Server on the same server, with its self-signed certificate Server=127.0.0.1,1433;User Id=sa;Password=yourStrong(!)Password;TrustServerCertificate=True; # 2. A database to start in Server=10.0.0.5,1433;Database=inventory;User Id=app;Password=password;TrustServerCertificate=True; # 3. A named instance Server=10.0.0.5\SQLEXPRESS;Database=inventory;User Id=app;Password=password;TrustServerCertificate=True; # 4. Azure SQL, its certificate checked Server=myserver.database.windows.net,1433;Database=inventory;User Id=app;Password=password;Encrypt=True; # 5. A readable secondary of an Always On group Server=listener.example.com,1433;Database=inventory;User Id=app;Password=password;ApplicationIntent=ReadOnly; ``` ## Add it to API Maker An instance never holds the connection string itself : it names a key of your [default secret](https://docs.apimaker.dev/v4/docs/secrets/secrets.html), where the string stays encrypted, out of Git. 1. **Put the string in the secret** **Security → Secret Management** → `Default`. Add it under `common.connectionString`, with a name of your choice, and save. 2. **Create the instance** **APIs & Logic → Instance API (DB API)** → add an instance : pick the database type, give it a name, and pick the key of the secret under **Connection**. 3. **Test it** **Test Instance** connects with the string. An instance which can not reach its database is not saved, and the form says why. **Connection String Sandbox** is optional : a second key, for code which runs in a sandbox and reaches the database by another address than API Maker does. ## Common errors | What you see | What to check | |---|---| | `Login failed for user 'app'` | The login and the password, and that the server accepts SQL Server sign-in (mixed mode). | | A certificate error | A server with a self-signed certificate needs `TrustServerCertificate=True`, or a certificate API Maker can check. | | A timeout | TCP/IP is enabled in the configuration of SQL Server, the firewall lets API Maker in, the port is right. | | A named instance can not be found | The SQL Server Browser service runs and UDP port `1434` is open, or give the port in place of the name : `Server=10.0.0.5,1433`. | ## Related - [Secret Management](https://docs.apimaker.dev/v4/docs/secrets/secrets.html) · [Execute plain query](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-execute-plain-query-api.html) · [Connection strings of SQL Server](https://learn.microsoft.com/sql/connect/ado-net/connection-string-syntax)