echonext

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 5, 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"
}

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

  • Support for file uploads
  • WebSocket support
  • GraphQL integration
  • Database integration helpers
  • Code generation from OpenAPI spec
  • Authentication/Authorization helpers

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)

AddSecurityScheme adds a security scheme to the OpenAPI spec

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) 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) 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 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 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

type Route

type Route struct {
	Summary         string
	Description     string
	Tags            []string
	Security        []Security
	SuccessStatus   int
	RequestHeaders  map[string]HeaderInfo
	ResponseHeaders map[string]HeaderInfo
	ContentTypes    []string
	Examples        map[string]interface{}
}

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"
	Name   string // For apiKey: header/query/cookie name
	Scheme string // For bearer: "bearer", for basic: "basic"
	In     string // For apiKey: "header", "query", "cookie"
}

Security defines security requirements for a route

type Server

type Server struct {
	URL         string
	Description string
}

Server represents an OpenAPI server

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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