# OpenAPI

The compiler writes one OpenAPI 3.1 document per API into `build/openapi/`.
It lists every route with its input, output, success status and the
failures it can reach, the 400 and 422 responses for bad input, and the
`///` descriptions
([Project layout and modules](project-layout-and-modules.md)). The
document's title is the application's name, and its version the first 12
hex digits of the SHA-256 of the API's record
([The public API record](the-public-api-record.md)).

Each route's responses follow from what it runs:

- 403 where policy can refuse what it does, or what an action it calls
  does;
- 503 where it uses a store;
- an `Idempotency-Key` that promises a repeat the first response, only
  where that response is kept.

Every route shows its security scheme.

## Failure wording for client apps

Beside each document, `jadpo check` writes
`<api>.failures.<locale>.json` for each supported locale. It maps each
failure code the API can reach to
`{ "text": "…{next_slot}…", "formats": { "next_slot": "date_time" } }`, the
same shape for every code. `formats` lists only the placeholders the
client must format, each `number`, `decimal`, `date`, `date_time` or
`duration`, decided by the client field's type
([Failures for client apps](failures-for-client-apps.md)).

## Serving the document

Every API serves its document at `<prefix>/openapi.json` by default:
`/v1/openapi.json`, or `/openapi.json` for `main` at `/`. Other Jadpo apps
read it to call this one
([Packages from other Jadpo apps](packages-from-other-jadpo-apps.md)).
`serve_openapi: false` in the API's entry in `apis: { }` turns it off.

The served route is listed like any generated route: in the API's own
OpenAPI document and in its API record, marked generated, and in
`jadpo routes`. Its record entry lists it as the runtime's:

```text
GET /v1/openapi.json
    generated openapi
    authentication none
    status 200
```

- **It needs the API's default sign-in:** a signed-in caller, by any
  method the API accepts, so an admin API's document needs sign-in, and
  the record leaves out the `authentication none` line. Where the API
  accepts no way to sign in that is built, every route it has lets anyone
  call it, so its document tells no one more than its routes do, and
  anyone may read it, as above.
- **It answers 200 with the document exactly as `jadpo check` writes it**
  to `build/openapi/<api>.json`, as `application/json`. Like any route that
  takes no input, it answers a query string or a body with 422
  `invalid_input`.
- A route the application writes at the same path is `route.path_overlap`.

## The `x-jadpo` fields

Jadpo's documents carry `x-jadpo` fields for what plain OpenAPI lacks.
Other tools ignore them. Jadpo's OpenAPI importer reads them whenever it
finds them, so another Jadpo app's document imports as an exact provider
package, with no corrections or recordings
([How the OpenAPI importer reads a document](how-the-openapi-importer-reads-a-document.md)).

| Field | On | Holds |
|---|---|---|
| `x-jadpo-changes` | Every operation | Whether the operation changes something: `true` for a route that runs an action, `false` for a `GET` and for the runtime's own reads |
| `x-jadpo-idempotency` | Every operation that reads an `Idempotency-Key` | Whether it takes `Idempotency-Key`, and whether the API requires it: `header`, `required` (the API's `idempotency:`), `keeps` (`response`: a repeat gets the first answer; `request`: a repeat waits for the first but runs again; `nothing`: running it again changes nothing, or no store keeps it), `window` (`1d`), `max_length` (255), and the codes a key's repeat answers with, `in_use` (`conflict`) and `reused` (`idempotency_key_reused`) |
| `x-jadpo-failure` | The schema of each failure the application declares | Its `code` and `kind` (`not_found`); sign-in's, policy's and the runtime's own codes carry none, since the caller's runtime handles them |
| `x-jadpo-constraints` | Every field's, placeholder's and success response's schema | Every field's rules: its type and rules as the API record writes them, `Text { min_length: 1, max_length: 200 }`, `List<TodoView>`, `Money?` |

Each operation is tagged with its route group, and the group's `///`
description is the tag's, so an importer names a resource after it.

> `x-jadpo-events`, the public events the app publishes, waits for
> publishing events outward
> ([Where events travel](where-events-travel.md)): an
> application publishes no event to another yet, so no document carries
> it.
