# Reading Your Own Writes over HTTP

To let a caller read its own writes over HTTP, call the `QueryRevisioned` function instead of `Query`. Additionally, hand over a view that implements `Revisioned`, whose projection is tracked (see [Tracking Revisions](/docs/architecturekit/reading-your-own-writes#tracking-revisions)), and how long to wait at most:

```go
httpapi.QueryRevisioned(
  api,
  mux,
  "GET /api/books",
  catalog,
  toListBooks,
  listBooks(catalog),
  httpapi.DefaultWait,
)
```

After sending a command, the caller takes the highest ID from `eventIds` and sends it in the `Wait-For-Revision` header of the query:

```shell
curl http://localhost:8080/api/books \
  -H "Wait-For-Revision: 1"
```

The route waits until the view has reached this revision, but at most for the given duration, which is five seconds for `httpapi.DefaultWait`. Then it answers with what the view holds, even if the time has run out. If the header does not contain a revision, the request is answered with `400 Bad Request`.

Once the view has seen at least one event, the response contains the revision it shows in the `X-Revision` header, as well as an `ETag` header and `Cache-Control: no-cache`. If the caller sends the `ETag` in the `If-None-Match` header and the view has not changed since, the request is answered with `304 Not Modified`.

*Note that the constants `httpapi.HeaderWaitFor` and `httpapi.HeaderRevision` contain the names of the two headers.*

## Depending on More Than the Read Model

If an answer depends on more than the view, for example on the current date, call the `QueryVarying` function instead, and additionally hand over a function of the type `httpapi.Volatile`. It receives the request and returns a value that changes whenever the answer would, and that becomes part of the `ETag`:

```go
type ListOverdueBooks struct {
  Today string
}

func listOverdueBooks(catalog architecturekit.View[BookItem]) func(context.Context, ListOverdueBooks) ([]BookItem, error) {
  return func(ctx context.Context, q ListOverdueBooks) ([]BookItem, error) {
    items, err := catalog.All(ctx)
    if err != nil {
      return nil, err
    }

    return slices.Collect(query.Where(items, func(item BookItem) bool {
      return item.IsBorrowed && item.BorrowedUntil < q.Today
    })), nil
  }
}

func today(*http.Request) string {
  return time.Now().Format(time.DateOnly)
}

httpapi.QueryVarying(
  api,
  mux,
  "GET /api/overdue-books",
  catalog,
  func(r *http.Request, user User) (ListOverdueBooks, error) {
    return ListOverdueBooks{Today: today(r)}, nil
  },
  listOverdueBooks(catalog),
  httpapi.DefaultWait,
  today,
)
```

## Building Your Own Revisioned Handler

To build a handler of your own that works like `QueryRevisioned`, use these three functions:

- `Await` waits for the revision the request asks for. Running out of time is not an error. It returns an error if the header does not contain a revision, or if waiting fails for another reason.
- `ServeUnchanged` answers with `304 Not Modified` if the caller already holds the given revision, and reports whether it did.
- `RespondResultAt` answers like `RespondResult`, and adds the headers for the given revision.

The last argument of `ServeUnchanged` and `RespondResultAt` is a `Volatile` function, or `nil`:

```go
mux.HandleFunc("GET /api/books", func(w http.ResponseWriter, r *http.Request) {
  if _, err := httpapi.UserOf(r, api); err != nil {
    httpapi.RespondResult(w, struct{}{}, err)
    return
  }

  if err := httpapi.Await(r.Context(), r, catalog, httpapi.DefaultWait); err != nil {
    httpapi.RespondResult(w, struct{}{}, err)
    return
  }

  revision := catalog.Revision()

  if httpapi.ServeUnchanged(w, r, revision, nil) {
    return
  }

  books, err := httpapi.Ask(r, api, toListBooks, listBooks(catalog))
  httpapi.RespondResultAt(w, r, revision, books, err, nil)
})
```
