Documentation
¶
Index ¶
- Constants
- Variables
- func CollectHooks(v any) lifecycle.Hooks
- func Controllers(constructors ...any) module.ModuleOption
- func Dynamic(factory func(...any) module.Module, opts ...any) module.ModuleOption
- func Get[T any](ctx Context, key string) T
- func HookedController(fn any) any
- func Hooks(hooks ...HookOption) *lifecycle.HookRegistry
- func Imports(modules ...module.Module) module.ModuleOption
- func Middlewares(constructors ...any) module.ModuleOption
- func ModuleHooks(opts ...ModuleHookOption) *lifecycle.ModuleHookRegistry
- func NewModule(name string, opts ...module.ModuleOption) module.Module
- func OnModuleDestroy(fn func() error) module.ModuleOption
- func OnModuleInit(fn func() error) module.ModuleOption
- func Providers(providers ...any) module.ModuleOption
- func ValidatedBody[T any](ctx Context) *T
- func WithModuleHooks(opts ...ModuleHookOption) module.ModuleOption
- type App
- type ChainRouter
- type Context
- type Controller
- type DIError
- type ErrAppAlreadyStarted
- type ErrCircularDependency
- type ErrControllerBinding
- type ErrDuplicateProvider
- type ErrMissingDependency
- type ExceptionFilter
- type Guard
- type HandlerFunc
- type HasRole
- type HookFunc
- type HookOption
- type HookRegistry
- type HookRegistryRef
- type Interceptor
- type LifecycleHook
- type Logger
- type LoggerField
- type LoggerOption
- type LoggerType
- type Middleware
- type Module
- type ModuleHookOption
- type Option
- func OnStart(hook LifecycleHook) Option
- func OnStop(hook LifecycleHook) Option
- func WithAddr(addr string) Option
- func WithAutoPort() Option
- func WithDebug(debug bool) Option
- func WithGracefulShutdown(timeout time.Duration) Option
- func WithJSON() Option
- func WithLogger(l Logger) Option
- func WithMiddleware(mw ...Middleware) Option
- func WithRouter(r Router) Option
- type Pipe
- type Provider
- type ProviderOption
- type Registerable
- type RouteBuilder
- type Router
Constants ¶
const ( // LoggerText enables human-readable text logging. LoggerText = logger.TypeText // LoggerJSON enables structured JSON logging. LoggerJSON = logger.TypeJSON )
const ValidatedBodyKey = http.ValidatedBodyKey
ValidatedBodyKey is the context key where ValidationPipe stores the validated body. Prefer ValidatedBody[T] over accessing this key directly.
Variables ¶
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).
Functions ¶
func CollectHooks ¶ added in v0.5.0
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 ¶
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.
Example:
func RegisterConfigModule(folder string) ligo.Module {
return ligo.NewModule("config",
ligo.Dynamic(
NewConfigModule,
folder,
),
)
}
func Get ¶ added in v0.3.0
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
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 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 ValidatedBody ¶
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 ¶
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) Provide ¶
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 ¶
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 ¶
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 ¶
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 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 = container.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 ErrDuplicateProvider ¶
type ErrDuplicateProvider = container.ErrDuplicateProvider
ErrDuplicateProvider is returned when a provider for a type is already registered. The first provider is used, and subsequent providers for the same type are ignored.
type ErrMissingDependency ¶
type ErrMissingDependency = container.ErrMissingDependency
ErrMissingDependency is returned when a required dependency cannot be found in the container.
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 ¶
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 ¶
AdminGuard is a convenience guard that checks for admin role. Usage: cr.DELETE("/:id", c.Delete).Guard(ligo.AdminGuard("user"))
func RolesGuard ¶
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"))
type HandlerFunc ¶
type HandlerFunc = http.HandlerFunc
HandlerFunc is the standard handler signature for route handlers. It receives a Context and returns an error.
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 ¶
LifecycleHook is a function called during app lifecycle events. The ctx parameter is context.Context for OnStart/OnStop hooks.
type 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(),
)
type LoggerField ¶
LoggerField is a key-value pair for structured logging.
type LoggerOption ¶
type LoggerOption = logger.LoggerOption
LoggerOption configures the logger.
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 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 ¶
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 WithAutoPort ¶
func WithAutoPort() Option
WithAutoPort enables automatic port increment if the default port is already in use.
func WithGracefulShutdown ¶
WithGracefulShutdown enables graceful shutdown on SIGINT/SIGTERM.
func WithMiddleware ¶
func WithMiddleware(mw ...Middleware) Option
WithMiddleware adds global middleware.
type Pipe ¶
Pipe transforms input data before it reaches the handler. Pipes are used for validation, parsing, and data transformation.
func ParseBoolPipe ¶
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 ¶
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 ¶
TrimPipe removes leading and trailing whitespace from a string parameter.
Example:
cr.POST("", c.Create).Pipe(ligo.TrimPipe("name"))
func UUIDPipe ¶
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 ¶
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 container. Providers can be eager values or factory functions.
func Export ¶
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
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 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) Hooks ¶ added in v0.5.0
func (p Provider) Hooks() *lifecycle.HookRegistry
Hooks returns the hook registry if set (for internal use).
func (Provider) IsExported ¶
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 ¶
IsTransient returns true if the provider creates new instances per resolve.
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.