# `route.run_kind`

A `GET` route runs an action that isn't read-only, or a route of another method runs a query.

Area 7, [HTTP](/docs/http.md); not declinable; the next step is usually the agent's.

## Why Jadpo refuses it

HTTP promises that a `GET` only reads, so a browser, a cache or a client
library may send one again without asking. Jadpo keeps that promise by what
a route runs. A query can only read, so a `GET` can run one. An action can
write, so a `GET` runs one only when the compiler can prove it writes
nothing, emits nothing and makes no changing call, itself and through every
action it calls. `POST`, `PUT`, `PATCH` and `DELETE` run an action, which owns
the writes and the transaction, and never a query.

A `GET` running an action that changes something could change it again each
time it is repeated, and nothing can show whether you meant the route to read
or to write. The message names what the action does and where, following the
calls, so you can see which it is.

## What it looks like

Here the action adds a note, so it can't answer a `GET`:

main.jadpo:

```jadpo
type Memo = Text {
    max_length: 200
}

type AddMemo = Input {
    text: Memo
}

type MemoView = Output {
    text: Memo
}

entity Note {
    id: Uuid
    text: Memo

    policy: {
        create: [Access.public]
        read: [Access.public]
    }
}

action add_memo(input: AddMemo) -> MemoView {
    var note: Note = Note.create {
        set: {
            text: input.text
        }
    }
    return MemoView {
        text: note.text
    }
}

routes Memos {
    prefix: /memos

    GET / {
        authentication: RouteAuthentication.none
        input: AddMemo
        output: MemoView
        run: add_memo(input)
    }
}
```

```text
error: `GET /memos` runs action `add_memo`, which writes with `Note.create`
 --> main.jadpo:41:14
   |
24 |     var note: Note = Note.create {
   |                      ----------- here
41 |         run: add_memo(input)
   |              ^^^^^^^^ not read-only
  reason: A `GET` is safe to repeat, so it runs a named query, or an action the graph proves writes nothing, emits nothing and makes no changing call; `add_memo` writes with `Note.create`.
  next: Answer `/memos` with another method, or leave `Note.create` out of what `add_memo` does (agent)
  rule: route.run_kind
  help: https://jadpo.dev/docs/errors/route.run_kind

check failed: 1 error, 1 file
```

`(agent)` at the end of the `next:` line means your coding agent can make
the fix itself.

## How to fix it

The question is whether the route changes anything.

**If the route adds or changes something**, answer it with another
method, here `POST`, which reads its input from the JSON body:

```jadpo
    POST / {
        authentication: RouteAuthentication.none
        input: AddMemo
        output: MemoView
        run: add_memo(input)
    }
```


`POST /memos` runs `add_memo`, and a client sends the memo as JSON.

**If the route only reads**, run a query that reads what it shows, or
leave what changes something out of the action. Here the memos are stored as
`Note` records, and the route lists them:

```jadpo
query recent_notes() -> List<MemoView> {
    from: Note
    order: [Note.text asc]
    limit: 50
}
```

```jadpo
    GET / {
        output: List<MemoView>
        run: recent_notes()
    }
```


`GET /memos` answers with up to 50 notes and never writes, so repeating
it is safe. A signed-in caller sees the notes `Note`'s `read:` lets them
read.

**An action that works something out** can stay on the `GET`, once it stops
doing what changes something. An action like this one, which reads and
calculates, has nothing to refuse:

```jadpo
action check_memo(input: MemoInput) fails TooShort -> MemoView {
    if (text.length(input.text) < 3) {
        reject TooShort {}
    }
    return MemoView {
        text: input.text
    }
}
```


`GET /memos` now answers with the memo, or 422 `too_short`, and repeating it
changes nothing.

## Related

- [What a route runs](/docs/what-a-route-runs.md)
- [A `GET` that runs an action](/docs/what-a-route-runs.md#a-get-that-runs-an-action)
- [One input](/docs/one-input.md)
- [Routes: signed in by default](/docs/routes-signed-in-by-default.md)
