# Routing

Register HTTP routes on the fiber or stdhttp driver with path params, groups, and method checks.

`router` is a thin facade over `fiber` and `stdhttp`; handlers stay plain `http.HandlerFunc` and `router.Param` reads path params identically on both. Use it for hand-written routes or to mirror `.zen` RPC bindings; `zever routes` prints the resolved table.

`stdhttp` is the recommended default (and the `zever new` scaffold default): it serves directly on `net/http.ServeMux` with no conversion layer. `fiber` pays a `fasthttpadaptor` net/http conversion plus header/status/body merge-back on every request — currently ~46 allocs/op per request against ~17 for a `stdhttp` param route (see [Benchmarks](https://zenta-dev.github.io/zever/reference/benchmarks/#router-re-measurement-2026-10-14-and-stdhttp-default)). Pick `fiber` only when you need its routing features (case-sensitive `:name` params, `{name}` accepted on both) rather than raw throughput.

## Register a route

Switch with `ROUTER_ADAPTER=fiber`; handler signatures do not change. Full options: [Config reference](https://zenta-dev.github.io/zever/reference/config/#router).

```yaml
router:
  adapter: stdhttp   # or: fiber
```

```go title="main.go" check
package main

import (
    "fmt"
    "net/http"

    routerstdhttp "github.com/zenta-dev/zever/adapters/router/stdhttp"
    "github.com/zenta-dev/zever/config"
    "github.com/zenta-dev/zever/container"
    "github.com/zenta-dev/zever/core/router"
)

func main() {
    routerstdhttp.Register()
    c := container.New(config.Default())
    r, _ := c.Router()

    r.Handle("GET", "/users/{id}", func(w http.ResponseWriter, req *http.Request) {
        fmt.Fprintf(w, "user %s", router.Param(req, "id"))
    })

    _ = http.ListenAndServe(":8080", r)
}
```

```sh
curl -s localhost:8080/users/42
```

```text
user 42
```

`c.Router()` resolves lazily and caches; the router has no `Close`.

## Write path patterns

`fiber` accepts `:name` and `{name}`; `stdhttp` accepts only ServeMux syntax. Fiber is case-sensitive, so prefer `{name}` for both.

| Pattern | fiber | stdhttp |
|---|---|---|
| `/users/:id` | `:id` | rejected |
| `/users/{id}` | `:id` | `{id}` |
| `/files/{path...}` | `*` wildcard | `{path...}` |
| `/users/{$}` | literal | `{$}` exact |
| `/items/:id<[0-9]+>` | passthrough | rejected |

## Use the router API

| Method | Purpose |
|---|---|
| `Handle(method, pattern, handler)` | One route. |
| `Group(prefix, middlewares...)` | Scoped routes. |
| `Use(middlewares...)` | Append middleware. |
| `router.Param(req, name)` | One param. |
| `router.ParamNames(req)` | All params. |
| `router.WithParams(ctx, params)` | Test params. |
| `router.ValidMethod(method)` | Method check. |
| `router.Open(adapter, opts)` | Open without container. |
| `router.Register(adapter, factory)` | Add custom driver. |

Valid methods: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, CONNECT, TRACE. Invalid or duplicate routes log `[router]` and are skipped. On `stdhttp`, `Use` applies only to later registrations. See [Middleware](https://zenta-dev.github.io/zever/guides/http/middleware/).

## Production checklist

- Shut down `http.Server` gracefully; set `ReadHeaderTimeout`, `ReadTimeout`, `WriteTimeout`, `IdleTimeout`.
- One driver per process; log option maps only via `config.RedactedServices`.

## Troubleshooting

<details>
<summary>Route 404s on stdhttp but works on fiber</summary>

You used `:id` or a regex constraint. Rewrite as `{id}`.
</details>

<details>
<summary>`Use` middleware does not run on stdhttp</summary>

It was registered after the route. Move `Use` before `Handle`.
</details>

## Related

- [Middleware](https://zenta-dev.github.io/zever/guides/http/middleware/): Logging, recovery, rate limiting.
- [Requests and responses](https://zenta-dev.github.io/zever/guides/http/requests-responses/): Params, bodies, JSON envelopes.
- [Validation](https://zenta-dev.github.io/zever/guides/http/validation/): @validate rules and handler checks.
