HTTP Services
HTTP services in GoForj are built from generated HTTP runtime code, application controllers, route groups, middleware, and the web abstraction.
The framework owns server composition and runtime behavior. Application code owns routes, controllers, services, validation, and response decisions.
When To Use It
Use HTTP services when your App exposes APIs, web endpoints, health checks, readiness probes, frontend assets, Lighthouse, Swagger, or metrics.
Use a controller when a route needs request translation, validation, or a call into application services. Keep business workflows in services rather than in HTTP runtime setup.
Where It Lives
HTTP-related generated code usually lives in:
internal/http
internal/routerApplication controllers live in application-owned packages, for example:
internal/users
internal/reports
internal/uploadsThe generated sample controller is:
internal/hello/controller.goRuntime Commands
Run the HTTP server directly:
forj apiRun all enabled local runtimes together:
forj appList registered routes:
forj route:listServer Configuration
The HTTP runtime reads:
API_HTTP_HOST=0.0.0.0
API_HTTP_PORT=3000
HTTP_ACCESS_LOG_ENABLED=trueWhen metrics are enabled, the dedicated API metrics endpoint can use:
METRICS_API_PORT=9100Controller Shape
Controllers group related route handlers and translate HTTP requests into service calls.
Example shape:
package users
import (
"net/http"
"github.com/goforj/web"
)
type Controller struct {
service *Service
}
func NewController(service *Service) *Controller {
return &Controller{service: service}
}
func (c *Controller) Routes() []web.Route {
return []web.Route{
web.NewRoute(http.MethodGet, "/users/:id", c.Show),
}
}
func (c *Controller) Show(ctx web.Context) error {
user, err := c.service.Find(ctx.Context(), ctx.Param("id"))
if err != nil {
return err
}
return ctx.JSON(http.StatusOK, user)
}The exact response helpers available come from the web package. Use the generated App pattern first, then go to Web for server-side primitive details or HTTPX for lower-level HTTP utility behavior.
Route Registration
Generated Apps collect routes through internal/router.
The route registry builds public and protected route groups and mounts them under /api/v1 by default.
The generated shape is:
func ProvideAppRoutes(
helloController *hello.Controller,
) *AppRoutes {
return &AppRoutes{
public: helloController.Routes(),
}
}When auth is enabled, protected route groups are wrapped with auth middleware.
Framework Routes
The HTTP server also registers framework-owned routes.
Common framework routes include:
GET /-/healthGET /-/readyGET /swaggerGET /swagger/doc.jsonGET /metricswhen metrics are enabled- Lighthouse routes when Lighthouse is enabled
Application route docs should not treat these as user-owned routes.
Health and Readiness
Use liveness for process health:
curl http://localhost:3000/-/healthUse readiness for dependency readiness:
curl http://localhost:3000/-/readyAuthorized readiness can expose structured dependency checks when called with:
Authorization: Bearer $APP_DIAG_TOKENUnauthenticated readiness intentionally avoids leaking raw infrastructure errors.
Observability
The HTTP runtime can record:
- access logs
- route registration summary
- request metrics
- inspect records
- local HTTP error response bodies in local environments
Use route:list for the full route table instead of relying on startup logs for complete route visibility.
Common Mistakes
Common mistakes
- Do not put business workflows in
internal/http. - Do not bypass
webroute registration with scattered low-level HTTP setup. - Do not edit framework route registration to add application endpoints.
- Do not expose detailed readiness errors without
APP_DIAG_TOKEN. - Do not assume
apiis the only runtime shape;appcan host HTTP with workers and scheduler locally.
Next Steps
- Routes covers route registration in depth.
- Controllers covers controller patterns.
- Runtime Topology explains combined and split runtime processes.
- Web covers the standalone server-side HTTP package.
