Options
ShiftAPI uses a layered option system. Options configure the API, groups, and individual routes.
Option types
Section titled “Option types”| Type | Where it works | Examples |
|---|---|---|
Option | API, Group, and Route | WithError, WithMiddleware, WithResponseHeader |
APIOption | API only (New) | WithInfo, WithBadRequestError, WithInternalServerError |
RouteOption | Route only (Handle) | WithStatus, WithRouteInfo |
Option implements all three level interfaces, so WithError and WithMiddleware work everywhere. Level-specific options like WithStatus are restricted to their level at compile time.
Composing options
Section titled “Composing options”Use ComposeOptions to bundle multiple Option values into a single reusable option that works at any level:
func WithAuth() shiftapi.Option { return shiftapi.ComposeOptions( shiftapi.WithMiddleware(authMiddleware), shiftapi.WithError[*AuthError](http.StatusUnauthorized), )}
// Works at any levelapi := shiftapi.New(WithAuth())v1 := api.Group("/api/v1", WithAuth())shiftapi.Handle(v1, "GET /secret", getSecret, WithAuth())Level-specific composition
Section titled “Level-specific composition”To mix shared options with level-specific options, use the corresponding compose function:
| Function | Accepts | Returns |
|---|---|---|
ComposeOptions | ...Option | Option |
ComposeAPIOptions | ...APIOption | APIOption |
ComposeGroupOptions | ...GroupOption | GroupOption |
ComposeRouteOptions | ...RouteOption | RouteOption |
Since Option implements all level interfaces, you can pass it to any of the level-specific compose functions alongside level-specific options:
createOpts := shiftapi.ComposeRouteOptions( shiftapi.WithStatus(http.StatusCreated), // RouteOption shiftapi.WithError[*ConflictError](http.StatusConflict), // Option (also a RouteOption))
shiftapi.Handle(api, "POST /users", createUser, createOpts)Route groups
Section titled “Route groups”Use Group to register routes under a common path prefix with shared options:
v1 := api.Group("/api/v1", shiftapi.WithError[*RateLimitError](http.StatusTooManyRequests), shiftapi.WithMiddleware(auth),)
shiftapi.Handle(v1, "GET /users", listUsers) // GET /api/v1/usersshiftapi.Handle(v1, "POST /users", createUser) // POST /api/v1/usersGroups can be nested. Error types and middleware are inherited by child groups:
admin := v1.Group("/admin", shiftapi.WithError[*ForbiddenError](http.StatusForbidden), shiftapi.WithMiddleware(adminOnly),)shiftapi.Handle(admin, "GET /stats", getStats) // GET /api/v1/admin/stats// inherits RateLimitError (429) + auth middleware from v1// adds ForbiddenError (403) + adminOnly middlewareOptions merge across all three levels: New() (API-wide) → Group() (group-level) → route registration (route-level).