# Setting Up an HTTP API

An optional package exposes commands and queries over HTTP.

To expose commands and queries over HTTP, use the `httpapi` package:

*(Changed in 2.0)*

```go
import "github.com/thenativeweb/architecturekit-golang/architecturekit/httpapi"
```

Define a type that describes who is making a request, and a function that determines it from the request. Then call the `NewAPI` function with the store and this function, and create a mux:

```go
type User struct {
  ID          string
  IsLibrarian bool
}

func userFrom(r *http.Request) (User, error) {
  // ...
}

api := httpapi.NewAPI(store, userFrom)
mux := http.NewServeMux()
```

If the function returns an error, neither a command nor a query is run, and the request is answered with `401 Unauthorized`. An error that has a status code of its own keeps it, though (see **[Mapping Errors to Status Codes](/docs/architecturekit/v1.0/mapping-errors-to-status-codes)**), and so do an error of the category `ErrPermanent`, one of a write whose outcome is unknown, `ErrOutcomeUnknown`, and one of a view that did not catch up with a write, `ErrNotCaughtUp`, which are answered with `500 Internal Server Error` and the message `internal server error`, since neither a command nor a query has run. So if the function can not determine the user because the session store is down, for example, it returns an error of the category `ErrTransient`. The request is then answered with `503 Service Unavailable`, and the failure is logged, rather than sending the caller off to sign in again.

*Note that to answer an error that has a status code of its own with `401 Unauthorized` all the same, the function wraps it with `httpapi.ErrUnauthorized` itself, for example with `fmt.Errorf("%w: %w", httpapi.ErrUnauthorized, err)`.*

*Note that calling `NewAPI` with `nil` as the function panics. The store may be `nil`, though, to test the queries alone (see **[Testing Queries](/docs/architecturekit/v1.0/testing-queries)**).*

For an application without authentication, call the `NewPublicAPI` function instead. Commands and queries then receive `httpapi.NoUser` as user:

```go
api := httpapi.NewPublicAPI(store)
```

Everything that answers through an API logs every error it does not explain to the caller in full, once, with the method and the route of the request: the routes it wires up, and the functions that answer in a handler of your own. A failure of the server is logged at level `Error`, and a refusal whose details the caller is not told, such as one with `401`, `409`, or a `404` for a query that found no item, at level `Info` (see **[Handling Commands over HTTP](/docs/architecturekit/v1.0/handling-commands-over-http)**). Only a request that was canceled is not logged, since nothing failed. A panic is logged with its value and its stack. By default, they use the default logger of `log/slog`. To use the logger of your application instead, hand over the `WithLogger` option, which `NewPublicAPI` accepts as well:

```go
api := httpapi.NewAPI(store, userFrom, httpapi.WithLogger(logger))
```

*Note that calling `WithLogger` with `nil` panics, and so does calling `NewAPI` or `NewPublicAPI` with `nil` as one of the options.*

## Determining the User

To determine the user in a handler of your own, call the `UserOf` function. If the user can not be determined, it returns an error that wraps `httpapi.ErrUnauthorized` as well as the error of the function, so that `errors.Is` and `errors.As` find either. If the error of the function has a status code of its own, though, it returns that error as it is (see above):

```go
mux.HandleFunc("GET /api/me", func(w http.ResponseWriter, r *http.Request) {
  user, err := httpapi.UserOf(r, api)
  if err != nil {
    // ...
  }

  // ...
})
```
