ligo

package module
v0.11.0 Latest Latest
Warning

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

Go to latest
Published: May 17, 2026 License: MIT Imports: 13 Imported by: 0

README

Ligo

A modular Go framework with lightweight dependency injection, inspired by NestJS.

Go Version License Tests Coverage

Note: Ligo v0.11.0 is available. Context is now a concrete struct that wraps the new Adapter interface — handlers receive *ligo.Context and adapters implement 14 methods instead of 45. ctx.OK(...), ctx.BadRequest(...), ctx.QueryInt(...) all keep working. See the Migration Guide.

Features

  • Modular Architecture - Self-contained modules with providers, controllers, and middleware
  • Dependency Injection - Automatic dependency resolution with zero boilerplate
  • Lifecycle Hooks - OnModuleInit, OnApplicationBootstrap, BeforeApplicationShutdown, OnApplicationShutdown, OnModuleDestroy
  • HTTP Routing - Adapter-agnostic router interface with Echo v5 adapter
  • Guards - Authorization with composable guard functions
  • Pipes - Validation and transformation with composable pipes
  • Interceptors - Logging, caching, and response transformation
  • Exception Filters - Error handling and HTTP response conversion
  • Type-Safe - Full type safety with generics

Installation

# Get the latest version (v0.11.0)
go get github.com/linkeunid/ligo@latest

# Or specify a version
go get github.com/linkeunid/ligo@v0.11.0

Quick Start

package main

import (
    "github.com/linkeunid/ligo"
    "github.com/linkeunid/ligo/adapters/echo"
)

func main() {
    router := echo.NewAdapter()
    app := ligo.New(
        ligo.WithRouter(router),
        ligo.WithAddr(":8080"),
    )

    app.Register(
        ligo.NewModule("hello",
            ligo.Providers(ligo.Value("Hello, World!")),
            ligo.Controllers(NewHelloController),
        ),
    )

    app.Run()
}

type helloController struct { msg string }

func NewHelloController(msg string) *helloController {
    return &helloController{msg: msg}
}

func (c *helloController) Routes(r ligo.Router) {
    cr := ligo.NewChainRouter(r)
    cr.GET("/", c.Hello).Handle()
}

func (c *helloController) Hello(ctx ligo.Context) error {
    return ctx.OK(map[string]string{"message": c.msg})
}

Documentation

Guides:

Features:

CLI

Scaffold projects and generate Clean Architecture boilerplate with ligo-cli:

go install github.com/linkeunid/ligo-cli/cmd/ligo@latest
ligo new my-app            # scaffold a new project
ligo new my-app --full     # full boilerplate (users, file upload, auth)
ligo new my-app --runner   # background worker/runner

ligo g res product         # generate all layers (entity, usecase, repo, controller, module)
ligo g co product --full   # generate controller only
ligo g run email           # generate background worker

ligo serve                 # go run ./cmd/api/
ligo serve --watch         # auto-reload on file changes
ligo work email            # run a background worker
ligo build                 # go build -o bin/app ./cmd/api/

See ligo-cli for the full command reference.

Ecosystem

Package Description
ligo Core framework
ligo-cli CLI — scaffolding and code generation
ligo-boilerplate Starter project with Clean Architecture
ligo-memory In-memory store for dev/testing
ligo-validator Validator provider

Coming next: ligo-microservices (RabbitMQ), ligo-db (pgx, no ORM), ligo-schedule, ligo-ws — see Sneak Peek.

Examples

See the ligo-boilerplate repository for complete examples:

  • REST API - Full CRUD operations with response helpers
  • Authentication - JWT-style auth with guards and role-based access
  • Authorization - Custom guards, roles guard, admin-only endpoints
  • File Upload - Multipart file upload with streaming downloads

See Examples Guide for detailed documentation and API usage.

License

MIT License - see LICENSE for details.

Documentation

Index

Constants

View Source
const (
	// DefaultPort is the default HTTP port for the server.
	DefaultPort = ":8080"
	// DefaultGracefulTimeout is the default timeout for graceful shutdown.
	DefaultGracefulTimeout = 10 * time.Second
)
View Source
const (
	// LoggerText enables human-readable text logging.
	LoggerText = logger.TypeText
	// LoggerJSON enables structured JSON logging.
	LoggerJSON = logger.TypeJSON
)
View Source
const ValidatedBodyKey = http.ValidatedBodyKey

ValidatedBodyKey is the context key where ValidationPipe stores the validated body. Prefer ValidatedBody[T] over accessing this key directly.

Variables

View Source
var ErrBadRequest = http.ErrBadRequest

ErrBadRequest is wrapped by param-parsing pipes (UUIDPipe, ParseIntPipe, ParseBoolPipe) when a path parameter is invalid. Detect it with errors.Is(err, ligo.ErrBadRequest).

View Source
var ErrGuardDenied = http.ErrGuardDenied

ErrGuardDenied is returned by the route handler when a Guard returns (false, nil). ExceptionFilters detect it with errors.Is(err, ligo.ErrGuardDenied) and typically map to HTTP 403.

Functions

func BindQuery added in v0.8.0

func BindQuery(r *nethttp.Request, v any) error

BindQuery decodes URL query parameters into the struct pointed to by v. Fields are matched by the `query:"name"` tag; untagged fields are ignored. Supported field kinds: string, signed/unsigned ints, bool, floats, and slices of those (accepted as repeated params or comma-separated).

Example:

type UserFilter struct {
    Name  string `query:"name"`
    Email string `query:"email"`
    Sort  string `query:"sort"`
}
var f UserFilter
if err := ligo.BindQuery(ctx.Request(), &f); err != nil { ... }

func CollectHooks added in v0.5.0

func CollectHooks(v any) lifecycle.Hooks

CollectHooks is the internal hook collection function. Re-exported for internal use.

func Controllers

func Controllers(constructors ...any) module.ModuleOption

Controllers adds controller constructors that receive dependencies via DI. Each constructor is called with resolved dependencies and must return a Controller.

Example:

ligo.Controllers(
    func(svc *UserService) ligo.Controller {
        return &UserController{service: svc}
    },
)

func Dynamic

func Dynamic(factory func(...any) module.Module, opts ...any) module.ModuleOption

Dynamic creates a module option for dynamic modules with configuration options. The factory function receives the options and returns a configured module. This is useful for creating modules that need runtime configuration.

Type safety: opts is intentionally typed as ...any. This is the framework's escape hatch for runtime-configured modules; the factory is responsible for type-asserting each option. For statically-known configuration prefer a typed constructor that returns a Module directly — no Dynamic needed:

// Prefer this when configuration is fixed at compile time:
func ConfigModule(folder string) ligo.Module {
    return ligo.NewModule("config", ligo.Providers(NewConfigService(folder)))
}

// Use Dynamic only when the factory must accept heterogeneous opts:
func RegisterConfigModule(folder string) ligo.Module {
    return ligo.NewModule("config",
        ligo.Dynamic(NewConfigModule, folder),
    )
}

func Get added in v0.3.0

func Get[T any](ctx *Context, key string) T

Get retrieves a context value set by a pipe and asserts it to type T. Returns the zero value of T if the key is missing or the type does not match. Use this instead of ctx.Get(key).(T) to avoid a manual type assertion.

Example:

func (c *UserController) GetByID(ctx *ligo.Context) error {
    id     := ligo.Get[int](ctx, "id")     // set by ParseIntPipe("id")
    active := ligo.Get[bool](ctx, "active") // set by ParseBoolPipe("active")
    uuid   := ligo.Get[string](ctx, "id")   // set by UUIDPipe("id")
}

func HookedController added in v0.5.0

func HookedController(fn any) any

HookedController wraps a controller constructor to enable explicit hook registration via a Register method on the controller instance. This provides compile-time safety for hook method expressions, similar to HookedFactory for providers.

The controller instance can implement:

type Registerable interface {
    Register(*lifecycle.HookRegistry)
}

Example:

type UserController struct {
    userService *UserService
    log         ligo.Logger
}

func NewUserController(svc *UserService, log ligo.Logger) *UserController {
    return &UserController{userService: svc, log: log}
}

func (c *UserController) Initialize() error {
    c.log.Info("User controller initializing")
    return nil
}

func (c *UserController) Ready() error {
    c.log.Info("User controller ready")
    return nil
}

// Register method enables compile-time safe hook registration
func (c *UserController) Register(r *lifecycle.HookRegistry) {
    r.OnInit(c.Initialize)    // Method expression - compile-time checked
    r.OnBootstrap(c.Ready)    // If Ready doesn't exist → compile error
}

// Controller registration
ligo.HookedController(NewUserController)

func Hooks added in v0.5.0

func Hooks(hooks ...HookOption) *lifecycle.HookRegistry

Hooks creates a new hook registry for explicit lifecycle hook registration. Use with providers and controllers:

ligo.Factory[*Database](NewDatabase,
    ligo.Hooks(
        ligo.OnInit(func(db *Database) error { ... }),
        ligo.BeforeShutdown(func(db *Database) error { ... }),
    ),
)

func Imports

func Imports(modules ...module.Module) module.ModuleOption

Imports adds child modules to this module. Child modules can access exported providers from this module.

Example:

ligo.Imports(
    database.Module(),
    auth.Module(),
)

func Middlewares

func Middlewares(constructors ...any) module.ModuleOption

Middlewares adds middleware constructors that receive dependencies via DI. Each constructor is called with resolved dependencies and must return a Middleware.

Example:

ligo.Middlewares(
    func(logger *Logger) ligo.Middleware {
        return LoggingMiddleware(logger)
    },
)

func ModuleHooks added in v0.5.0

func ModuleHooks(opts ...ModuleHookOption) *lifecycle.ModuleHookRegistry

ModuleHooks creates module-level lifecycle hooks. Use with NewModule:

ligo.NewModule("user",
    ligo.Providers(...),
    ligo.ModuleHooks(
        ligo.ModuleInit(func() error { ... }),
        ligo.ModuleDestroy(func() error { ... }),
    ),
)

func MustResolve added in v0.10.0

func MustResolve[T any](a *App) T

MustResolve returns an instance of type T from the application container. Panics on any resolution failure. Use Resolve when you can handle the error. Must be called after Run() has built the container.

func NewModule

func NewModule(name string, opts ...module.ModuleOption) module.Module

NewModule creates a new module with the given name and options. The name should be unique and descriptive (e.g., "user", "auth", "database").

Example:

func Module() ligo.Module {
    return ligo.NewModule("user",
        ligo.Providers(...),
        ligo.Controllers(...),
    )
}

func OnModuleDestroy

func OnModuleDestroy(fn func() error) module.ModuleOption

OnModuleDestroy adds a hook to run when the module is destroyed. Hooks are executed in reverse order during application shutdown.

Example:

ligo.OnModuleDestroy(func() error {
    return database.Close()
})

func OnModuleInit

func OnModuleInit(fn func() error) module.ModuleOption

OnModuleInit adds a hook to run when the module is initialized. Hooks are executed after all providers are registered but before the server starts.

Example:

ligo.OnModuleInit(func() error {
    return database.Connect()
})

func Providers

func Providers(providers ...any) module.ModuleOption

Providers adds providers to the module. Providers can be Values, Factories, or Transients that are registered in the DI container for this module.

Example:

ligo.Providers(
    ligo.Value("config-value"),
    ligo.Factory[*UserService](NewUserService),
    ligo.Transient[*RequestContext](NewRequestContext),
)

func Query added in v0.8.0

func Query(r *nethttp.Request, key string) string

Query returns a single query-string value or "" when absent.

func QueryDefault added in v0.8.0

func QueryDefault(r *nethttp.Request, key, def string) string

QueryDefault returns the query value or def when absent/empty.

func QueryInt added in v0.8.0

func QueryInt(r *nethttp.Request, key string, def int) int

QueryInt parses a query value as int, returning def on missing/invalid.

func Resolve added in v0.10.0

func Resolve[T any](a *App) (T, error)

Resolve returns an instance of type T from the application container. Returns the zero value and an error when the type cannot be resolved (missing provider, ambiguous interface, circular dependency, factory error). Must be called after Run() has built the container.

Example:

user, err := ligo.Resolve[*UserService](app)
if err != nil { /* handle */ }

func ValidatedBody

func ValidatedBody[T any](ctx *Context) *T

ValidatedBody retrieves the validated body stored by ValidationPipe[T]. Panics with a clear message if ValidationPipe was not added to the route.

Example:

func (c *UserController) Create(ctx *ligo.Context) error {
    input := ligo.ValidatedBody[CreateUserInput](ctx)
    // input is *CreateUserInput, guaranteed non-nil
}

func WithModuleHooks added in v0.5.0

func WithModuleHooks(opts ...ModuleHookOption) module.ModuleOption

WithModuleHooks adds explicit lifecycle hooks to the module. This is an alternative to OnModuleInit/OnModuleDestroy for more control.

Example:

ligo.NewModule("user",
    ligo.Providers(...),
    ligo.WithModuleHooks(
        ligo.OnInit(func() error { ... }),
        ligo.OnDestroy(func() error { ... }),
    ),
)

Types

type App

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

App represents a Ligo application with dependency injection, module management, and HTTP server capabilities.

func New

func New(opts ...Option) *App

New creates a new Ligo application with the given options. Options include WithRouter, WithAddr, WithMiddleware, OnStart, and OnStop.

Example:

app := ligo.New(
    ligo.WithRouter(echo.NewAdapter()),
    ligo.WithAddr(":8080"),
)

func (*App) Container

func (a *App) Container() *di.Container

func (*App) Provide

func (a *App) Provide(providers ...Provider)

Provide registers global providers that are available across all modules. Providers must be registered before calling Run(). Panics if called after the application has started.

Example:

app.Provide(
    ligo.Value("config-value"),
    ligo.Factory[*Config](NewConfig),
)

func (*App) Register

func (a *App) Register(modules ...module.Module)

Register registers one or more modules with the application. Modules must be registered before calling Run(). Panics if called after the application has started.

Example:

app.Register(
    user.Module(),
    auth.Module(),
)

func (*App) Run

func (a *App) Run() error

Run starts the HTTP server and blocks until the server is shut down. It builds the DI container, registers all modules and providers, executes OnModuleInit hooks, starts the server, and waits for shutdown. On shutdown, it executes OnModuleDestroy and OnStop hooks.

Example:

if err := app.Run(); err != nil {
    log.Fatal(err)
}

type ChainRouter

type ChainRouter = http.ChainRouter

ChainRouter provides fluent chain methods for building routes. It allows chaining method calls for configuring routes.

func NewChainRouter

func NewChainRouter(r Router) ChainRouter

NewChainRouter wraps a Router with chain methods. Example:

cr := ligo.NewChainRouter(router)
cr.GET("/", handler).Guard(authGuard).Handle()

type Context

type Context = http.Context

Context wraps HTTP request/response for handlers, providing methods for accessing request data, binding bodies, and sending responses.

type Controller

type Controller = http.Controller

Controller defines how HTTP routes are registered for a module. Controllers receive dependencies via DI and register routes using the Router.

type DIError

type DIError = di.DIError

DIError is a general error type for dependency injection operations.

type ErrAppAlreadyStarted

type ErrAppAlreadyStarted struct{}

ErrAppAlreadyStarted is returned when trying to modify an app after Run() has been called. This includes calling Register() or Provide() after the application has started.

func (*ErrAppAlreadyStarted) Error

func (e *ErrAppAlreadyStarted) Error() string

type ErrCircularDependency

type ErrCircularDependency = di.ErrCircularDependency

ErrCircularDependency is returned when a circular dependency is detected in the provider graph.

type ErrControllerBinding

type ErrControllerBinding = http.ErrControllerBinding

ErrControllerBinding is returned when a controller's dependency chain cannot be fully resolved.

type ErrMissingDependency

type ErrMissingDependency = di.ErrMissingDependency

ErrMissingDependency is returned when a required dependency cannot be found in the di.

type ExceptionFilter

type ExceptionFilter = http.ExceptionFilter

ExceptionFilter handles errors and converts them to HTTP responses. ExceptionFilters are called when handlers or other components return errors.

type Guard

type Guard = http.Guard

Guard determines if a request should proceed (authorization). A Guard returns (true, nil) to allow the request, or (false, error) to deny it.

func AdminGuard

func AdminGuard(contextKey string) Guard

AdminGuard is a convenience guard that checks for admin role. Usage: cr.DELETE("/:id", c.Delete).Guard(ligo.AdminGuard("user"))

func RolesGuard

func RolesGuard(contextKey string, requiredRoles ...string) Guard

RolesGuard creates a guard that checks if the user has one of the required roles. Usage: cr.GET("", c.List).Guard(ligo.RolesGuard("user", "admin"))

func ThrottleGuard

func ThrottleGuard(identifierKey string, maxRequests int, window time.Duration) Guard

ThrottleGuard creates a rate-limiting guard using a process-wide in-memory counter store. New code should prefer NewThrottler so each app has its own state and can clean up on shutdown. Usage: cr.POST("", c.Create).Guard(ligo.ThrottleGuard("ip", 10, time.Minute))

type HandlerFunc

type HandlerFunc = http.HandlerFunc

HandlerFunc is the standard handler signature for route handlers. It receives a Context and returns an error.

type HasRole

type HasRole = http.HasRole

HasRole is an interface that types can implement for role checking.

type HookFunc added in v0.5.0

type HookFunc = lifecycle.HookFunc

HookFunc represents a lifecycle hook function.

type HookOption added in v0.5.0

type HookOption func(*lifecycle.HookRegistry)

HookOption is a functional option for configuring hooks.

func BeforeShutdown added in v0.5.0

func BeforeShutdown(fn func() error) HookOption

BeforeShutdown creates a hook option for BeforeApplicationShutdown.

func OnBootstrap added in v0.5.0

func OnBootstrap(fn func() error) HookOption

OnBootstrap creates a hook option for OnApplicationBootstrap.

func OnDestroy added in v0.5.0

func OnDestroy(fn func() error) HookOption

OnDestroy creates a hook option for OnModuleDestroy.

func OnInit added in v0.5.0

func OnInit(fn func() error) HookOption

OnInit creates a hook option for OnModuleInit.

func OnShutdown added in v0.5.0

func OnShutdown(fn func() error) HookOption

OnShutdown creates a hook option for OnApplicationShutdown.

type HookRegistry added in v0.5.0

type HookRegistry = lifecycle.HookRegistry

HookRegistry stores lifecycle hooks for a specific type. Use Hooks() to create a new registry.

type HookRegistryRef added in v0.5.0

type HookRegistryRef = *lifecycle.HookRegistry

HookRegistryRef is a pointer to HookRegistry for use in Register methods. This is a convenience type alias for method receivers.

type Interceptor

type Interceptor = http.Interceptor

Interceptor wraps the entire request/response cycle. Interceptors can modify the request before processing and the response after.

func LoggingInterceptor

func LoggingInterceptor(logFunc func(start time.Time, ctx *Context, err error)) Interceptor

LoggingInterceptor creates an interceptor that logs request details. Usage: cr.GET("", c.List).Intercept(ligo.LoggingInterceptor(func(start time.Time, ctx *Context, err error) { ... }))

func TimeoutInterceptor

func TimeoutInterceptor(timeout time.Duration) Interceptor

TimeoutInterceptor creates an interceptor that enforces a timeout. Usage: cr.GET("", c.List).Intercept(ligo.TimeoutInterceptor(5 * time.Second))

type LifecycleHook

type LifecycleHook func(ctx any) error

LifecycleHook is a function called during app lifecycle events. The ctx parameter is context.Context for OnStart/OnStop hooks.

type ListMeta added in v0.7.0

type ListMeta = http.ListMeta

ListMeta is the meta block for plain list responses (no pagination).

type ListQuery added in v0.7.0

type ListQuery = http.ListQuery

ListQuery captures common pagination query params (?page=, ?per_page=).

func Paginate added in v0.8.0

func Paginate(r *nethttp.Request, defaultPerPage, maxPerPage int) ListQuery

Paginate is a one-shot helper: ParseListQuery + Normalize. Honors ?per_page=0 (LIMIT 0); falls back to defaultPerPage only when ?per_page= is absent. Caps PerPage at maxPerPage when maxPerPage > 0.

func ParseListQuery added in v0.7.0

func ParseListQuery(r *nethttp.Request) ListQuery

ParseListQuery reads ?page= and ?per_page= from the request. Missing or invalid values stay zero; call Normalize to apply defaults.

Example:

func (c *UserController) List(ctx *ligo.Context) error {
    q := ligo.ParseListQuery(ctx.Request())
    q.Normalize(20, 100) // default 20, max 100
    users, total, err := c.repo.FindPage(ctx.Request().Context(), q.PerPage, q.Offset())
    if err != nil { return err }
    return ctx.Paginated(users, q.Page, q.PerPage, total)
}

type ListResponse added in v0.7.0

type ListResponse = http.ListResponse

ListResponse is { "data": [...], "meta": { "count": N } }.

func NewListResponse added in v0.7.0

func NewListResponse(items any) ListResponse

NewListResponse builds a ListResponse, coercing nil slices to [].

type Logger

type Logger = logger.Logger

Logger is the interface for framework logging.

func NewLogger

func NewLogger(opts ...LoggerOption) Logger

NewLogger creates a new logger. Default is text mode for development.

Example:

logger := ligo.NewLogger(
    ligo.WithLoggerJSON(),
    ligo.WithLoggerDebug(),
)

func NoopLogger added in v0.11.0

func NoopLogger() Logger

NoopLogger returns a Logger that discards every call. Convenient for tests that want to bypass log spam without importing internal/core/logger.

type LoggerField

type LoggerField = logger.Field

LoggerField is a key-value pair for structured logging.

type LoggerOption

type LoggerOption = logger.LoggerOption

LoggerOption configures the logger.

func WithLoggerDebug

func WithLoggerDebug() LoggerOption

WithLoggerDebug enables debug logging.

func WithLoggerJSON

func WithLoggerJSON() LoggerOption

WithLoggerJSON sets JSON output format for production.

func WithLoggerProduction

func WithLoggerProduction() LoggerOption

WithLoggerProduction enables JSON logging (alias for WithLoggerJSON).

func WithLoggerText

func WithLoggerText() LoggerOption

WithLoggerText sets text output format (default).

type LoggerType

type LoggerType = logger.Type

LoggerType represents the logger output format.

type Middleware

type Middleware = http.Middleware

Middleware is a function that wraps a handler to add pre/post processing. Middleware can modify the request, response, or short-circuit the handler chain.

type Module

type Module = module.Module

Module represents a self-contained unit of functionality that encapsulates providers, controllers, middleware, and lifecycle hooks.

type ModuleHookOption added in v0.5.0

type ModuleHookOption func(*lifecycle.ModuleHookRegistry)

ModuleHookOption is a functional option for module-level hooks.

func ModuleDestroy added in v0.5.0

func ModuleDestroy(fn func() error) ModuleHookOption

ModuleDestroy creates a module-level hook option for OnModuleDestroy.

func ModuleInit added in v0.5.0

func ModuleInit(fn func() error) ModuleHookOption

ModuleInit creates a module-level hook option for OnModuleInit.

type Option

type Option func(*options)

Option configures the App.

func OnStart

func OnStart(hook LifecycleHook) Option

OnStart adds a hook to run on app startup.

func OnStop

func OnStop(hook LifecycleHook) Option

OnStop adds a hook to run on app shutdown.

func WithAddr

func WithAddr(addr string) Option

WithAddr sets the server address.

func WithAutoPort

func WithAutoPort() Option

WithAutoPort enables automatic port increment if the default port is already in use.

func WithDebug

func WithDebug(debug bool) Option

WithDebug enables debug logging.

func WithGracefulShutdown

func WithGracefulShutdown(timeout time.Duration) Option

WithGracefulShutdown enables graceful shutdown on SIGINT/SIGTERM.

func WithJSON

func WithJSON() Option

WithJSON enables JSON logging mode (production).

func WithLogger

func WithLogger(l Logger) Option

WithLogger overrides the framework logger. Useful in tests (pass ligo.NoopLogger() to silence startup/shutdown chatter) and for binaries that want to share a logger across the app and their own subsystems. nil is treated as "no override" — keeps the default constructed logger.

func WithMiddleware

func WithMiddleware(mw ...Middleware) Option

WithMiddleware adds global middleware.

func WithParallelHooks added in v0.10.0

func WithParallelHooks() Option

WithParallelHooks runs provider OnInit and OnBootstrap hooks concurrently. Default is sequential execution in registration order — opt in only when the application has many independent providers whose startup work is I/O-bound (DB pools, remote handshakes) and order does not matter.

Parallel execution does not guarantee any ordering between hooks and surfaces a single aggregated error if any hook fails.

func WithRouter

func WithRouter(r Router) Option

WithRouter sets the HTTP router adapter.

type PageMeta added in v0.7.0

type PageMeta = http.PageMeta

PageMeta is the meta block for paginated list responses.

type PageResponse added in v0.7.0

type PageResponse = http.PageResponse

PageResponse is { "data": [...], "meta": { page, per_page, total, total_pages } }.

func NewPageResponse added in v0.7.0

func NewPageResponse(items any, page, perPage int, total int64) PageResponse

NewPageResponse builds a PageResponse, coercing nil slices to [] and computing total_pages from total / perPage.

type Pipe

type Pipe = http.Pipe

Pipe transforms input data before it reaches the handler. Pipes are used for validation, parsing, and data transformation.

func ParseBoolPipe

func ParseBoolPipe(param string) Pipe

ParseBoolPipe parses a string parameter to bool. Accepts: "true", "false", "1", "0" (case-insensitive).

Example:

cr.GET("/:active", c.Get).Pipe(ligo.ParseBoolPipe("active"))

func ParseIntPipe

func ParseIntPipe(param string) Pipe

ParseIntPipe parses a string parameter to int. Returns an error if the parameter cannot be parsed as an integer.

Example:

cr.GET("/:id", c.Get).Pipe(ligo.ParseIntPipe("id"))

func TrimPipe

func TrimPipe(param string) Pipe

TrimPipe removes leading and trailing whitespace from a string parameter.

Example:

cr.POST("", c.Create).Pipe(ligo.TrimPipe("name"))

func UUIDPipe

func UUIDPipe(param string) Pipe

UUIDPipe validates that a string parameter is a valid UUID format. Returns an error if the parameter is not a valid UUID.

Example:

cr.GET("/:uuid", c.Get).Pipe(ligo.UUIDPipe("uuid"))

func ValidationPipe

func ValidationPipe[T any](v *T) Pipe

ValidationPipe validates a struct using struct tags. It uses the "validate" tag and requires the go-playground/validator package.

Example:

type CreateUserInput struct {
    Name  string `validate:"required,min=3"`
    Email string `validate:"required,email"`
}

cr.POST("", c.Create).Pipe(ligo.ValidationPipe(&CreateUserInput{}))

type Provider

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

Provider represents a dependency provider that can be registered in the DI di. Providers can be eager values or factory functions.

func Export

func Export(p Provider) Provider

Export marks a provider as exported, making it visible to sibling modules. This allows providers to be shared across modules without being global.

Example:

ligo.Export(ligo.Factory[*Database](func() *Database {
    return NewDatabase()
}))

func Factory

func Factory[T any](fn any, opts ...ProviderOption) Provider

Factory registers a factory function that produces a singleton. The function can have dependencies as parameters; they are auto-injected. The factory is called once, and the result is cached for subsequent resolutions.

Hooks can be attached using WithHooks:

ligo.Factory[*UserService](func(repo *UserRepository) *UserService {
    return NewUserService(repo)
}, ligo.WithHooks(
    ligo.OnInit(func(svc *UserService) error { ... }),
))

func HookedFactory added in v0.5.0

func HookedFactory[T any](fn any) Provider

HookedFactory registers a factory function and enables explicit hook registration via a Register method on the created instance. This provides compile-time safety for hook method expressions.

The created instance can implement:

type Registerable interface {
    Register(*lifecycle.HookRegistry)
}

Example:

type Database struct {
    db *sql.DB
}

func (d *Database) Connect() error {
    d.db = sql.Open("postgres", "dsn")
    return nil
}

func (d *Database) Close() error {
    return d.db.Close()
}

// Register method enables compile-time safe hook registration
func (d *Database) Register(r *lifecycle.HookRegistry) {
    r.OnInit(d.Connect)    // Method expression - compile-time checked
    r.OnShutdown(d.Close)  // If Close doesn't exist → compile error
}

// Provider registration
ligo.HookedFactory(NewDatabase)

func HookedSingleton added in v0.9.0

func HookedSingleton[T any](fn any) Provider

HookedSingleton is like HookedFactory but marks the provider for eager resolution at application startup. Use it for providers whose only purpose is to attach lifecycle hooks (RPC handler registrations, background workers, schedulers) — where nothing else in the DI graph depends on the type, so a plain HookedFactory would never be instantiated and its Register method would never fire.

Example:

// OrderMessaging only exists to bind RPC handlers in OnBootstrap. No
// other provider depends on it, so HookedFactory would be a no-op.
ligo.HookedSingleton[*OrderMessaging](NewOrderMessaging)

Eager providers are resolved after all modules have been built and before any OnInit / OnBootstrap hook executes, so their dependencies (and the hooks they register) participate normally in the lifecycle.

func Transient

func Transient[T any](fn any, opts ...ProviderOption) Provider

Transient registers a factory function that produces a new instance on each resolve. Unlike Factory, the factory function is called every time the type is resolved. Dependencies are still auto-injected.

Example:

ligo.Transient[*RequestContext](func() *RequestContext {
    return NewRequestContext()
}, ligo.WithHooks(
    ligo.OnInit(func(ctx *RequestContext) error { ... }),
))

func Value

func Value[T any](instance T, opts ...ProviderOption) Provider

Value registers a pre-built instance as a singleton. The same instance will be returned for all resolutions of this type.

Example:

ligo.Value("config-value")
ligo.Value(&Config{Debug: true})

With hooks:

ligo.Value(&Database{db: db}, ligo.WithHooks(
    ligo.OnShutdown(func(db *Database) error { return db.Close() }),
))

func (Provider) Eager

func (p Provider) Eager() any

Eager returns the eager value if set (for internal use).

func (Provider) Fn

func (p Provider) Fn() any

Fn returns the factory function (for internal use).

func (Provider) Hooks added in v0.5.0

func (p Provider) Hooks() *lifecycle.HookRegistry

Hooks returns the hook registry if set (for internal use).

func (Provider) IsEagerResolve added in v0.9.0

func (p Provider) IsEagerResolve() bool

IsEagerResolve returns true if the provider should be resolved at startup even when nothing else in the DI graph depends on it. Set by HookedSingleton.

func (Provider) IsExported

func (p Provider) IsExported() bool

IsExported returns true if the provider is exported to sibling modules. Exported providers are visible to modules that import the module that exports them.

func (Provider) IsTransient

func (p Provider) IsTransient() bool

IsTransient returns true if the provider creates new instances per resolve.

func (Provider) Type

func (p Provider) Type() reflect.Type

Type returns the type this provider produces.

type ProviderOption added in v0.5.0

type ProviderOption func(*Provider)

ProviderOption is a functional option for configuring providers.

func WithHooks added in v0.5.0

func WithHooks(hooks ...HookOption) ProviderOption

WithHooks attaches lifecycle hooks to a provider.

Example:

ligo.Factory[*Database](NewDatabase,
    ligo.WithHooks(
        ligo.OnInit(func(db *Database) error {
            var err error
            db.conn = sql.Open("postgres", "dsn")
            return err
        }),
        ligo.BeforeShutdown(func(db *Database) error {
            return db.conn.Close()
        }),
    ),
)

type Registerable added in v0.5.0

type Registerable = lifecycle.Registerable

Registerable is the interface that services can implement to explicitly register their lifecycle hooks. This enables compile-time safety via method expressions instead of relying on duck typing.

Example:

type Database struct {}

func (d *Database) Connect() error { ... }
func (d *Database) Close() error { ... }

func (d *Database) Register(r *lifecycle.HookRegistry) {
    r.OnInit(d.Connect)      // Method expression - compile-time checked
    r.OnShutdown(d.Close)    // If Close doesn't exist → compile error
}

type RouteBuilder

type RouteBuilder = http.RouteBuilder

RouteBuilder provides fluent API for composing routes with Guards, Pipes, Interceptors, and ExceptionFilters using the builder pattern.

type Router

type Router = http.Router

Router is the HTTP router interface that all router adapters must implement. It provides methods for registering routes, middleware, and managing the HTTP server.

type Throttler added in v0.11.0

type Throttler = http.Throttler

Throttler is an in-memory rate limiter scoped to a single Ligo app.

func NewThrottler added in v0.11.0

func NewThrottler(maxRequests int, window time.Duration) *Throttler

NewThrottler returns an app-scoped Throttler. Caller is responsible for calling t.Close() on application shutdown to stop the cleanup goroutine.

t := ligo.NewThrottler(10, time.Minute)
defer t.Close()
cr.POST("", c.Create).Guard(t.Guard("ip"))

Directories

Path Synopsis
adapters
internal
app
di

Jump to

Keyboard shortcuts

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