Skip to main content

httpserver package

Package httpserver provides a modular HTTP server built on Gin and the gosoline kernel. It offers structured request binding, typed responses, middleware, SSE streaming, and dependency-injected handler registration.

import "github.com/gosoline-project/httpserver"

Application helpers

RunDefaultServer()

Usage

httpserver.RunDefaultServer(func(ctx context.Context, config cfg.Config, logger log.Logger, router *httpserver.Router) error {
router.GET("/ping", handler)
return nil
})

Description

Runs a single HTTP server named "default", reading configuration from httpserver.default. This is the simplest way to start a server.

RunServers()

Usage

httpserver.RunServers(map[string]httpserver.RouterFactory{
"public": publicDefiner,
"admin": adminDefiner,
})

Description

Runs multiple named HTTP servers. Each server reads its configuration from httpserver.<name>.

Server construction

NewServer()

Usage

application.WithModuleFactory("http", httpserver.NewServer("default", myRouterFactory))

Description

Creates a kernel.ModuleFactory for an HTTP server. The server is registered as a kernel module and runs at the Service stage. The name parameter determines both the config key (httpserver.<name>) and the module name (httpserver-<name>).

Router

RouterFactory

type RouterFactory func(ctx context.Context, config cfg.Config, logger log.Logger, router *Router) error

Implement this function to define your routes. Return an error to prevent the server from starting.

Router methods

Handle()

router.Handle(httpMethod, relativePath, handlers...)

Registers a route for the given HTTP method and path.

GET() / POST() / PUT() / DELETE() / PATCH() / OPTIONS()

router.GET("/users", handler)
router.POST("/users", handler)

Convenience methods for registering routes with specific HTTP methods.

Group()

api := router.Group("/api")
api.GET("/users", handler)

Creates a route group with a common path prefix. Groups can be nested.

Use()

router.Use(middlewareFunc)

Adds middleware to the router or group.

UseFactory()

router.UseFactory(func(ctx context.Context, config cfg.Config, logger log.Logger, settings *httpserver.Settings) (gin.HandlerFunc, error) {
// create middleware with access to config, logger, and server settings
})

Adds a middleware factory that is resolved lazily when the router is built. settings.Name contains the server name used for server-scoped configuration.

HandleWith()

router.Group("/api").HandleWith(httpserver.With(NewHandler, func(r *httpserver.Router, h *Handler) {
r.GET("/items", httpserver.Bind(h.ListItems))
}))

Registers routes using a RegisterFactoryFunc (typically created with With()).

Handler registration

With[H]()

Usage

router.HandleWith(httpserver.With(NewMyHandler, func(r *httpserver.Router, h *MyHandler) {
r.GET("/items", httpserver.Bind(h.ListItems))
r.POST("/items", httpserver.Bind(h.CreateItem))
}))

Description

Generic function that creates a handler instance via the factory function, then calls the registration function with both a sub-router and the handler. This is the primary pattern for dependency-injected route registration.

The handler factory must have this signature:

func NewMyHandler(ctx context.Context, config cfg.Config, logger log.Logger) (*MyHandler, error)

Request binding

Bind functions

FunctionHandler signatureUse case
Bind[I](ctx, *I) (Response, error)Bind request to input struct
BindR[I](ctx, *http.Request, *I) (Response, error)Bind with raw request access
BindN(ctx) (Response, error)No input binding
BindNR(ctx, *http.Request) (Response, error)No input, with raw request
BindSse[I](ctx, *I, *SseWriter) errorSSE with input binding
BindSseR[I](ctx, *http.Request, *I, *SseWriter) errorSSE with input + raw request
BindSseN(ctx, *SseWriter) errorSSE with no input
BindSseNR(ctx, *http.Request, *SseWriter) errorSSE with raw request, no input

Binding tags

Input structs use standard tags to specify the data source:

TagSourceExample
uriPath parametersuri:"id"
jsonJSON bodyjson:"name"
formQuery string or form bodyform:"limit"
xmlXML bodyxml:"item"
yamlYAML bodyyaml:"config"
headerHTTP headersheader:"X-Request-Id"
bindingValidation rulesbinding:"required,email"

Responses

Response constructors

ConstructorDescription
NewJsonResponse[T](body T, opts ...ResponseOption) *jsonResponse[T]JSON response with Content-Type: application/json
NewTextResponse(text string, opts ...ResponseOption) *responsePlain text response
NewStatusResponse(statusCode int, opts ...ResponseOption) *responseStatus-only response (no body)
NewResponse(opts ...ResponseOption) *responseBase response constructor

Response options

OptionDescription
WithStatusCode(code int)Set the HTTP status code
WithHeader(key, value string)Add a single header
WithHeaders(headers http.Header)Merge multiple headers
WithBody(body []byte)Set raw response body

SSE

SseWriter

Methods

MethodDescription
Send(data string) errorSend a simple SSE data event
SendEvent(event SseEvent) errorSend a structured SSE event
Close()Close the writer and stop heartbeat

SseEvent

FieldTypeDescription
EventstringEvent type name
DatastringEvent payload
IdstringEvent ID for reconnection
RetryintReconnection hint (ms)

Error handling

WithErrorHandler()

httpserver.WithErrorHandler(func(statusCode int, err error) httpserver.Response {
return httpserver.NewJsonResponse(
map[string]any{"error": err.Error()},
httpserver.WithStatusCode(statusCode),
)
})

Sets a custom global error handler. By default, 4xx responses return {"err":"<message>"} and 5xx responses return {"err":"internal server error"}. Set httpserver.<name>.errors.privacy to public to expose 5xx error messages.

GetErrorHandler()

return httpserver.GetErrorHandler()(http.StatusBadRequest, err), nil

Returns the current error handler, useful for returning client errors with specific status codes.

Use NewErrorWithStatus(statusCode, err) when middleware attaches an error to the Gin context and the response should use a status other than 500.

Middleware

Cors()

corsMiddleware, err := httpserver.Cors(config)

Creates a CORS middleware from config keys: api_cors_allowed_origin_pattern, api_cors_allowed_headers, api_cors_allowed_methods.

CreateEmbeddedStaticServe()

router.UseFactory(httpserver.CreateEmbeddedStaticServe(fs, "public", "/api"))

Creates a middleware that serves embedded static files with SPA fallback.

Built-in middleware

The following middleware is automatically applied to every server:

MiddlewarePurpose
SamplingApply sampling decisions
MetricRecord request metrics
LoggingLog requests (fingers-crossed)
CompressionGzip compression
Max body sizeLimit incoming request bodies
ErrorCatch and format errors
RecoveryPanic recovery
Connection lifecycleManage connection age

Validation

AddCustomValidators()

httpserver.AddCustomValidators([]httpserver.CustomValidator{
{Name: "phone", Validator: validatePhone},
})

Register custom field validators for use in binding tags.

  • AddStructValidators([]StructValidator) — Register whole-struct validators
  • AddCustomTypeFuncs([]CustomTypeFunc) — Register custom type functions
  • AddValidateAlias([]ValidateAlias) — Register validation tag aliases

Configuration

Settings

Config key: httpserver.<name>

FieldTypeDefaultDescription
portstring"8080"Listening port. Use "0" for random port.
modestring"release"Gin mode: debug, release, test.
compressionCompressionSettings-Gzip configuration.
timeoutTimeoutSettings-IO timeouts.
loggingLoggingSettings-Request logging configuration.
routerRouterSettings-Router configuration.
max_body_bytesint10485760Maximum incoming request body size in bytes. 0 disables the limit.

TimeoutSettings

FieldTypeDefaultDescription
readduration60sMax duration for reading entire request. Min 1s.
writeduration60sMax duration for writing response. Min 1s.
idleduration60sMax idle time for keep-alive. Min 1s.
drainduration0sWait time before graceful shutdown.
shutdownduration60sMax time for graceful shutdown. Min 1s.

CompressionSettings

FieldTypeDefaultDescription
levelstring"default""none", "default", "fast", "best", "0"-"9".
decompressionbooltrueDecompress gzip request bodies.
excludeCompressionExcludeSettings-Paths/extensions to exclude.

CompressionExcludeSettings

FieldTypeDescription
extensionstring arrayFile extensions to exclude.
pathstring arrayExact paths to exclude.
pathRegexstring arrayRegex patterns to exclude.

LoggingSettings

FieldTypeDefaultDescription
request_bodyboolfalseLog request bodies.
request_body_base64boolfalseBase64-encode request body in logs.
request_headersboolfalseLog request headers.

ConnectionLifeCycleAdvisorSettings

FieldTypeDefaultDescription
enabledbooltrueEnable connection lifecycle management.
max_connection_ageduration1mMax connection age before close.
max_connection_request_countint0Max requests per connection (0 = disabled).