# HTTP

A Jadpo app answers HTTP requests with routes. A route says which method
and URL it answers, what comes in, what goes out, and which action or query
runs. This route adds a todo:

`domains/todos/routes/todos.jadpo`:

```jadpo
use todos/types { NewTodo, TodoView }
use todos/actions { add_todo }

/// The todo list.
routes Todos {
    prefix: /todos

    /// Adds a todo.
    POST / {
        authentication: RouteAuthentication.none
        input: NewTodo
        output: TodoView
        run: add_todo(input)
    }
}
```

It answers `POST /todos`. Jadpo reads a `NewTodo` from the JSON body and
checks it, and `run:` gets it as `input`. `run:` calls the action
`add_todo`, which returns a `TodoView`, the route's `output:`. The route
answers 200 with that value as JSON.

`NewTodo`, `TodoView` and `add_todo` are your app's own. Each `use` line
brings a name in from another file of your app, and these are the files:

`domains/todos/types/new_todo.jadpo`:

```jadpo
/// What a caller sends to add a todo.
type NewTodo = Input {
    title: Text
}
```

`domains/todos/types/todo_view.jadpo`:

```jadpo
/// A todo, as the app sends it back.
type TodoView = Output {
    title: Text
    done: Bool
}
```

`domains/todos/actions/add_todo.jadpo`:

```jadpo
use todos/types { NewTodo, TodoView }

/// Builds the todo and sends it back. It stores nothing.
action add_todo(input: NewTodo) -> TodoView {
    return TodoView {
        title: input.title
        done: false
    }
}
```

`policy.jadpo`:

```jadpo
use todos

policy {
    actions: {
        todos.add_todo: [Access.public]
    }
}
```

Most actions take their permission from the stored records they reach
([Policy](/docs/policy.md)). `add_todo` reaches none, so `policy.jadpo` says
who may run it, and `Access.public` means anyone. `RouteAuthentication`,
`Access`, `Text` and `Bool` are built into Jadpo, so they need no `use`
line.

Every route needs a signed-in caller unless an `authentication:` line in
the route says otherwise, as this one does because the app has no sign-in
yet ([Routes: signed in by default](/docs/routes-signed-in-by-default.md)).

Run `jadpo api update` once, which writes [the public API
record](/docs/the-public-api-record.md), then `jadpo dev`, and send it a todo:

```sh
curl -X POST http://localhost:3000/todos \
  -H 'content-type: application/json' \
  -d '{"title": "Buy milk"}'
```

```text
{"title":"Buy milk","done":false}
```

A route holds no logic of its own. The work lives in
[actions and queries](/docs/functions-and-actions.md). When an action
fails, the HTTP status comes from the failure's kind, a category such as
`not_found` (404), never from the route ([Failure kinds](/docs/failure-kinds.md)).

The topics of this page cover:

- how routes are grouped and matched: [Route groups](/docs/route-groups.md) and
  [Paths and placeholders](/docs/paths-and-placeholders.md);
- what a route reads and answers: [One input](/docs/one-input.md) and
  [Output and status](/docs/output-and-status.md);
- how long it may run: [Time limits](/docs/time-limits.md);
- what Jadpo writes for you: [Health](/docs/health.md) checks,
  [Generated routes](/docs/generated-routes.md), an [OpenAPI](/docs/openapi.md) document
  for each API, and [The public API record](/docs/the-public-api-record.md), a
  file in your project that lists each API's routes and fields, so every
  change to the API shows as a diff of that file.

| Page | What it covers |
|---|---|
| [Route groups](/docs/route-groups.md) | Every route belongs to a route group: a `routes` declaration with a name and a `prefix:`. |
| [Paths and placeholders](/docs/paths-and-placeholders.md) | A placeholder in a path is typed where it appears, and reaches what the route runs by its name. |
| [One input](/docs/one-input.md) | A route reads at most one input, named by `input:`. |
| [Output and status](/docs/output-and-status.md) | `output:` names what the route answers with: an `Output` type, an object made to be sent to clients. |
| [What a route runs](/docs/what-a-route-runs.md) | `run:` calls one named action. |
| [Time limits](/docs/time-limits.md) | Every route has a deadline: 10 seconds, unless `deadline:` sets another, and never more than 60. |
| [Waiting for follow-on work](/docs/waiting-for-follow-on-work.md) | An action does its own database work and leaves the rest, such as a second call to a provider, to subscribers: code that runs when an event the action emits is delivered (Subscribers). |
| [Streaming a model's answer](/docs/streaming-a-model-s-answer.md) | When what a route runs returns an `AiStream`, the route sends a model's answer as it is written, piece by piece. |
| [How failures reach the client](/docs/how-failures-reach-the-client.md) | Every failure reaches the client in one envelope: `code`, `message`, `request_id`, and the failure's client fields under `details` (Failures). |
| [Idempotent writes](/docs/idempotent-writes.md) | A client that retries a write after a timeout can't tell whether the first try worked. |
| [Generated routes](/docs/generated-routes.md) | Some features generate their routes for you. |
| [Health](/docs/health.md) | The runtime always serves two health checks, and there is nothing to write. |
| [APIs and versions](/docs/apis-and-versions.md) | Most apps have one API. |
| [OpenAPI](/docs/openapi.md) | The compiler writes one OpenAPI 3.1 document per API into `build/openapi/`. |
| [The public API record](/docs/the-public-api-record.md) | Each API has a committed, readable record of its routes, fields and failure codes: `api/main.jadpo_record` for `main`. |
| [Write revisions](/docs/write-revisions.md) ○ not built | After a write, a client can make sure its next read sees that write rather than an older cached copy. |
| [Webhooks](/docs/webhooks.md) | You don't write routes for a provider's webhooks: Jadpo generates them from the provider's package (Webhooks as events). |

[What is built](/docs/http-built.md) says which of this works today.
