> ## Documentation Index
> Fetch the complete documentation index at: https://engineering.unkey.com/llms.txt
> Use this file to discover all available pages before exploring further.

# HTTP handler tests

> Testing API endpoints with the test harness

## Testing the full stack

HTTP handler tests exercise API endpoints from request to response. A single request might authenticate a user, check permissions, validate input, query a database, update a cache, and write an audit log. Testing handlers end to end catches bugs that unit tests miss.

Every handler should have tests for success, validation errors, authentication errors, and authorization errors.

## Anatomy of a handler test

Create a test harness, configure the handler with harness dependencies, register the handler, create credentials, make a request, and verify the response.

```go theme={"theme":"kanagawa-wave"}
func TestCreateApi_Success(t *testing.T) {
    h := testutil.NewHarness(t)

    route := &handler.Handler{
        Logger:    h.Logger,
        DB:        h.DB,
        Keys:      h.Keys,
        Auditlogs: h.Auditlogs,
    }

    h.Register(route)

    rootKey := h.CreateRootKey(h.Resources().UserWorkspace.ID, "api.*.create_api")
    headers := http.Header{
        "Content-Type":  {"application/json"},
        "Authorization": {fmt.Sprintf("Bearer %s", rootKey)},
    }

    req := handler.Request{Name: "my-new-api"}
    res := testutil.CallRoute[handler.Request, handler.Response](h, route, headers, req)

    require.Equal(t, http.StatusOK, res.Status)
    require.NotEmpty(t, res.Body.ApiID)
}
```

## Organizing test files

Organize tests by behavior so the intent is clear. Example directory: [`svc/api/routes/v2_apis_create_api/`](https://github.com/unkeyed/unkey/blob/main/svc/api/routes/v2_apis_create_api/).

Typical files:

* [`svc/api/routes/v2_apis_create_api/handler.go`](https://github.com/unkeyed/unkey/blob/main/svc/api/routes/v2_apis_create_api/handler.go)
* [`svc/api/routes/v2_apis_create_api/success_test.go`](https://github.com/unkeyed/unkey/blob/main/svc/api/routes/v2_apis_create_api/success_test.go)
* [`svc/api/routes/v2_apis_create_api/validation_test.go`](https://github.com/unkeyed/unkey/blob/main/svc/api/routes/v2_apis_create_api/validation_test.go)
* [`svc/api/routes/v2_apis_create_api/auth_test.go`](https://github.com/unkeyed/unkey/blob/main/svc/api/routes/v2_apis_create_api/auth_test.go)
* [`svc/api/routes/v2_apis_create_api/BUILD.bazel`](https://github.com/unkeyed/unkey/blob/main/svc/api/routes/v2_apis_create_api/BUILD.bazel)

## Testing success cases

Test minimal requests, full requests, and any important variations. Verify side effects such as audit log writes when relevant.

## Testing validation errors

Test boundary conditions, missing required fields, and invalid formats. These tests document the API contract.

## Testing authentication

Reject missing headers, malformed tokens, and revoked credentials.

## Testing authorization

Verify that permissions are enforced and cross-workspace access is rejected.

## Helper functions

Extract repeated setup into helpers. If a helper asserts, it must call `t.Helper()`.

## Debugging failed requests

Use the raw response body to inspect failures:

```go theme={"theme":"kanagawa-wave"}
if res.Status != http.StatusOK {
    t.Logf("Response body: %s", res.RawBody)
}
```
