Request headers¶
A header changes how API Maker answers a call, without changing the URL. The headers work on every API : database, custom and system APIs.
In short
x-am-authorizationcarries the token of the app that calls. Most calls need it.- The other headers are optional. Leave them out and you get JSON, with the keys as they are.
x-am-metaworks in the admin panel only.
All headers¶
| Header | Values | What it does |
|---|---|---|
x-am-authorization |
a token | The API user : the app that calls. Needed unless the API is public. |
x-am-user-authorization |
a token | The person who uses the app, from a DB token generator. |
x-aws-authorization, x-google-authorization, x-azure-authorization, x-custom-authorization |
a token | The person, from AWS Cognito, Google, Azure AD or your own provider. |
x-am-response-case |
camelCase, snakeCase… |
The case of the keys in data. |
x-am-content-type-response |
application/json, text/xml, text/yaml… |
The format of the answer. |
x-am-response-object-type |
no_action, make_flat |
Turns nested objects into one level. |
x-am-meta |
true, false |
Adds how the call ran, in meta. Admin panel only. |
x-am-cache-control |
no_action, reset_cache |
Skips the cached answer and refreshes it. |
x-am-get-encrypted-data |
no_encryption, get_only_encryption, get_data_and_encryption |
Encrypts the answer. |
x-am-encrypted-payload |
true |
Says that the body is encrypted. |
x-am-internationalization |
the name of a language | The language of the messages. |
x-am-tenant-username |
a tenant | The tenant of a multi-tenant instance. |
x-am-sandbox-timeout |
milliseconds | How long the code of the call may run. |
x-am-run-in-sandbox |
0, 1, 2… |
Which sandboxes may run the code. |
x-am-run-in-debugger |
true |
Runs the code in the debugger. |
x-no-compression, accept-encoding |
true / gzip, br, deflate, identity |
Compression of the answer. |
x-am-authorization¶
The token of an API user : the app that calls. The groups of that API user decide which APIs, tables and fields the call may reach.
- Get the token from the token API. It lasts
jwtOptions.expiresInseconds : 72 hours by default.expiresInSecondsin the token request changes it. - No token, or a token that is not valid :
401. A good token, but no group allows the API :403. - A public API (
apiAccessType: IS_PUBLICin its settings) does not need it. - Your code reads the API user in
g.req.auth.authAMUser.
x-am-user-authorization¶
The token of a person : a row of your own users table. A DB token generator (auth provider) makes it, through the token API.
- It is needed when the settings of the database, the table, the API or the custom API name that provider in
authProviders. - Your code reads the person in
g.req.auth.authAMDB: the columns of the user that the generator selects. - A token made for a tenant works for that tenant only. See Multi-tenant.
x-aws-authorization¶
The access token of AWS Cognito, when an AWS auth provider is set up. Your code reads it in g.req.auth.authAWS.
x-google-authorization¶
The id token of a Google sign-in, when a Google auth provider is set up. Your code reads it in g.req.auth.authGoogle.
x-azure-authorization¶
The token of Azure Active Directory, when an Azure auth provider is set up. Your code reads it in g.req.auth.authAzure.
x-custom-authorization¶
The token of a custom auth provider : your own code makes and checks the token. Your code reads what the check returns in g.req.auth.authCustom.
x-am-response-case¶
Changes the case of the keys in data, also inside nested objects and lists. The keys of the envelope (success, statusCode…) do not change. Default : noChange.
| Value | first_name becomes |
|---|---|
noChange |
first_name |
camelCase |
firstName |
capitalCase |
First Name |
constantCase |
FIRST_NAME |
dotCase |
first.name |
headerCase |
First-Name |
noCase |
first name |
paramCase |
first-name |
pascalCase |
FirstName |
pathCase |
first/name |
sentenceCase |
First name |
snakeCase |
first_name |
- The
_idof MongoDB becomesidincamelCase, as in the answer above. - A value that is not in the table keeps the keys as they are.
x-am-response-object-type¶
Turns nested objects into one level, with _ between the names. Use it for grids, CSV files and spreadsheets, for example after a deep. Default : no_action.
{ "id": 101, "state_id": { "id": 201, "country_id": { "id": 301, "country_name": "INDIA" }, "state_name": "GUJARAT" }, "city_name": "AHMEDABAD" }
{ "id": 101, "state_id_id": 201, "state_id_country_id_id": 301, "state_id_country_id_country_name": "INDIA", "state_id_state_name": "GUJARAT", "city_name": "AHMEDABAD" }
x-am-meta¶
Adds meta to the answer : how the call ran. Default : false.
The admin panel only
meta shows the inside of your servers : their processes, the ports of the sandboxes, the groups that let a caller in. So API Maker gives it to the API Testing page of the admin panel only. The request must come through the encrypted channel of the panel, with the token of an administrator. Every other caller gets the answer without meta, whatever the header says. A value other than true or false is still refused with 400.
{
"data": [ { "id": 301, "country_name": "INDIA" } ],
"meta": {
"executionTime": "15ms",
"executionTimeMS": 15,
"apiAccessGroups": [ { "groupId": "6381b80359bdbd3a87c9abd5", "groupName": "all_permission", "hasAccess": true } ],
"runBy": [ { "apiCategory": "CUSTOM_APIS", "serverId": "…", "serverName": "primary", "processId": "…", "port": 49731, "runtime": "node", "runOnNativeProcess": false } ]
}
}
| Key | What it holds |
|---|---|
executionTime, executionTimeMS |
The time spent in API Maker, without the network. |
apiAccessGroups |
The groups of the API user, and which one allowed the call. |
runBy |
For a call that runs code (a custom API, a hook) : the server and process, the runtime, and the port of the sandbox. Code on the native process has runOnNativeProcess: true and port: null. Code of a group of separate sandboxes also shows enableSeparateSandboxForThis and allowAllPackagesOfAdmin. A call handed to one of the first sandboxes (x-am-run-in-sandbox) shows twice : once with publishToRedis: true for the hand-over, once for the sandbox that ran it. |
x-am-internationalization¶
The name of a language of i18N Management. Every message of the answer comes in that language : the messages of API Maker, and your own (errorList, the texts your code throws). Default, or no header, gives the original messages.
Add a language or change a message : the next call uses it. Nothing restarts.
x-am-run-in-sandbox¶
Which sandboxes may run the code of this call : a custom API, the hooks, the events.
x-am-run-in-sandbox: 0 # any sandbox (the default)
x-am-run-in-sandbox: 1 # always the first sandbox
x-am-run-in-sandbox: 2 # one of the first two
- Use
1when your code keeps something in memory, like a connection that a process initializer opened. Every call then meets the same runner, sog.sharedis the same for all of them. - "The first" means the oldest sandboxes of the code : the ones of its language and runtime, or of its group of separate sandboxes. How many sandboxes there are is a setting.
- The call does not start a sandbox of its own : it uses the ones that run (one is started if none runs). It asks for
5and only two run ? It uses those two. 0, or a value that is no number : any sandbox.- When the sandboxes restart, the first one is the oldest that still takes calls. No call fails for it.
- Code with
runOnNativeProcessruns in no sandbox : the header changes nothing for it.
x-am-run-in-debugger¶
The code of the call stops at your breakpoints. It works while debugging is on for your account, and the API testing page is open in the admin panel. That page sends the header by itself. See Debugging.
x-am-content-type-response¶
The format of the answer. Default : application/json.
| Value | The answer |
|---|---|
application/json |
{ "success": true, "statusCode": 200, "data": [ … ] } |
text/xml |
The same envelope in XML. Each item of a list is an <_el>. |
text/yaml |
The same envelope in YAML. |
text/plain, text/html |
When data is a text : that text alone. Anything else stays JSON. |
application/octet-stream |
When data is a base64 text (a data:…;base64, URL works too) : the bytes it stands for. Anything else stays JSON. |
<?xml version='1.0'?>
<root>
<success>true</success>
<statusCode>200</statusCode>
<data>
<_el>
<customer_id>4</customer_id>
<first_name>JOHNNY</first_name>
</_el>
</data>
</root>
- Errors are never plain text or bytes.
- The
/streamAPIs answer JSON, whatever this header says. - A custom API can choose the format itself with
g.res.contentType. See Content types.
x-am-cache-control¶
For an API with caching on. Default : no_action.
| Value | What happens | x-am-data-source of the answer |
|---|---|---|
no_action |
The cached answer comes back from Redis, when there is one. | cache |
reset_cache |
The API runs against the database. Its answer replaces the cached one. | api |
x-am-get-encrypted-data¶
Encrypts the answer with the transfer key of the secret (encryptionAlgorithmFETransfer and secretFETransfer) : the key you share with your web or mobile app. Default : no_encryption.
| Value | The answer |
|---|---|
no_encryption |
data only. |
get_only_encryption |
encryptedData, and data is null. |
get_data_and_encryption |
data and encryptedData. |
{ "success": true, "statusCode": 200, "data": null, "encryptedData": "U2FsdGVkX1+6qMdb3jXwJAUWH/qlwBq75mtA1kzpWccrNZRAr+CE2c3VtGpkEtVjH==" }
The app decrypts encryptedData with the same algorithm and key : AES, or the older RC4 or TripleDES. Anyone who has the app has that key : see what it protects.
x-am-encrypted-payload¶
Says that the body is encrypted : { "dataEncFE": "…" }. dataEncFE is { data, createdAt }, encrypted with the transfer key of the secret.
- A body older than
feTransferDataValidityInSecondsof the secret is refused : 15 seconds by default. - With
acceptOnlyEncryptedData: truein the settings of an API, a plain body is refused. - See Security features.
x-am-tenant-username¶
The tenant of the request, for the APIs of a multi-tenant instance. They work on the database of that tenant.
- It does what the tenant in the path does :
/api/schema/admin/crm::acme/crm/customers. When a request does both, the path wins. - Each multi-tenant instance looks the tenant up in its own tenants table : the Connection String Multi Tenant of the instance. So one header serves every multi-tenant instance that a call uses.
- An unknown tenant is refused with
400:Unable to find tenant with username 'acme'. - An empty value names no tenant : the request works on the structure database.
- A custom API reads the tenant in
g.req.params.tenantUsername. Itsg.sys.dbandg.sys.systemcalls pass it on, and so do the hooks. - Cached answers of custom and system APIs are kept per tenant.
- A token of a person made with this header works for that tenant only.
- On an instance that is not multi-tenant, the header changes nothing.
x-am-sandbox-timeout¶
How long the code of this call may run, in milliseconds : a custom API and the hooks of its versions, or the hooks of an API. It counts wherever the code runs : in a sandbox, on the native process, or in the server itself.
- Without the header, a custom API gets its own
customApiTimeoutInSeconds. Anything else getssandboxReqTimeoutof the configuration : 13000 ms. - The header wins over
customApiTimeoutInSeconds. - When the time is over, the answer is the error
API didn't respond in 60000ms.The runner of that code takes no new request, and ends once its other requests are done. - Event listeners, schedulers, migration scripts and process initializers have times of their own : see Time of a run.
x-no-compression¶
API Maker compresses an answer of compressThreshold bytes or more : 51200 by default. With true, this answer goes out as it is.
- A file that a custom API sends is compressed, whatever its size.
- The
/streamAPIs are never compressed.
accept-encoding¶
The standard header. API Maker takes the first of gzip, br (Brotli) and deflate that the header accepts. So a browser that sends gzip, deflate, br gets gzip : it costs much less CPU than Brotli, for nearly the same size.
identity, or no header, means no compression. The headers of the answer are listed in Response format.
From your code¶
The same headers go in headers of every g.sys call :