echonext

package module
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Dec 9, 2025 License: MIT Imports: 8 Imported by: 0

README

EchoNext

EchoNext is a type-safe wrapper around the Echo web framework that automatically generates OpenAPI specifications and provides request validation. Build robust, well-documented APIs with compile-time type safety.

Features

  • 🔒 Type-Safe Handlers - Define handlers with strongly-typed request and response structs
  • 📚 Automatic OpenAPI Generation - Generate OpenAPI 3.0 specs from your code
  • Built-in Validation - Validate requests using struct tags
  • 📖 Swagger UI - Interactive API documentation out of the box
  • 🚀 Zero Boilerplate - Focus on business logic, not HTTP details
  • 🔌 Echo Compatible - Use all Echo middleware and features

Installation

go get github.com/abdussamadbello/echonext

Quick Start

package main

import (
    "github.com/abdussamadbello/echonext"
    "github.com/labstack/echo/v4"
)

// Define your request/response types
type CreateUserRequest struct {
    Name  string `json:"name" validate:"required,min=2"`
    Email string `json:"email" validate:"required,email"`
}

type UserResponse struct {
    ID    string `json:"id"`
    Name  string `json:"name"`
    Email string `json:"email"`
}

func main() {
    // Create new EchoNext app
    app := echonext.New()
    
    // Set API info
    app.SetInfo("User API", "1.0.0", "User management service")
    
    // Register typed routes
    app.POST("/users", createUser, echonext.Route{
        Summary:     "Create a new user",
        Description: "Creates a new user with the provided information",
        Tags:        []string{"Users"},
    })
    
    app.GET("/users/:id", getUser, echonext.Route{
        Summary: "Get user by ID",
        Tags:    []string{"Users"},
    })
    
    // Serve OpenAPI spec and Swagger UI
    app.ServeOpenAPISpec("/api/openapi.json")
    app.ServeSwaggerUI("/api/docs", "/api/openapi.json")
    
    // Start server
    app.Start(":8080")
}

// Handlers with typed parameters
func createUser(c echo.Context, req CreateUserRequest) (UserResponse, error) {
    // Your business logic here
    user := UserResponse{
        ID:    "123",
        Name:  req.Name,
        Email: req.Email,
    }
    return user, nil
}

func getUser(c echo.Context) (UserResponse, error) {
    id := c.Param("id")
    // Fetch user logic
    return UserResponse{
        ID:    id,
        Name:  "John Doe",
        Email: "john@example.com",
    }, nil
}

Handler Signatures

EchoNext supports various handler signatures:

// No request body (GET, DELETE)
func handler(c echo.Context) (ResponseType, error)

// With request body (POST, PUT, PATCH)
func handler(c echo.Context, req RequestType) (ResponseType, error)

// No response body
func handler(c echo.Context) error

Validation

Use struct tags for validation:

type CreatePostRequest struct {
    Title   string   `json:"title" validate:"required,min=3,max=200"`
    Content string   `json:"content" validate:"required,min=10"`
    Tags    []string `json:"tags" validate:"max=5,dive,min=2,max=20"`
    Status  string   `json:"status" validate:"required,oneof=draft published"`
}

Query Parameters

For GET requests, use query tags:

type ListUsersRequest struct {
    Page  int    `query:"page" validate:"min=1"`
    Limit int    `query:"limit" validate:"min=1,max=100"`
    Sort  string `query:"sort" validate:"omitempty,oneof=name email created_at"`
}

func listUsers(c echo.Context, req ListUsersRequest) (ListResponse, error) {
    // Access validated query params from req
}

Error Handling

Return errors from handlers for automatic error responses:

func getUser(c echo.Context) (UserResponse, error) {
    id := c.Param("id")
    user, err := db.GetUser(id)
    if err != nil {
        return UserResponse{}, echo.NewHTTPError(404, "user not found")
    }
    return user, nil
}

Middleware & Echo Compatibility

EchoNext is fully compatible with all Echo middleware and features. Since it wraps *echo.Echo, you have access to everything Echo provides:

import "github.com/labstack/echo/v4/middleware"

app := echonext.New()

// All standard Echo middleware works
app.Use(middleware.Logger())
app.Use(middleware.Recover())
app.Use(middleware.CORS())
app.Use(middleware.Gzip())
app.Use(middleware.RateLimiter(middleware.NewRateLimiterMemoryStore(20)))
app.Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) {
    return username == "admin" && password == "secret", nil
}))
Echo Features Available
  • Context methods: c.Param(), c.QueryParam(), c.FormValue(), etc.
  • File uploads: c.FormFile(), c.MultipartForm()
  • Static files: app.Static("/static", "assets")
  • Route groups: api := app.Group("/api")
  • Custom binders: Custom request binding logic
  • Error handling: Echo's centralized error handler
  • Server options: TLS, graceful shutdown, etc.
Example with Echo Features
app := echonext.New()

// Use Echo middleware
app.Use(middleware.Logger())
app.Use(middleware.CORS())

// Create route groups (standard Echo)
api := app.Group("/api/v1")

// Static files (standard Echo)
app.Static("/assets", "public")

// EchoNext typed routes work within groups
api.POST("/users", createUser, echonext.Route{
    Summary: "Create user",
    Tags:    []string{"Users"},
})

// Mix typed and standard Echo handlers
app.POST("/upload", func(c echo.Context) error {
    file, err := c.FormFile("upload")
    if err != nil {
        return err
    }
    // Standard Echo file handling
    return c.String(200, "Uploaded: "+file.Filename)
})

EchoNext adds type safety and OpenAPI generation on top of Echo without removing any functionality!

Advanced OpenAPI Features

Security Schemes

Define security requirements for your API:

app := echonext.New()

// Add security schemes
app.AddSecurityScheme("bearerAuth", echonext.Security{
    Type:   "bearer",
    Scheme: "JWT",
})
app.AddSecurityScheme("apiKey", echonext.Security{
    Type: "apiKey",
    Name: "X-API-Key",
    In:   "header",
})

// Apply security to routes
app.POST("/protected", handler, echonext.Route{
    Security: []echonext.Security{
        {Type: "bearer"},
        {Type: "apiKey", Name: "X-API-Key"},
    },
})
Custom Response Status Codes

Use appropriate HTTP status codes:

app.POST("/users", createUser, echonext.Route{
    SuccessStatus: 201, // Returns 201 Created instead of 200 OK
})

app.DELETE("/users/:id", deleteUser, echonext.Route{
    SuccessStatus: 204, // Returns 204 No Content
})
Request/Response Headers

Document required and optional headers:

app.POST("/upload", uploadHandler, echonext.Route{
    RequestHeaders: map[string]echonext.HeaderInfo{
        "X-Request-ID": {
            Description: "Unique request identifier",
            Required:    true,
            Schema:      "string",
        },
    },
    ResponseHeaders: map[string]echonext.HeaderInfo{
        "X-Upload-ID": {
            Description: "ID of uploaded file",
            Schema:      "string",
        },
    },
})
Content Types and Examples

Support multiple content types and provide examples:

type CreateUserRequest struct {
    Name string `json:"name" example:"John Doe"`
    Age  int    `json:"age" example:"30"`
}

app.POST("/users", createUser, echonext.Route{
    ContentTypes: []string{"application/json", "application/xml"},
    Examples: map[string]interface{}{
        "basic": map[string]interface{}{
            "name": "John Doe",
            "age":  30,
        },
    },
})
Complete API Configuration
app := echonext.New()

// Set comprehensive API information
app.SetInfo("My API", "1.0.0", "A comprehensive API example")
app.SetContact("API Team", "https://example.com/support", "api@example.com")
app.SetLicense("MIT", "https://opensource.org/licenses/MIT")
app.SetServers([]echonext.Server{
    {URL: "https://api.example.com/v1", Description: "Production"},
    {URL: "https://staging.example.com/v1", Description: "Staging"},
})

Example Application

Run the example Todo API:

go run example/main.go

Then visit:

Development

Running Tests
go test ./...                    # Run all tests
go test -v ./...                # Run with verbose output
go test -bench=.                # Run benchmarks
go test -cover                  # Run with coverage
Project Structure
echonext/
├── echonext.go        # Main package implementation
├── echonext_test.go   # Test suite
├── example/
│   └── main.go        # Complete example application
├── go.mod
└── README.md

API Response Format

All responses are wrapped in a consistent format:

{
  "success": true,
  "data": { ... },
  "error": ""
}

Error responses:

{
  "success": false,
  "data": null,
  "error": "Validation failed: Name is required"
}

Optional Contrib Packages

EchoNext provides optional helper packages in pkg/contrib/ for common tasks. These are completely optional - you can use the underlying libraries directly if you prefer.

📦 Database (pkg/contrib/database)

GORM integration helpers with:

  • Connection management with retry logic
  • Generic Repository[T] pattern
  • Transaction utilities
  • Migration helpers
  • Atlas integration for schema migrations
import "github.com/abdussamadbello/echonext/pkg/contrib/database"

cfg := database.DefaultConfig()
db, err := database.Connect(postgres.Open(dsn), cfg)

// Use repository pattern with generics
userRepo := database.NewRepository[User](db)
user, err := userRepo.Find(1)
users, err := userRepo.Where("active = ?", true).FindAll()
🔄 Database Migrations (Atlas)

EchoNext uses Atlas for database schema management:

# Initialize Atlas in your project
echonext db init

# Apply migrations
echonext db migrate

# Generate migration from schema changes
echonext db migrate:diff add_users_table

# Check migration status
echonext db migrate:status

# Rollback migrations
echonext db migrate:down --count=1

Declarative Schema - Define your schema in schema.hcl:

table "users" {
  schema = schema.public
  column "id" { type = bigserial }
  column "email" { type = varchar(255) }
  primary_key { columns = [column.id] }
}

See CLAUDE.md for detailed Atlas documentation.

⚙️ Config (pkg/contrib/config)

Viper integration helpers with:

  • Generic config loading
  • Environment variable binding
  • Hot reload support
  • Standard config structures
import "github.com/abdussamadbello/echonext/pkg/contrib/config"

type MyConfig struct {
    App      config.AppConfig      `mapstructure:"app"`
    Database config.DatabaseConfig `mapstructure:"database"`
}

var cfg MyConfig
config.LoadSimple(&cfg)
🧪 Testing (pkg/contrib/testing)

Testing utilities with:

  • APIClient for testing endpoints
  • FixtureManager for test data
  • Test suite with setup/teardown
  • Factory pattern for test entities
import echonexttest "github.com/abdussamadbello/echonext/pkg/contrib/testing"

client := echonexttest.NewAPIClient(app)
resp := client.POST("/users", userRequest)
resp.AssertStatus(t, 201).AssertSuccess(t)

See pkg/contrib/README.md for detailed documentation.

🎓 Example Projects

Learn by example! Check out our complete example projects:

⚡ Quickstart - Running Example

Complete working Todo API. Run it now!

go run example/main.go
# Visit http://localhost:8080/api/docs
📝 Todo List API - Beginner

Simple CRUD operations demonstrating the basics of EchoNext.

echonext init todo-api
echonext generate domain todo
go run ./cmd/api
📰 Blog API - Intermediate

Multi-domain blog platform with authentication, search, and relationships.

echonext init blog-api
echonext generate domain post
echonext generate domain comment
echonext generate domain user
🛒 E-commerce API - Advanced

Complete e-commerce platform with orders, payments, and inventory.

echonext init ecommerce-api
echonext generate domain product
echonext generate domain order
echonext generate domain payment
🔧 Microservices - Expert

Distributed system with service-to-service communication and events.

See examples/README.md for detailed guides and more examples.

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT License - see the LICENSE file for details.

Roadmap

Completed:

  • ✅ Database integration helpers (see pkg/contrib/database)
  • ✅ Configuration management helpers (see pkg/contrib/config)
  • ✅ Testing utilities (see pkg/contrib/testing)
  • ✅ Middleware helpers (see pkg/contrib/middleware)
  • ✅ CLI tool for project generation (echonext init)
  • ✅ Code generation commands (echonext generate domain/handler/service/model/dto)
  • ✅ Database management commands (echonext db init/migrate/seed)
  • ✅ Atlas migration integration for schema management
  • ✅ Complete example projects (Todo, Blog, E-commerce, Microservices)

Planned:

  • Hot reload dev command (echonext dev)
  • Enhanced test runner (echonext test)
  • Build automation (echonext build)
  • Support for file uploads in OpenAPI spec
  • WebSocket support with type safety
  • GraphQL integration
  • Code generation from OpenAPI spec

Documentation

Overview

Package echonext provides a type-safe wrapper around Echo with automatic OpenAPI generation and validation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type App

type App struct {
	*echo.Echo
	// contains filtered or unexported fields
}

App represents an EchoNext application

func New

func New() *App

New creates a new EchoNext application

func (*App) AddSecurityScheme

func (app *App) AddSecurityScheme(name string, security Security) error

AddSecurityScheme adds a security scheme to the OpenAPI spec

func (*App) ClearGlobalSecurity added in v1.3.0

func (app *App) ClearGlobalSecurity()

ClearGlobalSecurity removes all global security requirements

func (*App) DELETE

func (app *App) DELETE(path string, handler interface{}, opts ...Route)

DELETE registers a typed DELETE endpoint

func (*App) GET

func (app *App) GET(path string, handler interface{}, opts ...Route)

GET registers a typed GET endpoint

func (*App) GenerateOpenAPISpec

func (app *App) GenerateOpenAPISpec() *openapi3.T

GenerateOpenAPISpec generates OpenAPI specification from registered routes

func (*App) Group added in v1.2.0

func (app *App) Group(prefix string, middleware ...echo.MiddlewareFunc) *Group

Group creates a route group with the given prefix

func (*App) PATCH

func (app *App) PATCH(path string, handler interface{}, opts ...Route)

PATCH registers a typed PATCH endpoint

func (*App) POST

func (app *App) POST(path string, handler interface{}, opts ...Route)

POST registers a typed POST endpoint

func (*App) PUT

func (app *App) PUT(path string, handler interface{}, opts ...Route)

PUT registers a typed PUT endpoint

func (*App) ServeOpenAPISpec

func (app *App) ServeOpenAPISpec(path string)

ServeOpenAPISpec serves the OpenAPI specification

func (*App) ServeSwaggerUI

func (app *App) ServeSwaggerUI(path string, specPath string)

ServeSwaggerUI serves Swagger UI for API documentation

func (*App) SetContact

func (app *App) SetContact(name, url, email string)

SetContact sets the API contact information

func (*App) SetGlobalSecurity added in v1.3.0

func (app *App) SetGlobalSecurity(requirements ...SecurityRequirement) error

SetGlobalSecurity sets default security requirements for all routes

func (*App) SetInfo

func (app *App) SetInfo(title, version, description string)

SetInfo sets the API information for OpenAPI spec

func (*App) SetLicense

func (app *App) SetLicense(name, url string)

SetLicense sets the API license information

func (*App) SetServers

func (app *App) SetServers(servers []Server)

SetServers sets the API servers

type Contact

type Contact struct {
	Name  string
	URL   string
	Email string
}

Contact represents OpenAPI contact information

type GlobalSecurityConfig added in v1.3.0

type GlobalSecurityConfig struct {
	Requirements     []SecurityRequirement // Default security requirements
	ApplyToAllRoutes bool                  // When true, applies to all routes by default
}

GlobalSecurityConfig defines default security settings for all routes

type Group added in v1.2.0

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

Group represents a route group with type-safe handlers

func (*Group) DELETE added in v1.2.0

func (g *Group) DELETE(path string, handler interface{}, opts ...Route)

DELETE registers a typed DELETE endpoint on the group

func (*Group) GET added in v1.2.0

func (g *Group) GET(path string, handler interface{}, opts ...Route)

GET registers a typed GET endpoint on the group

func (*Group) Group added in v1.2.0

func (g *Group) Group(prefix string, middleware ...echo.MiddlewareFunc) *Group

Group creates a sub-group with the given prefix

func (*Group) PATCH added in v1.2.0

func (g *Group) PATCH(path string, handler interface{}, opts ...Route)

PATCH registers a typed PATCH endpoint on the group

func (*Group) POST added in v1.2.0

func (g *Group) POST(path string, handler interface{}, opts ...Route)

POST registers a typed POST endpoint on the group

func (*Group) PUT added in v1.2.0

func (g *Group) PUT(path string, handler interface{}, opts ...Route)

PUT registers a typed PUT endpoint on the group

func (*Group) Use added in v1.2.0

func (g *Group) Use(middleware ...echo.MiddlewareFunc)

Use adds middleware to the group

type HeaderInfo

type HeaderInfo struct {
	Description string
	Required    bool
	Schema      string // "string", "integer", etc.
}

HeaderInfo describes a header parameter

type License

type License struct {
	Name string
	URL  string
}

License represents OpenAPI license information

type OAuth2Flow added in v1.3.0

type OAuth2Flow struct {
	AuthorizationURL string            // Authorization endpoint URL (required for implicit and authorizationCode)
	TokenURL         string            // Token endpoint URL (required for password, clientCredentials, authorizationCode)
	RefreshURL       string            // Optional refresh token endpoint URL
	Scopes           map[string]string // Maps scope names to their descriptions
}

OAuth2Flow represents a single OAuth2 flow configuration

type OAuth2Flows added in v1.3.0

type OAuth2Flows struct {
	Implicit          *OAuth2Flow // Implicit flow configuration
	Password          *OAuth2Flow // Password (Resource Owner Password Credentials) flow
	ClientCredentials *OAuth2Flow // Client Credentials flow configuration
	AuthorizationCode *OAuth2Flow // Authorization Code flow configuration
}

OAuth2Flows configures OAuth2 authentication flows

type Response

type Response[T any] struct {
	Data    T      `json:"data,omitempty"`
	Error   string `json:"error,omitempty"`
	Success bool   `json:"success"`
}

Response wraps API responses with a standard structure

func Error added in v1.2.0

func Error[T any](message string) Response[T]

Error creates an error response

func NoContent added in v1.2.0

func NoContent() Response[interface{}]

NoContent creates an empty successful response

func Success added in v1.2.0

func Success[T any](data T) Response[T]

Success creates a successful response

type Route

type Route struct {
	Summary               string
	Description           string
	Tags                  []string
	Security              []SecurityRequirement
	SuccessStatus         int
	RequestHeaders        map[string]HeaderInfo
	ResponseHeaders       map[string]HeaderInfo
	ContentTypes          []string
	Examples              map[string]interface{}
	DisableGlobalSecurity bool // When true, disables global security for this route
}

Route configures route metadata for OpenAPI generation

type RouteInfo

type RouteInfo struct {
	Method       string
	Path         string
	Handler      interface{}
	Summary      string
	Description  string
	Tags         []string
	RequestType  reflect.Type
	ResponseType reflect.Type
	RouteConfig  *Route // Store the full route configuration
}

RouteInfo stores metadata about a route for OpenAPI generation

type Security

type Security struct {
	Type             string       // "bearer", "apiKey", "oauth2", "basic", "openIdConnect"
	Name             string       // For apiKey: header/query/cookie name
	Scheme           string       // For bearer: "bearer", for basic: "basic"
	In               string       // For apiKey: "header", "query", "cookie"
	Description      string       // Human-readable description for the security scheme
	OAuth2Flows      *OAuth2Flows // OAuth2 flow configuration (required for oauth2 type)
	OpenIDConnectURL string       // OpenID Connect discovery URL (required for openIdConnect type)
}

Security defines a security scheme configuration for OpenAPI

type SecurityRequirement added in v1.3.0

type SecurityRequirement struct {
	SchemeName string   // References a scheme registered via AddSecurityScheme
	Scopes     []string // Required scopes for this security requirement
}

SecurityRequirement references a security scheme by name with optional scopes

type Server

type Server struct {
	URL         string
	Description string
}

Server represents an OpenAPI server

Directories

Path Synopsis
cmd
echonext-cli command
examples
otel-demo command
OTEL Demo - OpenTelemetry Distributed Tracing Example
OTEL Demo - OpenTelemetry Distributed Tracing Example
pkg
contrib/config
Package config provides optional Viper integration helpers for EchoNext applications.
Package config provides optional Viper integration helpers for EchoNext applications.
contrib/database
Package database provides optional GORM integration helpers for EchoNext applications.
Package database provides optional GORM integration helpers for EchoNext applications.
contrib/middleware
Package middleware provides optional Echo middleware helpers for EchoNext applications.
Package middleware provides optional Echo middleware helpers for EchoNext applications.
contrib/testing
Package testing provides optional testing utilities for EchoNext applications.
Package testing provides optional testing utilities for EchoNext applications.

Jump to

Keyboard shortcuts

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