rockfiber

package module
v0.0.0-...-ec73789 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 16, 2026 License: Apache-2.0 Imports: 22 Imported by: 0

README

rockfiber

A fiber-based HTTP server wrapper that integrates with rockengine and provides structured routing, request parsing, error handling, and production middlewares.

Overview

rockfiber wraps gofiber/fiber v2 with a clean API for:

  • Registering endpoints with typed request parsing and validation
  • Lifecycle management compatible with the rockengine App interface
  • Built-in middlewares: CORS, compression, security headers, rate limiting, tracing, pprof, metrics
  • Structured error responses
  • TLS / HTTPS support

Quick Start

app := rockfiber.New(
    rockfiber.Config{
        Port:       "8080",
        UseTraceId: true,
        Compress:   true,
    },
    rockfiber.GET("/hello", helloHandler),
    rockfiber.POST("/users", createUserHandler),
)

// Use standalone
ctx := context.Background()
if err := app.Init(ctx); err != nil {
    log.Fatal(err)
}
if err := app.Exec(ctx); err != nil {
    log.Fatal(err)
}

// Or register with rockengine
engine.MustRegister("http", app, rockengine.RestartPolicy{})
engine.Run()

Loading Config from File

rockfiber.Config is compatible with rockconfig.InitFromFile. Fields that contain functions or third-party complex types are tagged config:"-" and must be set in code — everything else can come from a YAML or JSON file.

# config.yaml
port: "8080"
endpoints_path_prefix: "/api/v1"
admin_password: "secret"
shutdown_timeout: "30s"
use_trace_id: true
compress: true
helmet: true
request_timeout: "5s"
tls_cert_file: "/etc/ssl/cert.pem"  # optional
tls_key_file:  "/etc/ssl/key.pem"   # optional
mask_internal_server_error_message: "internal server error"
cfg, err := rockconfig.InitFromFile[rockfiber.Config]("config.yaml")
if err != nil {
    log.Fatal(err)
}

// Fields that must be set in code
cfg.OnRequest = func(path, traceId string) { ... }
cfg.OnError   = func(traceId string, err *rockfiber.ErrorResponse) { ... }
cfg.CorsConfig = &cors.Config{AllowOrigins: "https://myapp.com"}
cfg.RateLimit  = &limiter.Config{Max: 100, Expiration: time.Minute}

app := rockfiber.New(*cfg,
    rockfiber.GET("/hello", helloHandler),
    rockfiber.POST("/users", createUserHandler),
)
From file Code only (config:"-")
port, admin_password App fiber.Config
endpoints_path_prefix, admin_endpoints_path RateLimit, CorsConfig
use_trace_id, compress, helmet Swagger, MonitoringConfig
request_timeout, shutdown_timeout NotFound, OnRequest, OnError
tls_cert_file, tls_key_file
mask_internal_server_error_message

Config

type Config struct {
    App  fiber.Config  // underlying fiber config (body limit, prefork, etc.)
    Port string        // listening port, e.g. "8080"

    EndpointsPathPrefix string        // common prefix for all endpoints, e.g. "/api/v1"
    AdminEndpointsPath  string        // admin route prefix; defaults to "/admin"
    AdminPassword       string        // X-Admin-Password header value; empty = deny all
    ShutdownTimeout     time.Duration // graceful shutdown timeout; defaults to 30s

    // TLS — both must be set together.
    TLSCertFile string
    TLSKeyFile  string

    // Global middlewares (all routes including /status and admin).
    Compress bool // gzip/deflate/brotli response compression
    Helmet   bool // security headers: X-Frame-Options, X-Content-Type-Options, HSTS, etc.

    // Endpoint middlewares (routes under EndpointsPathPrefix only).
    UseTraceId     bool
    RequestTimeout time.Duration   // sets context deadline; 0 = disabled
    RateLimit      *limiter.Config // nil = disabled

    Swagger          *SwaggerConfig
    MonitoringConfig *monitor.Config
    CorsConfig       *cors.Config   // nil = allow all origins (see CORS section)

    MaskInternalServerErrorMessage string       // masks 500 messages; see Error Handling
    NotFound                       fiber.Handler // catch-all for unmatched routes

    OnRequest func(path, traceId string)
    OnError   func(traceId string, err *ErrorResponse)
}

Endpoints

Method helpers
rockfiber.GET(path, handlers...)
rockfiber.POST(path, handlers...)
rockfiber.PUT(path, handlers...)
rockfiber.PATCH(path, handlers...)
rockfiber.DELETE(path, handlers...)
rockfiber.HEAD(path, handlers...)
rockfiber.OPTIONS(path, handlers...)

Pass middleware handlers before the final handler:

rockfiber.GET("/profile", authMiddleware, getProfileHandler)
Custom method
rockfiber.NewEndpoint("PURGE", "/cache", purgeHandler)
Custom endpoint type

Implement the FiberEndpoint interface to build your own endpoint descriptors:

type FiberEndpoint interface {
    GetPath() string
    GetMethod() string
    GetHandlers() []fiber.Handler
}

Request Parsing

DefaultHandler

DefaultHandler is a generic middleware that parses the request, validates it, and stores the result in ctx.Locals:

type CreateUserParams struct {
    Name  string `json:"name"`
    Email string `json:"email" query:"email"`
}

func (p *CreateUserParams) Validate(ctx *fiber.Ctx) error {
    if p.Name == "" {
        return rockfiber.NewError(http.StatusBadRequest, "name is required")
    }
    return nil
}

rockfiber.POST("/users",
    rockfiber.DefaultHandler[CreateUserParams](),
    createUserHandler,
)

func createUserHandler(ctx *fiber.Ctx) error {
    params, err := rockfiber.GetFromContext[CreateUserParams](ctx, "params")
    // ...
}

Use a custom key when multiple DefaultHandler calls are chained:

rockfiber.DefaultHandler[CreateUserParams]("user")
rockfiber.GetFromContext[CreateUserParams](ctx, "user")
ParseRequest

ParseRequest populates any struct from the incoming request. Supported tags:

Tag Source
query:"name" Query parameter
json:"name" JSON / XML / form body
reqHeader:"name" Request header
params:"name" URL path parameter
form:"name" Multipart file field

Parsing order: query → body → headers → path params. Path params are applied last and overwrite earlier values for the same field.

Multipart file upload
type UploadParams struct {
    Title    string                    `json:"title"`
    File     *multipart.FileHeader     `form:"file"`    // single file
    Gallery  []*multipart.FileHeader   `form:"gallery"` // multiple files
}
Params constraint

Params[T] is the interface your param struct must satisfy to be used with DefaultHandler:

type Params[T any] interface {
    *T
    Validate(ctx *fiber.Ctx) error
}

Error Handling

ErrorResponse

All errors are returned as JSON:

{
  "code": 404,
  "status": "Not Found",
  "message": "user not found",
  "source": "user-service",
  "action": "get"
}

source and action are omitted from JSON when empty.

// Simple error
return rockfiber.NewError(http.StatusNotFound, "user not found")

// With context
return rockfiber.NewError(http.StatusInternalServerError, "query failed").
    WithSource("database").
    WithAction("get-user")

// Return from handler — fiber routes it through ErrorHandler automatically
return rockfiber.NewError(http.StatusUnauthorized, "token expired")
Masking internal errors

Set MaskInternalServerErrorMessage to hide raw 500 error details from clients:

Config{
    MaskInternalServerErrorMessage: "internal server error",
}

The real error message is visible when ?debug= is added to the request URL — useful for investigating issues in any environment without redeployment.

Custom error handler

If cfg.App.ErrorHandler is set, it takes full priority and our handler is not registered:

Config{
    App: fiber.Config{
        ErrorHandler: myCustomHandler,
    },
}
Error logging hook
Config{
    OnError: func(traceId string, err *rockfiber.ErrorResponse) {
        log.Error("request failed",
            rocklog.Str("trace_id", traceId),
            rocklog.Int("code", err.Code),
            rocklog.Str("message", err.Message),
        )
    },
}

Tracing

When UseTraceId: true, every request under EndpointsPathPrefix gets an X-Trace-Id header:

  • If the client sends X-Trace-Id, it is propagated (sanitised: max 64 chars, no control characters).
  • Otherwise a new UUID v4 is generated.

The trace ID is available in handlers via ctx.Locals:

traceId, _ := ctx.Locals(rockfiber.TraceIdKey).(string)

And in response headers automatically.

Request Logging Hook

Config{
    UseTraceId: true,
    OnRequest: func(path, traceId string) {
        log.Info("request received",
            rocklog.Str("path", path),
            rocklog.Str("trace_id", traceId),
        )
    },
}

OnRequest runs after TraceIdMiddleware so the trace ID is always available.

Rate Limiting

Config{
    RateLimit: &limiter.Config{
        Max:        100,
        Expiration: 1 * time.Minute,
    },
}

Rate limiting is applied only to routes under EndpointsPathPrefix. Admin routes and /status are not affected.

Request Timeout

Config{
    RequestTimeout: 5 * time.Second,
}

Sets a context.WithTimeout deadline on every request. Any context-aware operation (database queries, HTTP calls) will respect this deadline automatically. The handler itself is not forcefully terminated — code that ignores the context will still run to completion.

TLS / HTTPS

Config{
    Port:        "443",
    TLSCertFile: "/etc/ssl/cert.pem",
    TLSKeyFile:  "/etc/ssl/key.pem",
}

Both fields must be set together. Omitting one returns an error from Init.

Compression

Config{Compress: true}

Enables gzip / deflate / brotli based on the Accept-Encoding request header. Applied globally to all routes. The middleware auto-detects content type and skips already-compressed formats.

Security Headers (Helmet)

Config{Helmet: true}

Adds: X-XSS-Protection, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Content-Security-Policy, Permissions-Policy, Strict-Transport-Security.

Note: The default CSP may conflict with the Swagger UI. If you use both Helmet: true and Swagger, configure cfg.App with a custom Helmet config instead.

Admin Routes

Registered under AdminEndpointsPath (default /admin), protected by X-Admin-Password header:

Route Description
GET /admin/metrics fiber monitor dashboard
GET /admin/debug/pprof/* Go pprof endpoints

If AdminPassword is empty, all admin requests return 401.

Built-in Routes

Route Description
GET /status Returns {"status":"ok"}

CORS

// Allow all origins (default — safe for public APIs without credentials)
Config{CorsConfig: nil}

// Restrict origins
Config{
    CorsConfig: &cors.Config{
        AllowOrigins: "https://app.example.com",
        AllowHeaders: "Content-Type, Authorization",
    },
}

Warning: The default CORS policy (nil) allows all origins (*). If your API uses cookies or Authorization headers with browser clients, always set CorsConfig explicitly.

Context Helpers

// Store any value in request locals
rockfiber.HandlerInitInCtx[MyStruct]("my-key")

// Retrieve it downstream (type-safe)
val, err := rockfiber.GetFromContext[MyStruct](ctx, "my-key")

Panic Recovery

RecoverHandler is registered globally. On panic it:

  1. Writes the stack trace to stderr
  2. Returns a 500 ErrorResponse to the client (routed through ErrorHandler)

Limitations

  • RequestTimeout sets a context deadline but does not forcefully kill goroutines. Handlers that ignore ctx.Done() complete normally.
  • Helmet: true with Swagger may conflict on Content-Security-Policy.
  • EndpointsPathPrefix should not overlap with /status or AdminEndpointsPath.
  • ?debug= reveals the original error message when MaskInternalServerErrorMessage is set. Restrict this at the gateway level if needed in production.

Documentation

Index

Constants

View Source
const TraceIdKey = "X-Trace-Id"

Variables

This section is empty.

Functions

func AdminAuthMiddleware

func AdminAuthMiddleware(password string) fiber.Handler

AdminAuthMiddleware checks the X-Admin-Password request header. If password is empty, all requests are denied. Uses constant-time comparison to prevent timing attacks.

func CorsHandler

func CorsHandler(cfg *cors.Config) fiber.Handler

CorsHandler returns a CORS middleware. Passing nil uses the fiber default policy.

func DefaultHandler

func DefaultHandler[T any, P Params[T]](key ...string) fiber.Handler

DefaultHandler parses the request into a P, validates it, and stores the result in ctx.Locals under the given key (default: "params"). Use GetFromContext to retrieve it in downstream handlers.

func ErrorHandler

func ErrorHandler(
	maskMessage string,
	onError func(traceId string, err *ErrorResponse),
) func(*fiber.Ctx, error) error

ErrorHandler returns a fiber error handler that serialises errors as ErrorResponse JSON.

maskMessage, when non-empty, replaces raw internal server error messages. The original message is still shown when the ?debug= query param is present.

onError is an optional callback invoked for every error response — use it to integrate rocklog or any other logger without coupling rockfiber to a specific library.

func GetFromContext

func GetFromContext[T any](ctx *fiber.Ctx, keyStr string) (*T, error)

GetFromContext retrieves a *T stored under keyStr in ctx.Locals. Returns an error if the key is missing or the stored value has the wrong type.

func HandlerInitInCtx

func HandlerInitInCtx[T any](keyStr string) fiber.Handler

HandlerInitInCtx returns a middleware that initialises a zero-value *T in ctx.Locals under keyStr. Useful for passing objects between middleware layers.

func MetricsHandler

func MetricsHandler(cfg *monitor.Config) fiber.Handler

MetricsHandler returns a monitor middleware. Passing nil uses a sensible default.

func ParseRequest

func ParseRequest(ctx *fiber.Ctx, params interface{}) error

ParseRequest populates params from the incoming request.

Supported struct tags:

reqHeader:"name"  — request header
query:"name"      — query parameter
params:"name"     — URL path parameter
json/xml/form     — request body (non-GET only)
form:"name"       — multipart file (*multipart.FileHeader or []*multipart.FileHeader)

Parsing order: query → body → headers → path params. Path params are applied last and will overwrite earlier values for the same field.

func PprofHandler

func PprofHandler(prefix string) fiber.Handler

PprofHandler registers pprof routes under the given path prefix.

func RecoverHandler

func RecoverHandler() fiber.Handler

RecoverHandler recovers from panics and writes the stack trace to stderr.

func RequestLogMiddleware

func RequestLogMiddleware(fn func(path, traceId string)) fiber.Handler

RequestLogMiddleware calls fn with the request URI and trace ID before each handler. Use the OnRequest hook in Config instead of wiring this manually.

func RequestTimeoutMiddleware

func RequestTimeoutMiddleware(d time.Duration) fiber.Handler

RequestTimeoutMiddleware sets a context deadline on every request. Any context-aware operation (DB queries, HTTP calls, etc.) will respect this deadline. d must be greater than zero; use Config.RequestTimeout instead of wiring this manually.

func TraceIdMiddleware

func TraceIdMiddleware() fiber.Handler

TraceIdMiddleware generates a new X-Trace-Id UUID for each request, or propagates an existing one if already present in the incoming request headers. Incoming values are sanitised: values longer than 64 chars or containing control characters (e.g. newlines) are rejected and a fresh UUID is generated instead.

Types

type Config

type Config struct {
	// Must be set in code — contains functions and types unsupported by rockconfig.
	App fiber.Config `config:"-"`

	Port string // required

	EndpointsPathPrefix string        `config:",omitempty"` // e.g. "/api/v1"
	AdminEndpointsPath  string        `config:",omitempty"` // defaults to "/admin"
	AdminPassword       string        `config:",omitempty"` // X-Admin-Password header; empty = deny all
	ShutdownTimeout     time.Duration `config:",omitempty"` // defaults to 30s

	// TLS — both must be set together to enable HTTPS.
	TLSCertFile string `config:",omitempty"`
	TLSKeyFile  string `config:",omitempty"`

	// Global middlewares (all routes including /status and admin).
	Compress bool `config:",omitempty"` // gzip/deflate/brotli compression
	Helmet   bool `config:",omitempty"` // security headers: X-Frame-Options, CSP, HSTS, etc.

	// Endpoint middlewares (routes under EndpointsPathPrefix only).
	UseTraceId     bool          `config:",omitempty"`
	RequestTimeout time.Duration `config:",omitempty"` // context deadline; 0 = disabled

	// Must be set in code — complex third-party config types.
	RateLimit        *limiter.Config `config:"-"` // nil = disabled
	Swagger          *SwaggerConfig  `config:"-"` // nil = disabled
	MonitoringConfig *monitor.Config `config:"-"` // nil = default
	CorsConfig       *cors.Config    `config:"-"` // nil = allow all origins

	// MaskInternalServerErrorMessage replaces raw 500 messages in responses.
	// The real message is still visible via ?debug= query param.
	MaskInternalServerErrorMessage string `config:",omitempty"`

	// Must be set in code — function types.
	NotFound  fiber.Handler                            `config:"-"` // catch-all for unmatched routes
	OnRequest func(path, traceId string)               `config:"-"` // called at the start of every request
	OnError   func(traceId string, err *ErrorResponse) `config:"-"` // called on error responses
}

Config holds all configuration for a FiberApp.

Compatible with rockconfig.InitFromFile — fields marked config:"-" cannot be loaded from a file and must be set in code. All other fields are optional (omitempty) except Port which is required.

Example config.yaml:

port: "8080"
endpoints_path_prefix: "/api/v1"
admin_password: "secret"
use_trace_id: true
compress: true
helmet: true
request_timeout: "5s"
mask_internal_server_error_message: "internal server error"

type Endpoint

type Endpoint[HandlerFunc any] interface {
	GetPath() string
	GetMethod() string
	GetHandlers() []HandlerFunc
}

Endpoint is a generic route descriptor.

type ErrorResponse

type ErrorResponse struct {
	Code    int    `json:"code"`
	Status  string `json:"status"`
	Message string `json:"message"`
	Source  string `json:"source,omitempty"`
	Action  string `json:"action,omitempty"`
}

ErrorResponse is the standard error payload returned by all API error responses. It implements the error interface, so it can be returned directly from fiber handlers.

func NewError

func NewError(statusCode int, message string) *ErrorResponse

NewError creates an ErrorResponse with the given HTTP status code and message.

func (*ErrorResponse) Error

func (e *ErrorResponse) Error() string

func (*ErrorResponse) WithAction

func (e *ErrorResponse) WithAction(action string) *ErrorResponse

WithAction sets the Action field and returns the receiver for chaining.

func (*ErrorResponse) WithSource

func (e *ErrorResponse) WithSource(source string) *ErrorResponse

WithSource sets the Source field and returns the receiver for chaining.

type FiberApp

type FiberApp struct {
	// contains filtered or unexported fields
}

FiberApp is a fiber-based HTTP server that satisfies the rockengine App interface:

Init(ctx context.Context) error
Exec(ctx context.Context) error
Stop() []error

func New

func New(cfg Config) *FiberApp

New creates a FiberApp with the given config and endpoints. Pass endpoints via NewEndpoint, GET, POST, etc.

func (*FiberApp) Exec

func (a *FiberApp) Exec(ctx context.Context) error

Exec registers endpoints and starts the HTTP server. Blocks until ctx is cancelled or the server exits with an error.

func (*FiberApp) Init

func (a *FiberApp) Init(_ context.Context) error

Init sets up the fiber instance and registers global middlewares.

func (*FiberApp) SetEndpoints

func (a *FiberApp) SetEndpoints(endpoints []FiberEndpoint)

func (*FiberApp) Stop

func (a *FiberApp) Stop() []error

Stop gracefully shuts down the HTTP server. Safe to call multiple times — only the first call takes effect.

type FiberEndpoint

type FiberEndpoint Endpoint[fiber.Handler]

FiberEndpoint is an Endpoint for fiber handlers.

func DELETE

func DELETE(path string, handlers ...fiber.Handler) FiberEndpoint

func GET

func GET(path string, handlers ...fiber.Handler) FiberEndpoint
func HEAD(path string, handlers ...fiber.Handler) FiberEndpoint

func NewEndpoint

func NewEndpoint(method, path string, handlers ...fiber.Handler) FiberEndpoint

NewEndpoint creates a FiberEndpoint with the given method, path and handlers.

func OPTIONS

func OPTIONS(path string, handlers ...fiber.Handler) FiberEndpoint

func PATCH

func PATCH(path string, handlers ...fiber.Handler) FiberEndpoint

func POST

func POST(path string, handlers ...fiber.Handler) FiberEndpoint

func PUT

func PUT(path string, handlers ...fiber.Handler) FiberEndpoint

type Params

type Params[T any] interface {
	*T
	Validate(ctx *fiber.Ctx) error
}

Params is a constraint for request parameter structs that validate themselves.

type SwaggerConfig

type SwaggerConfig struct {
	Path            string
	Config          swagger.Config
	OAuth           *swagger.OAuthConfig
	Filter          swagger.FilterConfig
	SyntaxHighlight *swagger.SyntaxHighlightConfig
}

SwaggerConfig configures the Swagger UI endpoint.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL