# One input

A route reads at most one input, named by `input:`. It is an `Input` type,
an object a client sends ([Values and types](values-and-types.md)).
Where the input comes from follows the method: the query string for `GET`
and `DELETE`, and the JSON body for `POST`, `PUT` and `PATCH`.

```jadpo
type ListTodos = Input {
    status: TodoStatus {
        optional: true
    }
    limit: PageSize {
        default: 25
    }
    request_tag: RequestTag {
        header: "X-Request-Tag"
        optional: true
    }
}

GET / {
    input: ListTodos
    output: TodoPage
    run: todos_for_owner(input, current_principal.user)
}
```

`GET /?status=open` fills `status` from the query string, and
`request_tag` from the `X-Request-Tag` header when it is sent. `limit` is
25 when the request leaves it out.

## The query string

Query-string fields are scalars, enums or lists of them. A list is the key
repeated: `?status=open&status=done`. A nested object needs a body.

## Headers

A field read from a header says so with `header:`. A header field is a
scalar, and each header is named once. A header field never reads a
credential (`Authorization`, cookies, `X-Jadpo-*`): those belong to
sign-in ([Identity](identity.md)).

## What is refused

- Unknown keys and fields are refused. A query string or a body that the
  route doesn't read counts as unknown input too.
- A `GET` or `DELETE` never reads a body.
- A body is at most 1 MB, and no setting changes that. A larger one
  answers 413.
- A body is read only when it is sent as JSON (`Content-Type:
  application/json`, or another `application/…+json` type). So a form a
  browser posts from another site never reaches an action.

## Text is normalised

Text in a request is normalised to Unicode NFC as it is decoded, in the
body, the path, the query string and headers alike, before the input's
rules are checked. NFC writes each character one standard way, so equal
text compares equal however the client spelled it
([Standard library](standard-library.md)).
