Use `server.Server` to configure the public Go server and register routes.

## Create the Server

Create one server during process setup:

```go
runtime := server.New(server.Config{
    Addr:   ":8080",
    Logger: logger,
})
```

The zero values use these defaults:

| Setting | Default |
| --- | --- |
| Address | `:8080` |
| Read timeout | 15 seconds |
| Write timeout | 30 seconds |
| Idle timeout | 60 seconds |
| Shutdown timeout | 15 seconds |
| Logger | `slog.Default()` |

`Run` starts the server. It waits for `SIGINT`, `SIGTERM`, or context cancellation. It then drains active HTTP connections.

```go
if err := runtime.Run(context.Background()); err != nil {
    return err
}
```

## Register Routes

Wahoo uses `http.ServeMux` patterns. Go 1.22 method patterns work without an extra router.

```go
runtime.HandleFunc("GET /healthz", health)
runtime.HandleFunc("POST /api/projects", createProject)
runtime.Handle("GET /events", events)
```

Use `HandleFunc` for a function. Use `Handle` for an `http.Handler`.

Register a page route after you set a renderer:

```go
runtime.SetRenderer(ssr.NewRenderer())
if err := runtime.Page("GET /"); err != nil {
    return err
}
```

The `GET /` pattern handles page paths that do not match a more specific route.

## Return JSON

Use `server.JSON` to set the content type and encode a value:

```go
func health(w http.ResponseWriter, _ *http.Request) {
    _ = server.JSON(w, http.StatusOK, map[string]string{
        "status": "ok",
    })
}
```

Pass `0` as the status to use `200 OK`.

Define a stable error format in the application:

```json
{
  "error": {
    "code": "validation_failed",
    "message": "Check the highlighted fields.",
    "request_id": "..."
  }
}
```

Do not return internal database or provider errors to the browser.

## Return HTML

Use `server.HTML` for a small HTML response:

```go
_ = server.HTML(w, http.StatusOK, "<h1>Ready</h1>")
```

Use the SSR renderer for React pages. `TemplateRenderer` is useful for a small non-React page or a test fixture. It does not replace the React worker.

## Request Behavior

For each request, `Server`:

1. Uses `X-Request-ID` when the client sends one.
2. Creates an ID when the header is absent.
3. Adds `X-Request-ID` to the response.
4. Recovers a panic at the HTTP boundary.
5. Writes a structured completion log entry.

Add application middleware for authentication, authorization, request size limits, rate limits, CORS, and security headers. Wahoo does not add these policies by default.

## Read JSON Safely

The generated application includes `decodeJSON`. It rejects unknown fields:

```go
var input CreateProjectInput
if err := decodeJSON(r, &input); err != nil {
    _ = server.JSON(w, http.StatusBadRequest, errorResponse("invalid JSON"))
    return
}
```

Before you decode a public request, set an HTTP body limit. Validate every field after decoding.

## Test Routes

Use `httptest` for route tests:

```go
request := httptest.NewRequest(http.MethodGet, "/healthz", nil)
response := httptest.NewRecorder()
runtime.ServeHTTP(response, request)

if response.Code != http.StatusOK {
    t.Fatalf("status = %d", response.Code)
}
```

Test status codes, response JSON, cookies, authorization, and error cases.