# restore-backup

Restores a **backup** into an **empty database**: a full backup followed by its increments, or a backup that the v1 API created.

- **Route:** `POST /api/v2/management/restore-backup`
- **Category:** `management`
- **Authentication:** required, with the API token
- **Answer:** a stream of NDJSON

A restore only goes into a database that holds **no events and no schemas**, so it takes **the full backup and all of its increments in one request**: once the full backup is restored, the database is no longer empty. It **checks every part, schema, and event** of the backup as it reads it, and until it is over, the database refuses reads and writes. If it fails, it **removes what it restored so far**, so that the database is empty again. **[Backup and Restore](/docs/eventsourcingdb/backup-and-restore)** explains the background, including which versions restore which backups.

## Request

The body is a **stream of NDJSON**, with the content type `application/x-ndjson`, and has **no limit on its size**, while each of its lines may hold **at most 601 KiB**, not counting its newline, which is more than any item of a backup takes, see **[Limits](/docs/eventsourcingdb/limits#size-limits)**. It holds either:

- a **full backup followed by its increments**, each exactly as **[`create-backup`](/docs/eventsourcingdb/api/create-backup)** sent it, in the order in which they were created, or
- a **backup that the v1 API created**, on its own, with its `schema`, `event`, and `error` lines, each with a `payload`.

In a backup of the v2 API, each part is made of these items, one per line:

| Type | Meaning |
| --- | --- |
| `backup` | Begins a part. Its `formatVersion` has to be `2`. Its `lastBackedUpEvent` has to be `null` for the first part, which is the full backup, and has to name the event the part before it ended at for every further part. |
| `eventSchema` | A schema, checked as registering a schema checks it. The schemas of a part come before its events. Every part brings every schema again, and the same schema is taken once. |
| `event` | An event, checked value by value as writing events checks it, against the chain of hashes of the events before it, against the clock of the server, and against the schema of its type. |
| `lastBackedUpEvent` | Skipped, since the event a part ended at follows from its events. |
| `heartbeat` | Skipped, wherever it stands. |
| `error` | Marks a part whose creation failed, which the restore refuses. |
| `end` | Ends a part. Every part needs it. |

In a backup of the v1 API, the schemas come before the events as well, and there is no `end` line to check for. The v1 API backs up an empty database as an **empty body**, so the restore takes an empty body for such a backup and **restores nothing**: the database stays empty, and the answer is the `end` item alone. A backup that is empty by mistake, for example because the job that created it failed, looks the same, so check that a backup holds what you expect before you restore it.

Send the parts **one after the other**, without anything between them, and with `--data-binary`, which keeps their line breaks: `-d` removes them, and the restore then refuses the body as malformed. To restore a full backup and two increments:

```shell
cat full-backup.ndjson increment-1.ndjson increment-2.ndjson \
  | curl \
      -X POST \
      -H "authorization: Bearer secret" \
      -H "content-type: application/x-ndjson" \
      --data-binary @- \
      http://localhost:3000/api/v2/management/restore-backup
```

## Answer

The answer is a **stream of items**, one per line, which tells the outcome of the restore:

| Type | Data | When |
| --- | --- | --- |
| `error` | `code`, `description`, and `details` | When the backup cannot be restored, see **[Errors](#errors)**. |
| `heartbeat` | empty | Once the whole backup has been read, while nothing else is sent for a while and the restore still runs. |
| `end` | empty | Once, as the last item, when the stream ends cleanly. Without an `error` item before it, the backup was restored. |

**Heartbeats and the `end` item** work as on every stream of the API, see **[Streams](/docs/eventsourcingdb/api#streams)**, with one difference: a restore sends **heartbeats only once it has read the whole backup**. While the backup is still being sent, the data of the client keeps the connection alive.

A client that goes away **while it sends the backup** breaks off reading it, which fails the restore, as **[`backup-unreadable`](/docs/eventsourcingdb/errors/backup-unreadable)** describes. **Once the whole backup has been read**, though, the restore **runs to its end** even if its client is gone.

A restore that succeeds is answered with the `end` item alone:

```json
{"type":"end","data":{}}
```

## Errors

The restore reports these errors as an `error` item, followed by the `end` item. After any of them, the database is **as it was before the restore**, since a restore that has begun removes what it restored so far:

- **[`license-invalid`](/docs/eventsourcingdb/errors/license-invalid)**: The license expired while the server ran. It is checked before any line of the backup.
- **[`backup-unreadable`](/docs/eventsourcingdb/errors/backup-unreadable)**: Reading the body broke off, because the connection dropped or the client sent nothing for more than five seconds.
- **[`backup-malformed`](/docs/eventsourcingdb/errors/backup-malformed)**: A line is not an item that a backup holds at its place, such as an empty line, a schema after an event, a part that begins before the one before it has ended, or an event without a subject. This includes a line that is longer than any item of a backup can be, and a schema that takes more as a backup writes it than any schema of a backup can.
- **[`backup-format-unknown`](/docs/eventsourcingdb/errors/backup-format-unknown)**: A `backup` item names a `formatVersion` other than `2`, or none, as in a backup that a newer version created.
- **[`full-backup-missing`](/docs/eventsourcingdb/errors/full-backup-missing)**: The body begins with an increment rather than with a full backup.
- **[`backup-increment-disconnected`](/docs/eventsourcingdb/errors/backup-increment-disconnected)**: An increment does not follow on the event the part before it ended at, as when an increment is missing, sent twice, or out of order.
- **[`backup-incomplete`](/docs/eventsourcingdb/errors/backup-incomplete)**: The body ends while a part of a backup of the v2 API is still open, without its `end` item. A part without its `end` item that another part follows is reported as `backup-malformed` instead.
- **[`backup-failed`](/docs/eventsourcingdb/errors/backup-failed)**: A part holds an `error` item, or a backup of the v1 API an `error` line, since creating it failed.
- **[`event-schema-malformed`](/docs/eventsourcingdb/errors/event-schema-malformed)**: A schema of the backup is not a valid JSON Schema, or holds a number with more than 1,000 digits before or after its decimal point.
- **[`event-schema-not-object`](/docs/eventsourcingdb/errors/event-schema-not-object)**: A schema of the backup does not describe an object.
- **[`event-schema-too-complex`](/docs/eventsourcingdb/errors/event-schema-too-complex)**: A schema of the backup refers back to a part of itself, or reaches more than 10,000 subschemas, counting a referenced one each time it is referenced.
- **[`event-schema-already-registered`](/docs/eventsourcingdb/errors/event-schema-already-registered)**: The backup brings two different schemas for the same event type.
- **[`store-not-empty`](/docs/eventsourcingdb/errors/store-not-empty)**: The database holds events or schemas. This is checked before the first line of the backup is read.
- **[`event-chain-broken`](/docs/eventsourcingdb/errors/event-chain-broken)**: An event of the backup does not follow on the one before it, or does not match its hash.
- **[`event-hash-version-unknown`](/docs/eventsourcingdb/errors/event-hash-version-unknown)**: An event of the backup has a hash of a version that this version does not know, as one that a newer version wrote.
- **[`backup-ahead-of-clock`](/docs/eventsourcingdb/errors/backup-ahead-of-clock)**: An event of the backup lies more than an hour beyond the clock of the server, such as one dated `9999-12-31`. The same backup restores once the clock has caught up.
- **[`event-too-large`](/docs/eventsourcingdb/errors/event-too-large)**: An event of the backup is larger than the maximum event size.
- **[`subject-too-long`](/docs/eventsourcingdb/errors/subject-too-long)**: The subject of an event of the backup is longer than 1,024 characters.
- **[`subject-too-deep`](/docs/eventsourcingdb/errors/subject-too-deep)**: The subject of an event of the backup has more than 32 segments.
- **[`event-schema-violated`](/docs/eventsourcingdb/errors/event-schema-violated)**: An event of the backup does not match the schema that the backup holds for its type.
- **[`event-schema-unregistered`](/docs/eventsourcingdb/errors/event-schema-unregistered)**: The server runs with `--require-event-schemas`, and an event of the backup has a type for which the backup holds no schema before it.
- **[`capacity-exceeded`](/docs/eventsourcingdb/errors/capacity-exceeded)**: The backup holds more events than the license permits.
- **[`indexes-rebuilding`](/docs/eventsourcingdb/errors/indexes-rebuilding)**: The indexes are still being rebuilt after an upgrade, which a restore needs complete to tell whether the database is empty.
- **[`store-read-only`](/docs/eventsourcingdb/errors/store-read-only)**: The database is in read-only mode.
- **[`disk-full`](/docs/eventsourcingdb/errors/disk-full)**: The disk is almost full, so the database refuses writes.
- **[`restore-in-progress`](/docs/eventsourcingdb/errors/restore-in-progress)**: Another restore is running.
- **[`file-unreadable`](/docs/eventsourcingdb/errors/file-unreadable)**: A file of the store that the restore needs is damaged, such as an events file whose checksum no longer matches.
- **[`store-failed`](/docs/eventsourcingdb/errors/store-failed)**: The store refuses writes after a failure to store one, or reads and writes after a restore that could not empty it again.
- **[`server-shutting-down`](/docs/eventsourcingdb/errors/server-shutting-down)**: The server began to shut down after the restore had sent a heartbeat. Before that, 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/x-ndjson`.
- **`401`**: The API token is missing or wrong.
- **`429`**: Too many requests were sent; the answer says when to try again.
- **`500`**: The server failed unexpectedly before the stream began, for example because a restore that failed could not empty the database again. Once the stream has begun, it breaks off without its `end` item instead.
- **`503`**: The server is shutting down, or began to shut down before the stream began, which includes the whole time the backup is being sent.
