Response format¶
Every API of API Maker answers with the same JSON object : the envelope. So one piece of client code can read every answer.
In short
successandstatusCodeare always there.dataholds the result.- A failed call has
errors: one entry for each problem. - The first error decides the status code of the answer.
- Headers can change the format (XML, YAML, plain text) and the case of the keys in
data.
The envelope¶
A successful answer
{
"success": true,
"statusCode": 200,
"data": [ { "customer_id": 1, "first_name": "Bob", "last_name": "Lin" } ],
"totalCount": 5
}
dataholds the result.totalCountcomes only withgetTotalCount=true.- A key with nothing to say is not sent :
warningscomes only when there are some.
A refused request
{
"success": false,
"statusCode": 400,
"errors": [
{ "type": "required", "field": "first_name", "message": "Please provide valid 'first_name' field with type 'string'.", "code": 400 }
]
}
errorslists every problem found. Each has acodeand amessage. A value the schema refuses also names itsfieldand thetypeof the rule.
| Key | When | What it holds |
|---|---|---|
success |
always | true when the call worked. |
statusCode |
always | The HTTP status of the answer, also in the body. |
data |
on success | The result : a list for get all and the queries, one row for get by id, whatever a custom API returns. null when there is nothing. |
totalCount |
with getTotalCount=true |
How many rows match the filter, before skip and limit. |
errors |
on failure | One entry for each problem. See An error entry. |
warnings |
when your code adds some | Problems that did not stop the call. A hook or a custom API adds them to g.res.warnings, in the shape of an error. |
meta |
with x-am-meta: true, in the admin panel only |
How the call ran : executionTime, executionTimeMS, apiAccessGroups (the groups that allowed it) and runBy (the server, process and sandbox that ran the code). |
encryptedData |
with x-am-get-encrypted-data |
The answer, encrypted. get_only_encryption sets data to null. |
What your code writes with g.logger is never part of the answer. It goes to the log of the request, in Log Explorer.
An error entry¶
A row of a save breaks a rule of the schema
{
"type": "min",
"field": "price_cents",
"message": "Please provide minimum '0' for 'price_cents' field.",
"code": 400
}
| Key | What it holds |
|---|---|
code |
The status of this problem. |
message |
What went wrong. With x-am-internationalization, the message comes in the language of the caller. See the messages. |
type |
For a value the schema refuses : the rule. required, min, max, minLength, maxLength, emailNotValid, enumValidation, unique, invalidValue (a wrong type, an error thrown by a validatorFun…), schemaKeyNotFound (a key the schema does not have), virtualFieldUsedInFind. |
field |
For a value the schema refuses : the column, with dots for nested fields (address.city). |
dataIndex |
For a unique error in a save of many rows : the place of the row in the list you sent, from 0. |
stack |
For an error of your code : the stack, one line in each entry. |
apiCallSequence |
When API calls go round in a circle (a calls b, b calls a) : the APIs of the circle. |
Status codes¶
The status of a failed answer is the code of its first error.
| Code | When |
|---|---|
200 |
The call worked. |
201 |
Save single or multiple and master save saved the rows. |
400 |
The request is wrong : a value the schema refuses, an unknown instance, a bad query, a missing body. |
401 |
No token, a token that is not valid any more, or an API closed to the outside (NO_ACCESS). Get a new token from the token API. |
403 |
The token is good, but no group of the API user allows this API. Or the browser page is on an origin the account does not allow. |
404 |
No API at this URL and method. Also update by id, replace by id and remove by id with throwErrorIfRecordNotFound=true, when no row has the id. |
500 |
An error of your code or of the database. Also any error whose code is missing or is not one of the codes above. |
A custom API can answer another status with g.res.statusCode.
The format of the answer¶
The answer is JSON. These headers change it :
| Header | Effect |
|---|---|
x-am-content-type-response |
text/xml or text/yaml : the same envelope, in XML or YAML. text/plain or text/html : when data is a text, the answer is that text alone. Errors stay JSON. |
x-am-response-case |
The case of the keys in data : camelCase, snakeCase, pascalCase… Any other value, like noChange, keeps them as they are. See the values. |
x-am-response-object-type: make_flat |
Nested objects become one level, joined by _ : state_id_state_name. |
x-no-compression: true |
Never compressed. Without it, an answer bigger than compressThreshold (51200 bytes by default) is compressed in a way the client accepts : gzip, brotli or deflate. |
A custom API can also answer a file or a page of its own : see Content types.
Response headers¶
| Header | Meaning |
|---|---|
x-am-data-source |
cache when the answer came from the cache, api when the API ran. Always api for the /stream APIs. |
x-am-request-id |
The id of the request. Search for it in Log Explorer. |
Content-Encoding |
gzip, br or deflate when the answer was compressed. |
In your code¶
A call of g.sys.db, g.sys.system or g.sys.cache returns data, and throws the errors. Ask for the full response to get the envelope instead : the second argument true in TypeScript, full in the other languages. Then nothing is thrown.