# Output and status

`output:` names what the route answers with: an `Output` type, an object
made to be sent to clients. It must be exactly what the action returns, so
the route shows its contract without anyone opening the action.

A route that succeeds answers 200, unless `status:` says otherwise:

```jadpo
POST / {
    input: CreateTodo
    output: TodoView
    status: SuccessStatus.created
    run: create_todo(input, current_principal.user)
}
```

| `status:` | HTTP | Needs |
|---|---|---|
| left out (`SuccessStatus.ok`) | 200 | `output:` |
| `SuccessStatus.created` | 201 | `output:` |
| `SuccessStatus.accepted` | 202 | `output:`; the work carries on in the background ([Jobs and events](jobs-and-events.md)) |
| `SuccessStatus.no_content` | 204 | no `output:`; the action returns `Unit` |

Only the output's declared fields are sent. `IssuedToken` and `IssuedKey`,
the built-in types for an issued sign-in token and a service's key
([Identity](identity.md)), are sent as the objects they are: an `id`,
`started_at` and `ends_at`.

A route never writes a failure's status. It comes from the kind of each
failure the action can produce ([Failures](failures.md)).

## Map layers

A route may also answer with a map layer: a `FeatureCollection<G, P>`, a
collection of shapes of geometry `G`, each with properties of type `P`
([Geospatial](geospatial.md)). It is sent bare, as the whole response,
in plain RFC 7946 GeoJSON, so a mapping library fetches it as its source.
A `GET` gets one from a query ([Reads and writes](reads-and-writes.md),
"A query giving a map layer"); a route with another method gets one from
an action that builds it.

- **Only a collection, only bare.** A `List` or `Page` of layers, or a lone
  `Feature<G, P>`, is `route.output_not_output`. A mapping library takes a
  collection as its source, and nothing asks for the others.
- **What `P` may not hold** is what an `Output`'s fields may not: a caller,
  a password's hash or a secret value, however deep. `P` is an `Object`,
  which could hold any of them, so the route checks it: a layer whose
  properties hold one is `route.output_not_output` at `output:`, naming
  what and where. The same search looks inside a feature's properties
  wherever a layer appears, so an `Output` with a layer field whose
  properties hold a password's hash is refused at that field.
- **Field policy.** A layer an action returns is shown to its caller, just
  as an `Output` the action builds is. So every `return` of a
  `FeatureCollection` in an action carries only fields every caller of the
  action may read. Otherwise it is `policy.output_field_unproved` at the
  value returned ([Field restrictions](field-restrictions.md)),
  whichever route or action calls it.
- **Sent as GeoJSON.** The response's body is the collection as
  `json.write` writes it, `{"type":"FeatureCollection","features":[...]}`.
  A route test reads it back through the same codec, so `response.output`
  is the layer the action returned.
