Routes
Routes connect HTTP methods and paths to handlers through the web routing contract.
GoForj Apps keep route registration explicit so HTTP behavior is discoverable through code, route:list, and enabled metrics, Inspects, and Lighthouse.
Where Routes Live
Application route composition usually lives in:
app/routes.goFeature packages expose routes from controllers:
internal/users/controller.go
internal/reports/controller.goThe app route file composes those controller routes into route groups. Additional apps use the same pattern under the owning app's directory:
app/admin/routes.goFollow the Complete Users Route
Use JSON API Route as the canonical, runnable Users workflow. It is maintained against the current templates; this page only describes the route-composition contract.
forj make:controller usersThe generator creates the controller and adds its constructor to app/wire/inject_http_controllers_app.go and its routes to app/routes.go. After replacing the generated handler with application behavior, add any service constructors it needs to app/wire/inject_services_app.go, then run the scenario's build, test, and endpoint-verification steps. forj route:list is the check that the registered route is present.
Controller Routes
Controllers return []web.Route:
func (c *Controller) Routes() []web.Route {
return []web.Route{
web.NewRoute(http.MethodGet, "/users/:id", c.Show),
web.NewRoute(http.MethodPost, "/users", c.Store),
}
}Handlers receive web.Context, not the underlying HTTP engine context.
Route Groups
The generated router groups public and protected routes under /api/v1 by default:
func ProvideRoutes(r *AppRoutes, authService *auth.Service) []web.RouteGroup {
var groups []web.RouteGroup
if len(r.public) > 0 {
groups = append(groups, web.NewRouteGroup("/api/v1", r.public))
}
if len(r.protected) > 0 {
groups = append(groups,
web.NewRouteGroup("/api/v1", r.protected, authService.RequireAuth()).
WithMiddlewareNames("auth.RequireAuth"),
)
}
return groups
}Route groups are the right place for shared prefixes and group-level middleware.
Route Naming
Use REST-ish paths that describe resources. Let HTTP methods carry the action:
GET /api/v1/users/:id
POST /api/v1/reportsAvoid RPC-style paths such as /api/v1/get-user for normal resource operations. See Naming Conventions for the full naming map.
Listing Routes
Use:
forj route:listFor an additional app, prefix the command with the app name:
forj admin route:listUse route:list as the source of truth for what the App registered. Do not rely only on startup logs.
Framework Routes
The HTTP runtime also registers framework-owned routes such as:
/-/health/-/ready/swagger/swagger/doc.json/metricswhen metrics are enabled- Lighthouse routes when Lighthouse is enabled
Do not add application behavior by editing framework route registration.
Common Mistakes
Common mistakes
- Do not scatter route registration across unrelated packages.
- Do not bypass
webroutes with low-level HTTP setup in normal App code. - Do not put business logic in route registration.
- Do not make route paths depend on runtime topology.
- Do not treat framework routes as application-owned endpoints.
Next Steps
- JSON API Route is the complete runnable workflow.
- Controllers explains handler structure.
- Middleware explains route and group policy.
- Naming Conventions defines route naming.
make:controllerReference lists generation, removal, and shared options.- Web covers standalone route primitives.