fiberresp

package module
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Jun 14, 2026 License: MIT Imports: 4 Imported by: 0

README

fiberresp 🚨

Go Report Card Go Reference Go Version

Elegant HTTP response handling for Fiber applications with support for custom errors and internationalization.

✨ Features

  • 🎯 Simple Integration - Easy to integrate with existing Fiber applications
  • 🔧 Custom Error Types - Create your own error types with custom codes
  • 🌍 i18n Support - Built-in internationalization for error messages
  • High Performance - Optimized for speed and efficiency
  • 🎨 Flexible Configuration - Customizable response formats
  • 📦 Standard HTTP Errors - Pre-defined standard HTTP error responses

📊 Performance

BenchmarkFiberResp_Response-12                     4781 ns/op   11162 B/op   36 allocs/op
BenchmarkFiberResp_DirectResponse-12              4699 ns/op   11139 B/op   36 allocs/op
BenchmarkBuildInErrorResponse_Response-12         4730 ns/op   11136 B/op   36 allocs/op
BenchmarkFiberResp_FastCustomResponse-12          4739 ns/op   11080 B/op   36 allocs/op
BenchmarkFiberResp_ResponseFastCustomResponse-12   4679 ns/op   11081 B/op   36 allocs/op
BenchmarkFiberResp_BadRequestBody-12              4646 ns/op   11063 B/op   36 allocs/op
BenchmarkFiberResp_ErrorBody-12                   5213 ns/op   11038 B/op   36 allocs/op
BenchmarkFiberResp_BadRequestBodyWithParam-12     4894 ns/op   11401 B/op   38 allocs/op

The previous github.com/prongbang/fibererror module should remain available as the legacy v1 module for existing users.

📦 Installation

go get github.com/prongbang/fiberresp

🚀 Quick Start

Use fiberresp.Response for the shortest and fastest no-config path:

Basic Usage with Standard HTTP Status
package main

import (
    "github.com/prongbang/goerror"
    "github.com/prongbang/fiberresp"
    "github.com/gofiber/fiber/v2"
)

func main() {
    app := fiber.New()
    
    app.Get("/", func(c *fiber.Ctx) error {
        return fiberresp.Response(c, goerror.NewUnauthorized())
    })
    
    _ = app.Listen(":3000")
}
Custom Response Body
func handler(c *fiber.Ctx) error {
    return fiberresp.Response(c,
        fiberresp.BadRequest("VAL001", "validation.field.required").
            WithParam("field", "email").
            WithData(map[string]any{"field": "email"}).
            WithCause("email is empty"),
    )
}

The message argument can be plain text when you do not use i18n:

func handler(c *fiber.Ctx) error {
    return fiberresp.Response(c,
        fiberresp.BadRequest("VAL001", "Email is required"),
    )
}

Use fiberresp.Error for any HTTP status:

func handler(c *fiber.Ctx) error {
    return fiberresp.Response(c,
        fiberresp.Error(http.StatusConflict, "CNF001", "conflict.resource_exists"),
    )
}

Convenience constructors are also available for every net/http status, for example BadRequest, Unauthorized, NotFound, InternalServerError, and ServiceUnavailable.

Use fiberresp.New(...).Response when you need shared configuration such as i18n or a custom response handler.

🛠️ Advanced Usage

Custom Error Types

Create your own error types with custom codes:

package main

import (
    "github.com/prongbang/goerror"
    "github.com/prongbang/fiberresp"
    "github.com/gofiber/fiber/v2"
    "net/http"
)

type CustomError struct {
    goerror.Body
}

func (c *CustomError) Error() string {
    return c.Message
}

func (c *CustomError) StatusCode() int {
    return http.StatusBadRequest
}

func NewCustomError() error {
    return &CustomError{
        Body: goerror.Body{
            Code:    "CUS001",
            Message: "Custom error occurred",
        },
    }
}

func main() {
    app := fiber.New()
    
    app.Get("/", func(c *fiber.Ctx) error {
        return fiberresp.Response(c, NewCustomError())
    })
    
    _ = app.Listen(":3000")
}
🌍 Internationalization Support

Localize error messages based on Accept-Language header. The error code stays as an application error code, while the message key is read from Body.Message or a custom MessageKey() string method. If i18n is disabled or localization fails, fiberresp keeps the original message value and sends it as plain text.

1. Create localization files

localize/en.yaml:

custom.error: Custom error {{.ID}}

localize/th.yaml:

custom.error: ข้อผิดพลาดแบบกำหนดเอง {{.ID}}
2. Configure i18n with fiberresp
package main

import (
    "fmt"
    "net/http"

    "github.com/gofiber/contrib/fiberi18n/v2"
    "github.com/gofiber/fiber/v2"
    "github.com/nicksnyder/go-i18n/v2/i18n"
    "github.com/prongbang/fiberresp"
    "github.com/prongbang/goerror"
    "golang.org/x/text/language"
)

type CustomError struct {
    goerror.Body
    Args any `json:"-"`
}

func (c *CustomError) Error() string {
    return c.Message
}

func (c *CustomError) MessageArgs() any {
    return c.Args
}

func (c *CustomError) StatusCode() int {
    return http.StatusBadRequest
}

func (c *CustomError) SetMessage(message string) {
    c.Message = message
}

func NewCustomError() error {
    return &CustomError{
        Body: goerror.Body{
            Code:    "CUS001",
            Message: "custom.error",
        },
        Args: map[string]any{
            "ID": "001",
        },
    }
}

func main() {
    app := fiber.New()
    
    // Configure i18n middleware
    app.Use(fiberi18n.New(&fiberi18n.Config{
        RootPath:        "./localize",
        AcceptLanguages: []language.Tag{language.Thai, language.English},
        DefaultLanguage: language.English,
    }))
    
    // Configure fiberresp with i18n
    response := fiberresp.New(&fiberresp.Config{
        I18n: &fiberresp.I18n{
            Enabled: true,
            LocalizeWithArgs: func(ctx *fiber.Ctx, messageKey string, args any) (string, error) {
                return fiberi18n.Localize(ctx, &i18n.LocalizeConfig{
                    MessageID:    messageKey,
                    TemplateData: args,
                })
            },
        },
    })
    
    app.Get("/", func(c *fiber.Ctx) error {
        return response.Response(c, NewCustomError())
    })
    
    err := app.Listen(":3000")
    if err != nil {
        fmt.Println("Error starting server:", err)
    }
}

📝 Configuration Options

fiberresp.Config
Option Type Description
Custom *Custom Custom error response handler
I18n *I18n Internationalization configuration
API Use case
fiberresp.Response(c, err) Fastest and shortest no-config response
fiberresp.Error(status, code, key) Custom response body for any HTTP status
fiberresp.Status(status, code, key) Alias for custom response body by HTTP status
fiberresp.NewBody(status, code, key) Low-level body constructor
fiberresp.BadRequest(code, key).WithParam(key, value) Short custom response body with i18n args
fiberresp.New(config).Response(c, err) Reusable configured response for i18n/custom handlers
fiberresp.New(config).With(c).Response(err) Backward-compatible convenience style
Body Constructors

fiberresp.Error, fiberresp.Status, and fiberresp.NewBody work with any HTTP status code:

fiberresp.Error(http.StatusConflict, "CNF001", "conflict.resource_exists")
fiberresp.Status(http.StatusInternalServerError, "SRV001", "server.error")
fiberresp.NewBody(http.StatusAccepted, "JOB001", "job.accepted")

Convenience constructors are available for every net/http status, including:

fiberresp.OK("OK001", "ok")
fiberresp.Created("CRT001", "created")
fiberresp.BadRequest("VAL001", "validation.failed")
fiberresp.Unauthorized("AUT001", "auth.unauthorized")
fiberresp.Forbidden("AUT002", "auth.forbidden")
fiberresp.NotFound("USR001", "user.not_found")
fiberresp.Conflict("CNF001", "conflict")
fiberresp.UnprocessableEntity("VAL002", "validation.unprocessable")
fiberresp.TooManyRequests("RAT001", "rate_limited")
fiberresp.InternalServerError("SRV001", "server.error")
fiberresp.ServiceUnavailable("SRV002", "service.unavailable")
Body Methods
Method Description
WithData(data any) *Body Set response data
WithCause(cause string) *Body Set error cause
WithParam(key string, value any) *Body Set one i18n template argument
WithParams(args map[string]any) *Body Set many i18n template arguments
fiberresp.I18n
Option Type Description
Enabled bool Enable/disable i18n support
Localize func(*fiber.Ctx, string) (string, error) Localization function for a message key
LocalizeWithArgs func(*fiber.Ctx, string, any) (string, error) Localization function for a message key with template arguments
Message Key and Arguments

Message can be either a plain text response message or an i18n key:

fiberresp.BadRequest("VAL001", "Email is required")
fiberresp.BadRequest("VAL001", "validation.email.required")

When i18n is enabled and localization succeeds, the localized text replaces Message before the JSON response is written. Otherwise, the original Message is returned unchanged.

fiberresp resolves i18n keys in this order:

  1. MessageKey() string
  2. MessageKey string field
  3. goerror.Body.Message

Arguments are optional and resolved in this order:

  1. MessageArgs() any
  2. MessageArgs, Arguments, or Args field

The localized text is written back to goerror.Body.Message before your custom response handler serializes the error.

For the fastest custom error path, implement:

  1. StatusCode() int so fiberresp can write the response directly without a custom handler switch
  2. SetMessage(message string) so i18n can write the localized message without reflection

🔍 Examples

Returning From Application Layers

Return error from datasource, repository, usecase, and handler layers. The handler should be the single place that writes the Fiber response:

func (r *UserRepository) FindByEmail(email string) (*User, error) {
    user, err := r.db.FindByEmail(email)
    if errors.Is(err, sql.ErrNoRows) {
        return nil, fiberresp.NotFound("USR001", "user.not_found").
            WithParam("email", email)
    }
    if err != nil {
        return nil, fiberresp.InternalServerError("USR999", "user.query_failed")
    }
    return user, nil
}

func (s *UserService) GetUser(email string) (*User, error) {
    user, err := s.repo.FindByEmail(email)
    if err != nil {
        return nil, err
    }
    if !user.Active {
        return nil, fiberresp.Forbidden("USR002", "user.inactive")
    }
    return user, nil
}

func (h *UserHandler) Get(c *fiber.Ctx) error {
    user, err := h.service.GetUser(c.Params("email"))
    if err != nil {
        return fiberresp.Response(c, err)
    }
    return fiberresp.Response(c, goerror.NewOK(user))
}

WithCause is sent to clients, so only use it for safe, public details. Avoid putting raw SQL, stack traces, secrets, tokens, or internal hostnames in cause.

Response Format

Standard error response structure:

{
    "code": "CUS001",
    "message": "Custom error message"
}

With additional fields:

{
    "code": "VAL001",
    "message": "Validation failed",
    "data": {
        "field": "email",
        "reason": "invalid format"
    },
    "cause": "email is empty"
}

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

💖 Support the Project

If you find this package helpful, please consider supporting it:

  • goerror - Error handling utilities for Go
  • Fiber - Express-inspired web framework
  • fiberi18n - i18n middleware for Fiber

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Respond added in v1.2.0

func Respond(c *fiber.Ctx, err error) error

func Response added in v1.2.0

func Response(c *fiber.Ctx, err error) error

Types

type Body added in v1.2.0

type Body struct {
	Code    string         `json:"code"`
	Message string         `json:"message"`
	Data    any            `json:"data,omitempty"`
	Cause   *string        `json:"cause,omitempty"`
	Args    map[string]any `json:"-"`
	// contains filtered or unexported fields
}

func Accepted added in v1.2.0

func Accepted(code string, messageKey string) *Body

func AlreadyReported added in v1.2.0

func AlreadyReported(code string, messageKey string) *Body

func BadGateway added in v1.2.0

func BadGateway(code string, messageKey string) *Body

func BadRequest added in v1.2.0

func BadRequest(code string, messageKey string) *Body

func Conflict added in v1.2.0

func Conflict(code string, messageKey string) *Body

func Continue added in v1.2.0

func Continue(code string, messageKey string) *Body

func Created added in v1.2.0

func Created(code string, messageKey string) *Body

func EarlyHints added in v1.2.0

func EarlyHints(code string, messageKey string) *Body

func Error added in v1.2.0

func Error(status int, code string, messageKey string) *Body

func ExpectationFailed added in v1.2.0

func ExpectationFailed(code string, messageKey string) *Body

func FailedDependency added in v1.2.0

func FailedDependency(code string, messageKey string) *Body

func Forbidden added in v1.2.0

func Forbidden(code string, messageKey string) *Body

func Found added in v1.2.0

func Found(code string, messageKey string) *Body

func GatewayTimeout added in v1.2.0

func GatewayTimeout(code string, messageKey string) *Body

func Gone added in v1.2.0

func Gone(code string, messageKey string) *Body

func HTTPVersionNotSupported added in v1.2.0

func HTTPVersionNotSupported(code string, messageKey string) *Body

func IMUsed added in v1.2.0

func IMUsed(code string, messageKey string) *Body

func InsufficientStorage added in v1.2.0

func InsufficientStorage(code string, messageKey string) *Body

func InternalServerError added in v1.2.0

func InternalServerError(code string, messageKey string) *Body

func LengthRequired added in v1.2.0

func LengthRequired(code string, messageKey string) *Body

func Locked added in v1.2.0

func Locked(code string, messageKey string) *Body

func LoopDetected added in v1.2.0

func LoopDetected(code string, messageKey string) *Body

func MethodNotAllowed added in v1.2.0

func MethodNotAllowed(code string, messageKey string) *Body

func MisdirectedRequest added in v1.2.0

func MisdirectedRequest(code string, messageKey string) *Body

func MovedPermanently added in v1.2.0

func MovedPermanently(code string, messageKey string) *Body

func MultiStatus added in v1.2.0

func MultiStatus(code string, messageKey string) *Body

func MultipleChoices added in v1.2.0

func MultipleChoices(code string, messageKey string) *Body

func NetworkAuthenticationRequired added in v1.2.0

func NetworkAuthenticationRequired(code string, messageKey string) *Body

func NewBody added in v1.2.0

func NewBody(status int, code string, messageKey string) *Body

func NoContent added in v1.2.0

func NoContent(code string, messageKey string) *Body

func NonAuthoritativeInformation added in v1.2.0

func NonAuthoritativeInformation(code string, messageKey string) *Body

func NotAcceptable added in v1.2.0

func NotAcceptable(code string, messageKey string) *Body

func NotExtended added in v1.2.0

func NotExtended(code string, messageKey string) *Body

func NotFound added in v1.2.0

func NotFound(code string, messageKey string) *Body

func NotImplemented added in v1.2.0

func NotImplemented(code string, messageKey string) *Body

func NotModified added in v1.2.0

func NotModified(code string, messageKey string) *Body

func OK added in v1.2.0

func OK(code string, messageKey string) *Body

func PartialContent added in v1.2.0

func PartialContent(code string, messageKey string) *Body

func PaymentRequired added in v1.2.0

func PaymentRequired(code string, messageKey string) *Body

func PermanentRedirect added in v1.2.0

func PermanentRedirect(code string, messageKey string) *Body

func PreconditionFailed added in v1.2.0

func PreconditionFailed(code string, messageKey string) *Body

func PreconditionRequired added in v1.2.0

func PreconditionRequired(code string, messageKey string) *Body

func Processing added in v1.2.0

func Processing(code string, messageKey string) *Body

func ProxyAuthRequired added in v1.2.0

func ProxyAuthRequired(code string, messageKey string) *Body

func RequestEntityTooLarge added in v1.2.0

func RequestEntityTooLarge(code string, messageKey string) *Body

func RequestHeaderFieldsTooLarge added in v1.2.0

func RequestHeaderFieldsTooLarge(code string, messageKey string) *Body

func RequestTimeout added in v1.2.0

func RequestTimeout(code string, messageKey string) *Body

func RequestURITooLong added in v1.2.0

func RequestURITooLong(code string, messageKey string) *Body

func RequestedRangeNotSatisfiable added in v1.2.0

func RequestedRangeNotSatisfiable(code string, messageKey string) *Body

func ResetContent added in v1.2.0

func ResetContent(code string, messageKey string) *Body

func SeeOther added in v1.2.0

func SeeOther(code string, messageKey string) *Body

func ServiceUnavailable added in v1.2.0

func ServiceUnavailable(code string, messageKey string) *Body

func Status added in v1.2.0

func Status(status int, code string, messageKey string) *Body

func SwitchingProtocols added in v1.2.0

func SwitchingProtocols(code string, messageKey string) *Body

func Teapot added in v1.2.0

func Teapot(code string, messageKey string) *Body

func TemporaryRedirect added in v1.2.0

func TemporaryRedirect(code string, messageKey string) *Body

func TooEarly added in v1.2.0

func TooEarly(code string, messageKey string) *Body

func TooManyRequests added in v1.2.0

func TooManyRequests(code string, messageKey string) *Body

func Unauthorized added in v1.2.0

func Unauthorized(code string, messageKey string) *Body

func UnavailableForLegalReasons added in v1.2.0

func UnavailableForLegalReasons(code string, messageKey string) *Body

func UnprocessableEntity added in v1.2.0

func UnprocessableEntity(code string, messageKey string) *Body

func UnsupportedMediaType added in v1.2.0

func UnsupportedMediaType(code string, messageKey string) *Body

func UpgradeRequired added in v1.2.0

func UpgradeRequired(code string, messageKey string) *Body

func UseProxy added in v1.2.0

func UseProxy(code string, messageKey string) *Body

func VariantAlsoNegotiates added in v1.2.0

func VariantAlsoNegotiates(code string, messageKey string) *Body

func (*Body) Error added in v1.2.0

func (b *Body) Error() string

func (*Body) MessageArgs added in v1.2.0

func (b *Body) MessageArgs() any

func (*Body) MessageKey added in v1.2.0

func (b *Body) MessageKey() string

func (*Body) SetMessage added in v1.2.0

func (b *Body) SetMessage(message string)

func (*Body) StatusCode added in v1.2.0

func (b *Body) StatusCode() int

func (*Body) WithCause added in v1.2.0

func (b *Body) WithCause(cause string) *Body

func (*Body) WithData added in v1.2.0

func (b *Body) WithData(data any) *Body

func (*Body) WithParam added in v1.2.0

func (b *Body) WithParam(key string, value any) *Body

func (*Body) WithParams added in v1.2.0

func (b *Body) WithParams(args map[string]any) *Body

type Config

type Config struct {
	Custom *Custom
	I18n   *I18n
}

type Custom added in v1.2.0

type Custom interface {
	Response(ctx *fiber.Ctx, err error) error
}

type HttpResponse added in v1.2.0

type HttpResponse interface {
	Response(err error) error
}

type I18n added in v1.2.0

type I18n struct {
	Enabled bool
	// Localize resolves a message key to a localized message.
	// Deprecated: use LocalizeWithArgs when the message needs template data.
	Localize         func(c *fiber.Ctx, messageKey string) (string, error)
	LocalizeWithArgs func(c *fiber.Ctx, messageKey string, args any) (string, error)
}

type MessageArgser added in v1.2.0

type MessageArgser interface {
	MessageArgs() any
}

type MessageKeyer added in v1.2.0

type MessageKeyer interface {
	MessageKey() string
}

type MessageSetter added in v1.2.0

type MessageSetter interface {
	SetMessage(message string)
}

type Responder added in v1.2.0

type Responder interface {
	With(c *fiber.Ctx) HttpResponse
	Response(c *fiber.Ctx, err error) error
}

func New

func New(config ...*Config) Responder

type StatusCoder added in v1.2.0

type StatusCoder interface {
	StatusCode() int
}

Jump to

Keyboard shortcuts

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