# read-subjects

Lists a **subject**, or a subject together with **every subject below it**.

- **Route:** `QUERY /api/v2/data/read-subjects`
- **Category:** `data`
- **Authentication:** required, with the API token
- **Answer:** a stream of NDJSON

A **[subject](/docs/eventsourcingdb/subjects)** is listed when it **holds events itself, or a subject below it does**. So `/books` is listed once `/books/42` holds an event, even though no event was written to `/books`, while a subject without any event at or below it is not listed at all. The tutorial **[Listing Subjects](/learn/tutorials/first-steps-with-eventsourcingdb/listing-subjects)** walks through it step by step.

## Request

The body is a JSON object, with the content type `application/json`:

| Field | Type | Required | Meaning |
| --- | --- | --- | --- |
| `subject` | string | yes | The subject to list, a slash-separated path such as `/books`. |
| `options.recursive` | boolean | no | Whether to list every subject below the given one as well. Defaults to `false`, which lists the given subject alone. |

To list `/books` and every subject below it:

```shell
curl \
  -X QUERY \
  -H "authorization: Bearer secret" \
  -H "content-type: application/json" \
  -d '{"subject":"/books","options":{"recursive":true}}' \
  http://localhost:3000/api/v2/data/read-subjects
```

## Answer

The answer is a **stream of items**, one per line. Each subject is a `subject` item:

| Type | Data | When |
| --- | --- | --- |
| `subject` | `subject`, the subject as a string | For every subject that the listing finds. |
| `error` | `code`, `description`, and `details` | When the listing cannot go on, see **[Errors](#errors)**. |
| `heartbeat` | empty | While nothing else is sent for a while, to keep the connection alive. |
| `end` | empty | Once, as the last item, when the stream ends cleanly. |

**Heartbeats and the `end` item** work as on every stream of the API, see **[Streams](/docs/eventsourcingdb/api#streams)**. A subject that holds no event, neither itself nor below it, is answered with the `end` item alone.

For a database that holds events in `/books/42`, `/books/42/copies/1`, and `/books/43`, the request above is answered with:

```json
{"type":"subject","data":{"subject":"/books"}}
{"type":"subject","data":{"subject":"/books/42"}}
{"type":"subject","data":{"subject":"/books/42/copies"}}
{"type":"subject","data":{"subject":"/books/42/copies/1"}}
{"type":"subject","data":{"subject":"/books/43"}}
{"type":"end","data":{}}
```

## Errors

The listing reports these errors as an `error` item, followed by the `end` item:

- **[`subject-missing`](/docs/eventsourcingdb/errors/subject-missing)**: The request leaves out the subject, or sends it as an empty string.
- **[`subject-malformed`](/docs/eventsourcingdb/errors/subject-malformed)**: The subject is not a valid subject, such as `books` without its leading slash.
- **[`subject-too-long`](/docs/eventsourcingdb/errors/subject-too-long)**: The subject is longer than 1,024 characters.
- **[`subject-too-deep`](/docs/eventsourcingdb/errors/subject-too-deep)**: The subject has more than 32 segments.
- **[`indexes-rebuilding`](/docs/eventsourcingdb/errors/indexes-rebuilding)**: The indexes that the listing needs are still being rebuilt after an upgrade.
- **[`restore-in-progress`](/docs/eventsourcingdb/errors/restore-in-progress)**: A restore is running, which refuses reads until it has finished.
- **[`file-unreadable`](/docs/eventsourcingdb/errors/file-unreadable)**: A file of the store that the listing needs is damaged, such as an events file whose checksum no longer matches.
- **[`store-failed`](/docs/eventsourcingdb/errors/store-failed)**: The store refuses reads for good, after a restore that could not empty it again.
- **[`server-shutting-down`](/docs/eventsourcingdb/errors/server-shutting-down)**: The server began to shut down while a recursive listing was running. Before the stream begins, the server answers with `503` instead.

## Status Codes

Before the stream begins, the server answers with a status code other than `200` where it cannot take the request at all, as described in **[Errors](/docs/eventsourcingdb/api#errors)**:

- **`400`**: The content type of the body is not `application/json`, or the body is missing or no JSON object of the shape above, for example with a field the route does not know, such as `recursive` outside of `options`, or with `null` as a value.
- **`401`**: The API token is missing or wrong.
- **`408`**: The body did not arrive in time.
- **`413`**: The body is larger than its **[limit](/docs/eventsourcingdb/limits)**.
- **`429`**: Too many requests were sent, or the client already holds 256 open streams, see **[Rate Limiting](/docs/eventsourcingdb/rate-limiting)**; the answer says when to try again.
- **`500`**: The server failed unexpectedly before the stream began. Once it has begun, the stream breaks off without its `end` item instead.
- **`503`**: The server is shutting down.
