# ADR-002: Embedded chi.Router in HttpServerComponent **Status:** Accepted **Date:** 2026-03-18 ## Context `HttpServerComponent` must expose routing methods to callers so they can register routes before the server starts. There are two design options: 1. **Wrapper methods** — define `Get(pattern, handler)`, `Post(...)`, `Route(...)`, `Mount(...)`, `Use(...)`, etc. on `HttpServerComponent` explicitly, delegating each to an internal router. 2. **Embedded router** — embed `chi.Router` directly in the interface and the concrete struct, so all chi routing methods are promoted to the component surface automatically. The application bootstrap pattern in this project registers routes in a `lc.BeforeStart(...)` hook, after `db.OnInit` has run but before `srv.OnStart` binds the port. This means the same value returned by `httpserver.New(...)` is used both as a `launcher.Component` (lifecycle) and as a router (route registration). Callers write: ```go srv := httpserver.New(logger, cfg, httpserver.WithMiddleware(...)) lc.Append(db, srv) lc.BeforeStart(func() error { srv.Get("/health", healthHandler) srv.Route("/api/v1", func(r chi.Router) { ... }) return nil }) ``` ## Decision Embed `chi.Router` directly in both the `HttpServerComponent` interface and the `httpServer` concrete struct. The interface is declared as: ```go type HttpServerComponent interface { launcher.Component chi.Router } ``` The struct embeds `chi.Router` as an anonymous field, initialized to `chi.NewRouter()` in `New()`. This means callers receive the complete chi routing API — `Get`, `Post`, `Put`, `Delete`, `Patch`, `Head`, `Options`, `Route`, `Mount`, `Use`, `With`, `Group`, `Handle`, `HandleFunc`, `Method`, `MethodFunc`, `Connect`, `Trace`, `NotFound`, `MethodNotAllowed` — without any wrapper boilerplate and without any risk of an incomplete wrapper missing a method. The compliance test (`compliance_test.go`) asserts at compile time: ```go var _ launcher.Component = httpserver.New(...) var _ chi.Router = httpserver.New(...) ``` ## Consequences - `chi` is a visible part of the `HttpServerComponent` API. Callers using `Route(...)` or `Mount(...)` must import `github.com/go-chi/chi/v5` for the callback type. This is intentional and explicit, not a leaky abstraction — httpserver is documented as chi-backed. - A future swap to a different router would be a breaking change to `HttpServerComponent`. This is accepted: the router choice is a deliberate, long-term decision (see ADR-001). - Writing wrapper methods would have to be updated every time chi adds a new method. Embedding avoids that maintenance burden permanently. - Middleware is applied to the embedded router in `OnInit()` by calling `s.Router.Use(mw)` for each registered middleware, preserving chi's standard middleware chaining semantics.