omnis

package module
v1.3.4 Latest Latest
Warning

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

Go to latest
Published: Aug 27, 2025 License: MIT Imports: 9 Imported by: 0

README

omnis

Go Reference Go Report Card

High-level web framework integrations and middleware for Go web applications built on Gin.

Installation

go get github.com/ternarybob/omnis@latest

Features

  • JSON Response Interception: Automatically enhances all c.JSON() calls with logging and formatting
  • Configurable Render Service: Structured API responses with correlation ID tracking
  • Memory Log Integration: Request-scoped log retrieval using correlation IDs
  • Custom Logger Support: Inject your own arbor logger instances
  • Middleware Collection: Headers, static files, correlation ID, error handling, and recovery
  • Environment-Aware: Different behavior for DEV/PRD environments
  • Zero Code Changes: Transparent enhancements to existing Gin applications

Quick Start

Basic Usage
package main

import (
    "github.com/gin-gonic/gin"
    "github.com/ternarybob/omnis"
)

func main() {
    r := gin.New()
    
    // Configure your service
    config := &omnis.ServiceConfig{
        Version: "1.0.0",
        Name:    "my-api",
        Support: "support@mycompany.com", 
        Scope:   "DEV",
    }
    
    // Add middleware
    r.Use(omnis.SetCorrelationID())
    r.Use(omnis.JSONMiddleware(config))  // Automatic JSON enhancement
    r.Use(omnis.SetHeaders(config))
    
    // Use render service
    r.GET("/users", func(c *gin.Context) {
        users := []string{"alice", "bob"}
        omnis.RenderService(c).WithConfig(config).AsResult(200, users)
    })
    
    r.Run(":8080")
}
With Custom Logger
// Configure your arbor logger
logger := arbor.Logger().
    WithConsoleWriter(models.WriterConfiguration{
        Type: models.LogWriterTypeConsole,
    }).
    WithMemoryWriter(models.WriterConfiguration{
        Type: models.LogWriterTypeMemory,
    }).
    WithPrefix("my-api")

// Use with render service for log correlation
r.GET("/data", func(c *gin.Context) {
    // Your business logic here
    logger.Info().Msg("Processing data request")
    
    data := map[string]interface{}{"result": "success"}
    
    // Render with custom logger - memory logs will be included in response
    omnis.RenderService(c).
        WithConfig(config).
        WithLogger(logger).
        AsResult(200, data)
})

JSON Response Interception

The JSON middleware automatically intercepts and enhances all c.JSON() calls in your application:

Automatic Enhancement
func main() {
    r := gin.New()
    
    // Configure JSON middleware
    config := &omnis.ServiceConfig{
        Name:    "my-api",
        Version: "1.0.0",
        Scope:   "DEV",
    }
    
    r.Use(omnis.SetCorrelationID())
    r.Use(omnis.JSONMiddleware(config))
    
    r.GET("/users", func(c *gin.Context) {
        log := arbor.GetLogger().WithPrefix("UsersHandler")
        
        // Set logger for this request
        omnis.WithLogger(c, log)
        
        // Standard Gin JSON response - automatically enhanced with:
        // ✅ Request/response logging
        // ✅ Pretty printing in development  
        // ✅ Response size tracking
        // ✅ Correlation ID integration
        c.JSON(200, gin.H{
            "users": []string{"alice", "bob"},
            "count": 2,
        })
    })
    
    r.Run(":8080")
}
Advanced Configuration
// Full configuration with custom logger and settings
defaultLogger := arbor.GetLogger().WithPrefix("API")
jsonConfig := &omnis.JSONRendererConfig{
    ServiceConfig:     config,
    DefaultLogger:     defaultLogger,
    EnablePrettyPrint: true,
}

r.Use(omnis.JSONMiddlewareWithConfig(jsonConfig))

// Now all c.JSON() calls are automatically enhanced
r.GET("/health", func(c *gin.Context) {
    c.JSON(200, gin.H{"status": "healthy"})  // Enhanced automatically!
})
Fluent Logger Chaining

For cases where you want to provide a logger with fluent syntax, omnis offers multiple approaches:

func userHandler(c *gin.Context) {
    log := arbor.GetLogger().WithPrefix("UserHandler")
    
    // Option 1: Direct logger chaining - closest to c.WithLogger(log).JSON() syntax
    omnis.LoggerChain(c, log).JSON(200, gin.H{"user": "john"})
    
    // Option 2: Alternative chain syntax
    omnis.Chain(c).WithLogger(log).JSON(200, gin.H{"user": "john"})
    
    // Option 3: Original C() wrapper syntax
    omnis.C(c).WithLogger(log).JSON(200, gin.H{"user": "john"})
    
    // All syntaxes support convenience methods
    omnis.LoggerChain(c, log).Success(gin.H{"user": "john"})
    omnis.Chain(c).WithLogger(log).Created(gin.H{"user": "john"})
    omnis.C(c).WithLogger(log).BadRequest(gin.H{"error": "invalid input"})
}

### Manual Control (Alternative)

For explicit control, you can also use the fluent interface:

```go
r.GET("/data", func(c *gin.Context) {
    log := arbor.GetLogger().WithPrefix("DataHandler")
    data := gin.H{"message": "explicit control"}
    
    // Fluent interface approach
    omnis.JSON(c).WithLogger(log).Success(data)
})
Advanced Configuration Examples
Complete Service Setup
func setupAPI() *gin.Engine {
    r := gin.New()
    
    // Service configuration
    config := &omnis.ServiceConfig{
        Name:    "pexa-mock-api",
        Version: "0.0.2",
        Support: "support@pexa.com",
        Scope:   "DEV",
    }
    
    // Configure logger with memory storage for correlation
    logger := arbor.Logger().
        WithPrefix("API").
        WithConsoleWriter(models.WriterConfiguration{
            Type: models.LogWriterTypeConsole,
        }).
        WithMemoryWriter(models.WriterConfiguration{
            Type: models.LogWriterTypeMemory,
        })
    
    // Add middleware stack
    r.Use(omnis.SetCorrelationID())
    r.Use(omnis.SetHeaders(config))
    r.Use(omnis.StaticRequests(config, []string{"assets/", "favicon.ico"}))
    
    return r
}
Multiple Response Types
// Success responses
r.GET("/users", func(c *gin.Context) {
    users := []gin.H{
        {"id": 1, "name": "John Doe"},
        {"id": 2, "name": "Jane Smith"},
    }
    
    omnis.RenderService(c).
        WithConfig(config).
        WithLogger(logger).
        AsResult(200, users)
})

// Error responses with stack traces (DEV mode only)
r.GET("/error-demo", func(c *gin.Context) {
    err := errors.New("demonstration error")
    
    omnis.RenderService(c).
        WithConfig(config).
        WithLogger(logger).
        AsResultWithError(500, nil, err)
})

// Model responses (merge into existing struct)
r.GET("/profile", func(c *gin.Context) {
    profile := &UserProfile{
        ID:   123,
        Name: "John Doe",
    }
    
    omnis.RenderService(c).
        WithConfig(config).
        WithLogger(logger).
        AsModel(200, profile)
})

Examples

Error Handling with Stack Traces (DEV mode)
r.GET("/error", func(c *gin.Context) {
    err := errors.New("something went wrong")
    
    omnis.RenderService(c).
        WithConfig(config).
        AsResultWithError(500, nil, err)
})
API Response Formats
Standard API Response (with correlation tracking)

All responses include metadata, correlation tracking, and memory logs:

{
  "result": {
    "users": ["alice", "bob"]
  },
  "name": "pexa-mock-api",
  "version": "0.0.2+build.go1.24.20250827.105800",
  "support": "support@pexa.com",
  "status": 200,
  "scope": "DEV",
  "correlationid": "550e8400-e29b-41d4-a716-446655440000",
  "request": {
    "url": "/users"
  },
  "log": {
    "001": "INF|10:30:45.123|API|Processing request started",
    "002": "DBG|10:30:45.124|API|Found 2 users",
    "003": "INF|10:30:45.125|API|Request completed"
  }
}
Error Response with Stack Trace (DEV mode only)
{
  "result": null,
  "name": "pexa-mock-api",
  "version": "0.0.2+build.go1.24.20250827.105800",
  "status": 500,
  "scope": "DEV",
  "correlationid": "550e8400-e29b-41d4-a716-446655440000",
  "error": "demonstration error",
  "stack": [
    "main.errorHandler()",
    "  /app/handlers.go:45",
    "github.com/gin-gonic/gin.(*Context).Next()",
    "  /go/pkg/mod/github.com/gin-gonic/gin@v1.10.1/context.go:174"
  ],
  "request": {
    "url": "/error-demo"
  },
  "log": {
    "001": "ERR|10:30:50.123|API|Error occurred: demonstration error"
  }
}

Documentation

Full documentation is available at pkg.go.dev.

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.

API Reference

ServiceConfig

Configure your service metadata:

type ServiceConfig struct {
    Version string  // Service version (e.g., "1.0.0")
    Name    string  // Service name (e.g., "my-api") 
    Support string  // Support contact (e.g., "support@company.com")
    Scope   string  // Environment scope ("DEV", "PRD", etc.)
}
Render Service Methods
service := omnis.RenderService(ctx)

// Configuration and logger injection
service.WithConfig(config)           // Set service configuration
service.WithLogger(logger)           // Set custom arbor logger

// Response methods
service.AsResult(200, data)          // Success response with data
service.AsError(500, err)            // Error response  
service.AsResultWithError(200, data, err) // Success with error details (DEV only)
service.AsModel(200, &modelStruct)   // Response merged into existing model
Available Middleware
// Correlation ID tracking
r.Use(omnis.SetCorrelationID())

// Service headers (x-t3b-app, x-t3b-version)  
r.Use(omnis.SetHeaders(config))

// Static file handling with cache control
r.Use(omnis.StaticRequests(config, []string{"assets/", "favicon.ico"}))

// Additional middleware available:
// - Error handler middleware
// - Recovery middleware  
// - CORS headers middleware

Migration Guide

Updating Existing Applications

To integrate omnis into existing Gin applications:

1. Update main.go setup
// Before: Standard Gin setup
func main() {
    r := gin.New()
    
    r.GET("/users", func(c *gin.Context) {
        users := getUserList()
        c.JSON(http.StatusOK, users)
    })
}

// After: With omnis integration
func main() {
    r := gin.New()
    
    config := &omnis.ServiceConfig{
        Name:    "my-api",
        Version: "1.0.0",
        Support: "support@company.com",
        Scope:   "DEV",
    }
    
    logger := arbor.Logger().WithPrefix("API")
    
    // Add omnis middleware
    r.Use(omnis.SetCorrelationID())
    r.Use(omnis.SetHeaders(config))
    
    r.GET("/users", func(c *gin.Context) {
        users := getUserList()
        
        // Enhanced response with correlation tracking
        omnis.RenderService(c).
            WithConfig(config).
            WithLogger(logger).
            AsResult(200, users)
    })
}
2. Update Handler Methods
// Before: Direct JSON responses
func UserHandler(c *gin.Context) {
    userInfo := getUserFromToken(c)
    if userInfo == nil {
        c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
        return
    }
    c.JSON(http.StatusOK, userInfo)
}

// After: With omnis structured responses
func UserHandler(c *gin.Context) {
    logger := arbor.Logger().WithPrefix("UserHandler")
    config := getServiceConfig() // Your config source
    
    userInfo := getUserFromToken(c)
    if userInfo == nil {
        omnis.RenderService(c).
            WithConfig(config).
            WithLogger(logger).
            AsError(401, errors.New("unauthorized"))
        return
    }
    
    omnis.RenderService(c).
        WithConfig(config).
        WithLogger(logger).
        AsResult(200, userInfo)
}

This library is part of the ternarybob ecosystem:

  • funktion - Core utility functions
  • arbor - Structured logging system
  • omnis - Web framework integrations

Breaking Changes

v1.0.22+
  • Removed satus dependency: Use ServiceConfig instead of satus.AppConfig
  • Updated middleware signatures: Pass *ServiceConfig instead of *satus.AppConfig
  • Configuration injection: Use WithConfig() method on render service

Documentation

Index

Constants

View Source
const (
	CORRELATION_ID_KEY string = "correlationid"
	DEFAULT_TIMEFORMAT string = "01-02 15:04:05.000"
)
View Source
const REQUEST_LOGGER = "omnis_request_logger"

REQUEST_LOGGER is the key used to store request-specific loggers in gin.Context

Variables

This section is empty.

Functions

func GetCorrelationID

func GetCorrelationID(c *gin.Context) string

GetCorrelationID retrieves the correlation ID from the gin context Returns the correlation ID or "unknown" if not found

func GetCorrelationIDOrGenerate added in v1.0.3

func GetCorrelationIDOrGenerate(c *gin.Context) string

GetCorrelationIDOrGenerate retrieves the correlation ID or generates one if not found

func JSONMiddleware added in v1.0.27

func JSONMiddleware(config *ServiceConfig) gin.HandlerFunc

JSONMiddleware creates middleware that enables fluent JSON rendering with logging context Usage: router.Use(omnis.JSONMiddleware(config))

func JSONMiddlewareWithConfig added in v1.0.27

func JSONMiddlewareWithConfig(config *JSONRendererConfig) gin.HandlerFunc

JSONMiddlewareWithConfig creates middleware with full configuration options This middleware intercepts all c.JSON() calls and enhances them with logging Usage: router.Use(omnis.JSONMiddlewareWithConfig(&omnis.JSONRendererConfig{...}))

func JSONMiddlewareWithDefaults added in v1.0.27

func JSONMiddlewareWithDefaults() gin.HandlerFunc

JSONMiddlewareWithDefaults creates middleware with default configuration Usage: router.Use(omnis.JSONMiddlewareWithDefaults())

func RequestScopedLoggerMiddleware added in v1.0.19

func RequestScopedLoggerMiddleware(createLogger func() interface{}) gin.HandlerFunc

RequestScopedLoggerMiddleware creates a fresh logger instance for each request with correlation ID pre-configured. This eliminates the need for correlation ID lifecycle management and cleanup - the logger instance dies with the request.

This is the cleanest architectural approach: - No global state pollution - No cleanup required - No correlation ID leaking between requests - Handlers get a dedicated logger instance

Usage:

router.Use(omnis.SetCorrelationID())
router.Use(omnis.RequestScopedLoggerMiddleware(func() interface{} {
    return arbor.NewLogger() // Create fresh instance
}))
// In handlers: logger := c.MustGet("logger")

func SetCorrelationID

func SetCorrelationID() gin.HandlerFunc

func SetHeaders

func SetHeaders(config *ServiceConfig) gin.HandlerFunc

func StaticRequests

func StaticRequests(config *ServiceConfig, e []string) gin.HandlerFunc

Types

type ApiResponse

type ApiResponse struct {
	Version       string                 `json:"version,omitempty"`
	Build         string                 `json:"build,omitempty"`
	Name          string                 `json:"name,omitempty"`
	Support       string                 `json:"support,omitempty"`
	Status        int                    `json:"status"`
	Scope         string                 `json:"scope,omitempty"`
	CorrelationId string                 `json:"correlationid,omitempty"`
	Log           map[string]interface{} `json:"log,omitempty"`
	Result        interface{}            `json:"result"`
	Error         string                 `json:"error,omitempty"`
	Stack         []string               `json:"stack,omitempty"`
	Request       map[string]interface{} `json:"request,omitempty"`
}

ApiResponse represents the structured API response format (minimal version)

type ICorrelationService

type ICorrelationService interface {
	WithContext(ctx gin.Context) ICorrelationService
	SetCorrelationID() (string, error)
	GetCorrelationID() string
}

type JSONRendererConfig added in v1.0.27

type JSONRendererConfig struct {
	ServiceConfig     *ServiceConfig // Service configuration
	DefaultLogger     arbor.ILogger  // Default logger to use if none specified
	EnablePrettyPrint bool           // Enable pretty printing in development
	ApiLogLevel       arbor.LogLevel // Minimum log level for capturing logs (default: InfoLevel)
	ResponseFormat    string         // Response format: "apiresponse" (default) or "standard"
}

JSONRendererConfig holds configuration for the JSON renderer middleware

type ServiceConfig added in v1.0.22

type ServiceConfig struct {
	Version string // Service version (e.g., "1.0.0")
	Build   string // Build timestamp (e.g., "2025-08-27-15-30")
	Name    string // Service name (e.g., "my-api")
	Scope   string // Environment scope ("DEV", "PRD", etc.)
}

ServiceConfig defines service metadata for middleware (minimal version)

Jump to

Keyboard shortcuts

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