fiberoapi

package module
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Aug 31, 2025 License: MIT Imports: 8 Imported by: 0

README

Fiber OpenAPI

A Go library that extends Fiber to add automatic OpenAPI documentation generation with built-in validation and group support.

Features

  • Complete HTTP methods (GET, POST, PUT, DELETE) with automatic validation
  • Group support with OpenAPI methods available on both app and groups
  • Unified API with interface-based approach for seamless app/group usage
  • Powerful validation via github.com/go-playground/validator/v10
  • Type safety with Go generics
  • Custom error handling
  • OpenAPI documentation generation with automatic schema generation
  • Redoc documentation UI for modern, responsive API documentation
  • Support for path, query, and body parameters
  • Automatic documentation setup with configurable paths

Installation

go get github.com/labbs/fiber-oapi

Quick Start

Basic Usage with Default Configuration
package main

import (
    "github.com/gofiber/fiber/v2"
    fiberoapi "github.com/labbs/fiber-oapi"
)

func main() {
    app := fiber.New()
    
    // Create OApi app with default configuration
    // Documentation will be available at /documentation (Redoc UI) and /openapi.json
    oapi := fiberoapi.New(app)

    // Your routes here...

    oapi.Listen(":3000")
}
Using Groups
func main() {
    app := fiber.New()
    oapi := fiberoapi.New(app)

    // Create groups with OpenAPI support
    v1 := fiberoapi.Group(oapi, "/api/v1")
    v2 := fiberoapi.Group(oapi, "/api/v2")
    
    // Nested groups
    users := fiberoapi.Group(v1, "/users")
    admin := fiberoapi.Group(v1, "/admin")

    // Routes work the same on app, groups, and nested groups
    fiberoapi.Get(oapi, "/health", handler, options)     // On app
    fiberoapi.Get(v1, "/status", handler, options)       // On group
    fiberoapi.Post(users, "/", handler, options)         // On nested group

    oapi.Listen(":3000")
}
Custom Configuration
func main() {
    app := fiber.New()
    
    // Custom configuration
    config := fiberoapi.Config{
        EnableValidation:  true,                // Enable input validation
        EnableOpenAPIDocs: true,                // Enable automatic docs setup
        OpenAPIDocsPath:   "/documentation",    // Custom docs path
        OpenAPIJSONPath:   "/api-spec.json",    // Custom spec path
    }
    oapi := fiberoapi.New(app, config)

    // Your routes here...

    oapi.Listen(":3000")
}

Usage Examples

GET with path parameters and validation
type GetInput struct {
    Name string `path:"name" validate:"required,min=2"`
}

type GetOutput struct {
    Message string `json:"message"`
}

type GetError struct {
    Code    int    `json:"code"`
    Message string `json:"message"`
}

// Works on app
fiberoapi.Get(oapi, "/greeting/:name", 
    func(c *fiber.Ctx, input GetInput) (GetOutput, GetError) {
        return GetOutput{Message: "Hello " + input.Name}, GetError{}
    }, 
    fiberoapi.OpenAPIOptions{
        OperationID: "get-greeting",
        Tags:        []string{"greeting"},
        Summary:     "Get a personalized greeting",
    })

// Works on groups too
v1 := fiberoapi.Group(oapi, "/api/v1")
fiberoapi.Get(v1, "/greeting/:name", handler, options)
POST with JSON body and validation
type CreateUserInput struct {
    Username string `json:"username" validate:"required,min=3,max=20,alphanum"`
    Email    string `json:"email" validate:"required,email"`
    Age      int    `json:"age" validate:"required,min=13,max=120"`
}

type CreateUserOutput struct {
    ID      string `json:"id"`
    Message string `json:"message"`
}

type CreateUserError struct {
    Code    int    `json:"code"`
    Message string `json:"message"`
}

fiberoapi.Post(oapi, "/users", 
    func(c *fiber.Ctx, input CreateUserInput) (CreateUserOutput, CreateUserError) {
        if input.Username == "admin" {
            return CreateUserOutput{}, CreateUserError{
                Code:    403,
                Message: "Username 'admin' is reserved",
            }
        }
        
        return CreateUserOutput{
            ID:      "user_" + input.Username,
            Message: "User created successfully",
        }, CreateUserError{}
    }, 
    fiberoapi.OpenAPIOptions{
        OperationID: "create-user",
        Tags:        []string{"users"},
        Summary:     "Create a new user",
    })
PUT with path parameters and JSON body
type UpdateUserInput struct {
    ID       string `path:"id" validate:"required"`
    Username string `json:"username" validate:"omitempty,min=3,max=20,alphanum"`
    Email    string `json:"email" validate:"omitempty,email"`
    Age      int    `json:"age" validate:"omitempty,min=13,max=120"`
}

type UpdateUserOutput struct {
    ID      string `json:"id"`
    Message string `json:"message"`
    Updated bool   `json:"updated"`
}

fiberoapi.Put(oapi, "/users/:id", 
    func(c *fiber.Ctx, input UpdateUserInput) (UpdateUserOutput, CreateUserError) {
        if input.ID == "notfound" {
            return UpdateUserOutput{}, CreateUserError{
                Code:    404,
                Message: "User not found",
            }
        }
        
        return UpdateUserOutput{
            ID:      input.ID,
            Message: "User updated successfully",
            Updated: true,
        }, CreateUserError{}
    }, 
    fiberoapi.OpenAPIOptions{
        OperationID: "update-user",
        Tags:        []string{"users"},
        Summary:     "Update an existing user",
    })
DELETE with path parameters
type DeleteUserInput struct {
    ID string `path:"id" validate:"required"`
}

type DeleteUserOutput struct {
    ID      string `json:"id"`
    Message string `json:"message"`
    Deleted bool   `json:"deleted"`
}

fiberoapi.Delete(oapi, "/users/:id", 
    func(c *fiber.Ctx, input DeleteUserInput) (DeleteUserOutput, CreateUserError) {
        if input.ID == "protected" {
            return DeleteUserOutput{}, CreateUserError{
                Code:    403,
                Message: "User is protected and cannot be deleted",
            }
        }
        
        return DeleteUserOutput{
            ID:      input.ID,
            Message: "User deleted successfully",
            Deleted: true,
        }, CreateUserError{}
    }, 
    fiberoapi.OpenAPIOptions{
        OperationID: "delete-user",
        Tags:        []string{"users"},
        Summary:     "Delete a user",
    })

Configuration

The library supports flexible configuration through the Config struct:

type Config struct {
    EnableValidation  bool   // Enable/disable input validation (default: true)
    EnableOpenAPIDocs bool   // Enable automatic docs setup (default: true)
    OpenAPIDocsPath   string // Path for documentation UI (default: "/docs")
    OpenAPIJSONPath   string // Path for OpenAPI JSON spec (default: "/openapi.json")
}
Default Configuration

If no configuration is provided, the library uses these defaults:

  • Validation: enabled
  • Documentation: enabled
  • Docs path: /docs
  • JSON spec path: /openapi.json
Disabling Features
// Disable documentation but keep validation
config := fiberoapi.Config{
    EnableValidation:  true,
    EnableOpenAPIDocs: false,
}

// Or disable validation but keep docs
config := fiberoapi.Config{
    EnableValidation:  false,
    EnableOpenAPIDocs: true,
    OpenAPIDocsPath:   "/api-docs",
    OpenAPIJSONPath:   "/openapi.json",
}

Validation

This library uses validator/v10 for validation. You can use all supported validation tags:

  • required - Required field
  • min=3,max=20 - Min/max length
  • email - Valid email format
  • alphanum - Alphanumeric characters only
  • uuid4 - UUID version 4
  • url - Valid URL
  • oneof=admin user guest - Value from a list
  • dive - Validation for slice elements
  • gtfield=MinPrice - Greater than another field

Supported Parameter Types

  • Path parameters: path:"paramName" (GET, POST, PUT, DELETE)
  • Query parameters: query:"paramName" (GET, DELETE)
  • JSON body: json:"fieldName" (POST, PUT)

Supported HTTP Methods

All methods work with both the main app and groups through the unified API:

  • GET: fiberoapi.Get() - Retrieve resources with path/query parameters
  • POST: fiberoapi.Post() - Create resources with JSON body + optional path parameters
  • PUT: fiberoapi.Put() - Update resources with path parameters + JSON body
  • DELETE: fiberoapi.Delete() - Delete resources with path parameters + optional query parameters
Legacy Method Names (Still Supported)

For backward compatibility, the old method names are still available:

  • fiberoapi.GetOApi()
  • fiberoapi.PostOApi()
  • fiberoapi.PutOApi()
  • fiberoapi.DeleteOApi()

Groups

Fiber-oapi provides full support for Fiber groups while maintaining access to OpenAPI methods:

// Create the main app
app := fiber.New()
oapi := fiberoapi.New(app)

// Create groups - they have access to all Fiber Router methods AND OpenAPI methods
v1 := fiberoapi.Group(oapi, "/api/v1")
v2 := fiberoapi.Group(oapi, "/api/v2")

// Nested groups work too
users := fiberoapi.Group(v1, "/users")
admin := fiberoapi.Group(v1, "/admin")

// Use OpenAPI methods on any router (app or group)
fiberoapi.Get(oapi, "/health", healthHandler, options)        // Main app
fiberoapi.Get(v1, "/status", statusHandler, options)          // Group
fiberoapi.Post(users, "/", createUserHandler, options)        // Nested group
fiberoapi.Put(users, "/:id", updateUserHandler, options)      // Nested group

// Use standard Fiber Router methods on groups (inherited via embedding)
v1.Use("/protected", authMiddleware)                          // Middleware
admin.Get("/stats", func(c *fiber.Ctx) error {              // Regular Fiber handler
    return c.JSON(fiber.Map{"stats": "data"})
})

// For static files, use the main Fiber app
app.Static("/files", "./uploads")  // Static files via main app

// Groups preserve full path context for OpenAPI documentation
// fiberoapi.Get(users, "/:id", ...) registers as GET /api/v1/users/{id}
Group Features
  • Fiber Router compatibility: Groups embed fiber.Router so standard Router methods work (Use, Get, Post, etc.)
  • OpenAPI method support: Use fiberoapi.Get(), fiberoapi.Post(), etc. on groups
  • Nested groups: Create groups within groups with proper path handling
  • Path prefix handling: OpenAPI paths are automatically constructed with full prefixes
  • Unified API: Same function names work on both app and groups through interface polymorphism

Note: For features like static file serving, use the main Fiber app: app.Static("/path", "./dir")

Error Handling

Validation errors are automatically formatted and returned with HTTP status 400:

{
  "error": "Validation failed",
  "details": "Key: 'CreateUserInput.Username' Error:Field validation for 'Username' failed on the 'min' tag"
}

Custom errors use the StatusCode from your error struct.

Testing

Run tests:

go test -v

Complete Example with Groups

package main

import (
    "github.com/gofiber/fiber/v2"
    fiberoapi "github.com/labbs/fiber-oapi"
)

type UserInput struct {
    ID int `path:"id" validate:"required,min=1"`
}

type UserOutput struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}

type UserError struct {
    Message string `json:"message"`
}

func main() {
    app := fiber.New()
    oapi := fiberoapi.New(app)

    // Global routes
    fiberoapi.Get(oapi, "/health", func(c *fiber.Ctx, input struct{}) (map[string]string, struct{}) {
        return map[string]string{"status": "ok"}, struct{}{}
    }, fiberoapi.OpenAPIOptions{
        Summary: "Health check",
        Tags:    []string{"health"},
    })

    // API v1 group
    v1 := fiberoapi.Group(oapi, "/api/v1")
    
    fiberoapi.Get(v1, "/users/:id", func(c *fiber.Ctx, input UserInput) (UserOutput, UserError) {
        return UserOutput{ID: input.ID, Name: "User " + string(rune(input.ID))}, UserError{}
    }, fiberoapi.OpenAPIOptions{
        Summary: "Get user by ID",
        Tags:    []string{"users"},
    })

    fiberoapi.Post(v1, "/users", func(c *fiber.Ctx, input UserOutput) (UserOutput, UserError) {
        return UserOutput{ID: 99, Name: input.Name}, UserError{}
    }, fiberoapi.OpenAPIOptions{
        Summary: "Create a new user",
        Tags:    []string{"users"},
    })

    // API v2 with nested groups
    v2 := fiberoapi.Group(oapi, "/api/v2")
    usersV2 := fiberoapi.Group(v2, "/users")

    fiberoapi.Get(usersV2, "/:id", func(c *fiber.Ctx, input UserInput) (UserOutput, UserError) {
        return UserOutput{ID: input.ID, Name: "User v2 " + string(rune(input.ID))}, UserError{}
    }, fiberoapi.OpenAPIOptions{
        Summary: "Get user by ID (v2)",
        Tags:    []string{"users", "v2"},
    })

    // Mix with standard Fiber methods
    v1.Use("/admin", func(c *fiber.Ctx) error {
        return c.Next() // Auth middleware
    })

    app.Listen(":3000")
    // Visit http://localhost:3000/docs to see the Redoc documentation
}

Advanced Usage

Custom Documentation Configuration
config := fiberoapi.DocConfig{
    Title:       "My API",
    Description: "My API description",
    Version:     "2.0.0",
    DocsPath:    "/documentation",
    JSONPath:    "/api-spec.json",
}
oapi.SetupDocs(config) // Optional - docs are auto-configured by default
OApiRouter Interface

The library uses an OApiRouter interface that allows the same functions to work seamlessly with both apps and groups:

// This interface is implemented by both *OApiApp and *OApiGroup
type OApiRouter interface {
    GetApp() *OApiApp
    GetPrefix() string
}

// So these functions work with both:
func Get[T any, U any, E any](router OApiRouter, path string, handler HandlerFunc[T, U, E], options OpenAPIOptions)
func Post[T any, U any, E any](router OApiRouter, path string, handler HandlerFunc[T, U, E], options OpenAPIOptions)
func Put[T any, U any, E any](router OApiRouter, path string, handler HandlerFunc[T, U, E], options OpenAPIOptions)
func Delete[T any, U any, E any](router OApiRouter, path string, handler HandlerFunc[T, U, E], options OpenAPIOptions)
func Group(router OApiRouter, prefix string, handlers ...fiber.Handler) *OApiGroup

Documentation

When EnableOpenAPIDocs is set to true (default), the library automatically sets up:

  • Redoc UI: Modern, responsive documentation interface available at the configured docs path (default: /docs)
  • OpenAPI JSON: Complete OpenAPI 3.0 specification available at the configured JSON path (default: /openapi.json)
  • Automatic Schema Generation: Input and output types are automatically converted to OpenAPI schemas
  • Components Section: All schemas are properly organized in the components/schemas section

No manual setup required! Just visit http://localhost:3000/docs to see your API documentation with Redoc.

Redoc vs Swagger UI

This library uses Redoc for documentation UI instead of Swagger UI because:

  • Better performance with large APIs
  • Responsive design that works great on mobile
  • Clean, modern interface
  • Better OpenAPI 3.0 support
  • No JavaScript framework dependencies
OpenAPI Schema Generation

The library automatically generates OpenAPI 3.0 schemas from your Go types:

// This struct automatically becomes an OpenAPI schema
type User struct {
    ID       string `json:"id"`
    Username string `json:"username" validate:"required,min=3"`
    Email    string `json:"email" validate:"required,email"`
    Age      int    `json:"age" validate:"min=13,max=120"`
}

Generated OpenAPI spec will include:

  • Complete path definitions with parameters
  • Request/response schemas
  • Validation rules as schema constraints
  • Proper HTTP status codes
  • Operation IDs, tags, and descriptions

Migration from v1

If you're migrating from a previous version, here are the key changes:

fiberoapi.Get(oapi, "/users/:id", handler, options)      // Works on app
fiberoapi.Post(oapi, "/users", handler, options)         // Works on app

// And seamlessly on groups
v1 := fiberoapi.Group(oapi, "/api/v1")
fiberoapi.Get(v1, "/users/:id", handler, options)        // Works on groups
fiberoapi.Post(v1, "/users", handler, options)           // Works on groups
2. Group Support
// New group functionality
v1 := fiberoapi.Group(oapi, "/api/v1")
users := fiberoapi.Group(v1, "/users")

// All OpenAPI methods work on groups
fiberoapi.Get(users, "/:id", getUserHandler, options)
fiberoapi.Post(users, "/", createUserHandler, options)

// Standard Fiber Router methods work too (inherited via embedding)
users.Use(authMiddleware)                                     // Middleware
users.Get("/legacy", func(c *fiber.Ctx) error {             // Regular Fiber handler
    return c.SendString("legacy endpoint")
})

// For static files, use the main Fiber app
app.Static("/avatars", "./uploads")  // Static files via main app
3. Documentation UI
  • Changed from Swagger UI to Redoc for better performance and modern UI
  • Same paths: /docs for UI, /openapi.json for spec
  • No code changes required for existing documentation setup

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Delete added in v1.2.0

func Delete[TInput any, TOutput any, TError any](
	router OApiRouter,
	path string,
	handler HandlerFunc[TInput, TOutput, TError],
	options OpenAPIOptions,
)

Delete defines a DELETE operation for the OpenAPI documentation

func Get added in v1.2.0

func Get[TInput any, TOutput any, TError any](
	router OApiRouter,
	path string,
	handler HandlerFunc[TInput, TOutput, TError],
	options OpenAPIOptions,
)

Get defines a GET operation for the OpenAPI documentation

func Head[TInput any, TOutput any, TError any](
	router OApiRouter,
	path string,
	handler HandlerFunc[TInput, TOutput, TError],
	options OpenAPIOptions,
)

Head defines a HEAD operation for the OpenAPI documentation

func Method added in v1.2.0

func Method[TInput any, TOutput any, TError any](
	router OApiRouter,
	m string,
	path string,
	handler HandlerFunc[TInput, TOutput, TError],
	options OpenAPIOptions,
)

Method defines a generic method for registering HTTP operations with OpenAPI documentation

func Patch added in v1.2.0

func Patch[TInput any, TOutput any, TError any](
	router OApiRouter,
	path string,
	handler HandlerFunc[TInput, TOutput, TError],
	options OpenAPIOptions,
)

Patch defines a PATCH operation for the OpenAPI documentation

func Post added in v1.2.0

func Post[TInput any, TOutput any, TError any](
	router OApiRouter,
	path string,
	handler HandlerFunc[TInput, TOutput, TError],
	options OpenAPIOptions,
)

Post defines a POST operation for the OpenAPI documentation

func Put added in v1.2.0

func Put[TInput any, TOutput any, TError any](
	router OApiRouter,
	path string,
	handler HandlerFunc[TInput, TOutput, TError],
	options OpenAPIOptions,
)

Put defines a PUT operation for the OpenAPI documentation

Types

type Config

type Config struct {
	EnableValidation  bool   // Enable request validation (default: true)
	EnableOpenAPIDocs bool   // Enable automatic docs setup (default: true)
	OpenAPIDocsPath   string // Path for documentation UI (default: "/docs")
	OpenAPIJSONPath   string // Path for OpenAPI JSON spec (default: "/openapi.json")
}

Config represents configuration for the OApi wrapper

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns the default configuration

type DocConfig

type DocConfig struct {
	Title       string
	Description string
	Version     string
	DocsPath    string // Path where docs will be served, default: "/docs"
	JSONPath    string // Path where OpenAPI JSON will be served, default: "/openapi.json"
}

DocConfig contains configuration for the documentation

func DefaultDocConfig

func DefaultDocConfig() DocConfig

DefaultDocConfig returns default documentation configuration

type ErrorResponse added in v1.3.0

type ErrorResponse struct {
	Code    int    `json:"code"`
	Details string `json:"details"`
	Type    string `json:"type"`
}

type HandlerFunc

type HandlerFunc[TInput any, TOutput any, TError any] func(c *fiber.Ctx, input TInput) (TOutput, TError)

HandlerFunc represents a handler function with typed input and output

type OApiApp

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

OApiApp wraps fiber.App with OpenAPI capabilities

func New

func New(app *fiber.App, config ...Config) *OApiApp

New creates a new OApiApp with optional configuration

func (*OApiApp) Config

func (o *OApiApp) Config() Config

Config returns the current configuration

func (*OApiApp) GenerateOpenAPISpec

func (o *OApiApp) GenerateOpenAPISpec() map[string]interface{}

GenerateOpenAPISpec generates a complete OpenAPI 3.0 specification

func (*OApiApp) GetApp added in v1.2.0

func (o *OApiApp) GetApp() *OApiApp

Implement OApiRouter interface for OApiApp

func (*OApiApp) GetOperations

func (o *OApiApp) GetOperations() []OpenAPIOperation

GetOperations returns all registered operations (useful for testing and documentation generation)

func (*OApiApp) GetPrefix added in v1.2.0

func (o *OApiApp) GetPrefix() string

func (*OApiApp) Group added in v1.2.0

func (app *OApiApp) Group(prefix string, handlers ...fiber.Handler) *OApiGroup

Group creates a new OApiGroup that wraps a fiber.Router

func (*OApiApp) SetupDocs

func (o *OApiApp) SetupDocs(config ...DocConfig)

SetupDocs configures documentation routes for the OApiApp

type OApiGroup added in v1.2.0

type OApiGroup struct {
	fiber.Router // Embedded fiber.Router (includes all standard Fiber methods)
	// contains filtered or unexported fields
}

OApiGroup wraps a fiber.Router and adds OpenAPI methods

func Group added in v1.2.0

func Group(router OApiRouter, prefix string, handlers ...fiber.Handler) *OApiGroup

Group creates a new group from an OApiRouter (app or group)

func (*OApiGroup) GetApp added in v1.2.0

func (g *OApiGroup) GetApp() *OApiApp

Implement OApiRouter interface for OApiGroup

func (*OApiGroup) GetPrefix added in v1.2.0

func (g *OApiGroup) GetPrefix() string

func (*OApiGroup) Group added in v1.2.0

func (g *OApiGroup) Group(prefix string, handlers ...fiber.Handler) *OApiGroup

Group creates a new sub-group within this group

type OApiRouter added in v1.2.0

type OApiRouter interface {
	GetApp() *OApiApp
	GetPrefix() string
}

OApiRouter interface that both OApiApp and OApiGroup implement

type OpenAPIOperation

type OpenAPIOperation struct {
	Method     string
	Path       string
	Options    OpenAPIOptions
	InputType  reflect.Type
	OutputType reflect.Type
	ErrorType  reflect.Type
}

OpenAPIOperation represents a registered operation

type OpenAPIOptions

type OpenAPIOptions struct {
	OperationID string                   `json:"operationId,omitempty"`
	Tags        []string                 `json:"tags,omitempty"`
	Summary     string                   `json:"summary,omitempty"`
	Description string                   `json:"description,omitempty"`
	Parameters  []map[string]interface{} `json:"parameters,omitempty"`
}

OpenAPIOptions represents options for OpenAPI operations

type OpenAPIParameter

type OpenAPIParameter struct {
	Name        string                 `json:"name"`
	In          string                 `json:"in"` // "path", "query", "header", "cookie"
	Required    bool                   `json:"required,omitempty"`
	Description string                 `json:"description,omitempty"`
	Schema      map[string]interface{} `json:"schema"`
}

type OpenAPIRequestBody

type OpenAPIRequestBody struct {
	Description string                 `json:"description,omitempty"`
	Required    bool                   `json:"required,omitempty"`
	Content     map[string]interface{} `json:"content"`
}

type OpenAPIResponse

type OpenAPIResponse struct {
	Description string                 `json:"description"`
	Content     map[string]interface{} `json:"content,omitempty"`
}

type PathInfo

type PathInfo struct {
	Name   string
	IsPath bool
	Index  int // Position in the path for validation
}

PathInfo represents information about a path parameter

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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