# Response Format

> What every API Maker API answers - the envelope with success, statusCode, data, totalCount, errors, warnings, logs and meta, the HTTP status codes, and how headers change the shape and the format of the reply.

Source: https://docs.apimaker.dev/v1/docs/apis-all/response-format.html

Every API of API Maker, generated, schema, custom, system or third party, answers with the same envelope, so one client handles all of them the same way.

## The envelope

```json title="A successful answer"
{
    "success": true,
    "statusCode": 200,
    "data": [ { "customer_id": 1, "first_name": "Bob", "last_name": "Lin" } ],
    "totalCount": 5,
    "warnings": [],
    "logs": [],
    "meta": {}
}
```

- `data` holds the result, `totalCount` comes with `getTotalCount=true`, `warnings` and `logs` when there are some, `meta` with the header `x-am-meta: true`. Absent keys are simply not sent.

```json title="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 }
    ],
    "warnings": []
}
```

- `errors` lists every problem found, each with its `code`, `message`, and for data problems the `field` and the `type` of the rule. The HTTP status of the reply is `statusCode`.

| Key | When | Meaning |
|---|---|---|
| `success` | always | `true` when the request did what it was asked, `false` otherwise. |
| `statusCode` | always | The HTTP status of the reply, repeated in the body : `200`, `201` for a save, `400`, `401`, `403`, `404` or `500`. |
| `data` | on success, and on some failures | The result : an array for get all and the query APIs, an object for get by id, a save of one object, an update ; whatever a custom API returns. `null` when there is nothing. |
| `totalCount` | with `getTotalCount=true` | The number of rows matching the filter, without `skip` and `limit`. |
| `errors` | on failure | One entry per problem. Data problems name the `field` and the `type` of the rule ; the `message` follows the language asked with `x-am-internationalization`. |
| `warnings` | when there are some | Problems which did not stop the request, in the same shape as errors : for example a `deep` which found no target. |
| `logs` | when your code logged | What `g.logger` printed while a custom API, a hook or an event ran, so the caller can see it. |
| `meta` | with `x-am-meta: true` | `executionTime`, `executionPlan` (MongoDB explain), `apiAccessGroups` (which group granted the call) and `runBy` (which server, process and sandbox ran the code). |
| `encryptedData` | with `x-am-get-encrypted-data` | The response encrypted with the transfer key of the secret, next to or instead of `data`. |

## An error entry

```json
{
    "type": "min",
    "field": "price_cents",
    "message": "Please provide minimum '0' for 'price_cents' field.",
    "code": 400,
    "dataIndex": 2
}
```

| Key | Meaning |
|---|---|
| `type` | The rule which failed : `required`, `min`, `max`, `minLength`, `maxLength`, `email`, `enumValidation`, `invalidValue` (a wrong type, a thrown `validatorFun`, a concurrency version mismatch…), `schemaKeyNotFound` (a key the schema does not have), `schemaNotFound`, `unique`, `virtualFieldUsedInFind`. |
| `field` | The field concerned, with dots for nested fields. |
| `message` | The text, from the [message templates](/v1/docs/apis-all/error-codes.html) or your own throw, translated when the caller asks for a language. |
| `code` | The HTTP status of this problem. The `statusCode` of the reply is the highest one. |
| `dataIndex` | For a save of several objects : the index of the object in the array. |
| `stack`, `apiCallSequence` | Present for unexpected errors of your code, to help you debug : the stack as lines, and the chain of APIs which led there. |

## Status codes

| Code | Meaning |
|---|---|
| `200` | Done. |
| `201` | Created : a save through save single or multiple or master save. |
| `400` | The request is wrong : validation errors, an unknown key, a bad query, a missing body. |
| `401` | The token is missing, malformed or expired. Get a new one from the [token API](/v1/docs/apis-all/system-apis/system-generated-token-api.html). |
| `403` | The token is fine but no group of the API user grants this API, this table or this field ; or the origin of the browser is not allowed. Fix the group, do not sign the user out. |
| `404` | The path does not exist : a typo in the URL or a wrong method, an instance name which is not there. Also the answer of update by id, replace by id and remove by id with `throwErrorIfRecordNotFound=true` when the id is unknown. |
| `500` | An error of your code or of the database. The message and, for your code, the stack are in `errors`. |

## The format of the reply

The body is JSON unless the request asks otherwise with [headers](/v1/docs/apis-all/header/requestHeader.html) :

| Header | Effect |
|---|---|
| `x-am-content-type-response` | `application/json` (default), `text/xml`, `text/yaml`, `text/plain`, `text/html`, `application/octet-stream`. The envelope is the same, only its encoding changes. |
| `x-am-response-case` | The case of every key : `camelCase`, `snake_case`, `PascalCase`, `kebab-case`… |
| `x-am-response-object-type: make_flat` | Nested objects flattened with `_` between the levels : `state_id_country_id_country_name`. |
| `x-am-meta: true` | Adds `meta`. |
| `x-am-get-encrypted-data` | Adds or replaces `data` with `encryptedData`. |
| `x-no-compression: true` | No gzip or brotli, whatever the size (replies bigger than `compressThreshold`, 51200 bytes by default, are compressed otherwise). |

A custom API can also answer something other than the envelope : set `g.res.contentType` to a MIME type and return a string, or return a file, see [Content types](/v1/examples/res/contentType/contentType.html) and the [download example](/v1/docs/apis-all/custom-apis/user-created-custom-api.html#files).

## Response headers

| Header | Meaning |
|---|---|
| `x-am-data-source` | `cache` when the reply came from Redis, `api` when the API ran. |
| `Content-Encoding` | `gzip` or `br` when the reply was compressed. |

## In your code

The same envelope is what `g.sys.db.*`, `g.sys.system.*` and `g.sys.cache.*` return when you ask for the full response with the second argument `true`. Without it, they return `data` and throw the errors.

```typescript linenums="1"
const full = await g.sys.db.getAll({ instance: 'mongodb', database: 'shop', collection: 'products' }, true);
if (!full.success) g.logger.error(full.errors);
const rows = full.data;
```
