dygo

package module
v1.0.0-beta.1 Latest Latest
Warning

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

Go to latest
Published: Nov 2, 2026 License: MIT Imports: 28 Imported by: 0

README

Dygo

A modular framework for Go: modules, dependency injection, lifecycle hooks, controllers with typed handlers, and the guard, interceptor, pipe and filter pipeline with typed metadata and validation. It stays idiomatic Go: constructors, context.Context, error values, no code generation required.

Status: phases 0 to 6 of 7 done (core container, modules, HTTP layer, pipeline, production essentials, the dygo CLI, transports and background work). Phase 7 (v1.0) is in progress. Start with getting started. Plans: PLAN.md and docs/.

var UsersModule = &dygo.Module{
    Name:      "users",
    Imports:   []*dygo.Module{store.Module},
    Providers: []dygo.Provider{
        dygo.Provide(NewStoreRepo, dygo.As[Repo]()),
        dygo.Provide(NewUserService),
    },
    Exports: []dygo.Token{dygo.TypeOf[*UserService]()},
}

func (c *UsersController) Routes(r dygo.Router) {
    r = r.Prefix("/users")
    r.Get("/{id}", dygo.Handle(c.Get))
}

type GetIn struct {
    ID int `path:"id"`
}

func (c *UsersController) Get(ctx context.Context, in GetIn) (*User, error) { ... }

app, err := dygo.Create(ctx, AppModule, dygo.WithGlobalPrefix("/api"))
err = app.Listen(ctx, ":9900")

Try it

go test -race ./...
go run ./examples/worker     # Ctrl+C to watch shutdown hooks
(cd examples/http-users && go run .)  # users API on :9900, docs at /docs
(cd examples/academy && go test ./...)  # a course platform backend, used to dogfood v1.0
docker compose -f examples/http-users/compose.yaml up --build  # with Jaeger traces on :16686

Requires Go 1.27+. The core has no third party dependencies.

Performance

Typed JSON handlers cost about the same as hand written net/http and are faster than chi, Gin and Huma on the same work. Method and numbers: benchmarks/.

Security

See SECURITY.md for how to report a vulnerability.

License

MIT, see LICENSE.

Documentation

Overview

Package dygo is a modular application framework for Go.

An application is a tree of modules. Each module declares providers (constructor functions or values), the tokens it exports, and the modules it imports. At startup the container reads constructor signatures, checks the whole dependency graph, builds every singleton in dependency order, and runs lifecycle hooks module level by module level.

var Module = &dygo.Module{
	Name:      "users",
	Imports:   []*dygo.Module{database.Module},
	Providers: []dygo.Provider{
		dygo.Provide(NewUserService),
		dygo.Provide(NewPgRepo, dygo.As[Repo]()),
	},
	Exports: []dygo.Token{dygo.TypeOf[*UserService]()},
}

app, err := dygo.CreateApplicationContext(ctx, AppModule)

Go has no decorators, so providers, injection and modules are declared with plain function calls and struct literals. Reflection is used only while the application boots.

Writing a transport

Transport, Endpoint, Pipeline, Enhancers, NewEnhancers and ProvidersImplementing are for packages that add a way to receive work, such as the ws, graphql and micro modules. Applications do not need them.

Stability

From v1.0.0 the module follows semantic versioning. The promise covers the exported Go API, the JSON error body written by errs.DefaultWriter, and the struct tag syntax read by the binder (path, query, header, cookie, form, file, body, default, required). It does not cover the output format of the dygo CLI, the layout of generated code, or log messages.

Index

Constants

View Source
const (
	AppGuards       = "dygo.app.guards"
	AppInterceptors = "dygo.app.interceptors"
	AppPipes        = "dygo.app.pipes"
	AppFilters      = "dygo.app.filters"
)

Group names that make providers global enhancers with dependency injection:

dygo.Provide(NewAuthGuard, dygo.Group(dygo.AppGuards))

Members must be singletons. They run after the enhancers given with the WithGlobal* options.

View Source
const VersionNeutral = "*"

VersionNeutral as a route version makes the route match every version, and requests without a version.

Variables

View Source
var (
	// ErrNotFound is returned by Get when no provider matches the token.
	ErrNotFound = errors.New("dygo: no provider found")
	// ErrAmbiguous is returned by Get when more than one provider matches.
	ErrAmbiguous = errors.New("dygo: more than one provider found")
)
View Source
var ErrFiltered = errors.New("dygo: error handled by an exception filter")

ErrFiltered is returned by Pipeline.Run when an exception filter caught the error. The filter has answered (or chosen not to), so the transport sends nothing more.

View Source
var ErrInspected = errors.New("dygo: inspection written to DYGO_INSPECT_OUT; the application was not started")

ErrInspected is returned by Create and CreateApplicationContext when the DYGO_INSPECT_OUT environment variable is set: the dygo CLI (dygo routes, graph and check) runs the application that way to read its graph and routes, and the application is not started.

Functions

func Construct

func Construct[T any](ref *ModuleRef, ctor any) (T, error)

Construct calls ctor through ref and returns its result as T.

func Discover

func Discover[T any](ref *ModuleRef) []T

Discover is ProvidersImplementing for a provider: it returns every built singleton in the application that implements or is of type T. Call it from OnModuleInit or later, when every singleton is built. Packages such as events and schedule use it to find their listeners and jobs.

func Get

func Get[T any](r Resolver) (T, error)

Get resolves type T from r.

func GetNamed

func GetNamed[T any](r Resolver, tok NamedToken[T]) (T, error)

GetNamed resolves a named token from r.

func MustGet

func MustGet[T any](r Resolver) T

MustGet is Get that panics on error. Use it in main and tests.

func ProvidersImplementing

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

ProvidersImplementing returns every built singleton whose instance implements or is of type T. Transports use it to find their handlers (controllers, gateways, message handlers). Code inside a provider uses Discover.

func Ref

func Ref[T any]() any

Ref refers to the provider registered under T, as an enhancer argument:

r = r.Use(dygo.Guards(dygo.Ref[*auth.Guard]()))

func RefToken

func RefToken(tok Token) any

RefToken is Ref for a named token.

func RegisterConverter

func RegisterConverter[T any](fn func(string) (T, error))

RegisterConverter makes T usable in path, query, header, cookie and form fields. Types implementing encoding.TextUnmarshaler need no registration. Call it before creating the application, for example in an init function.

func RegisterSource

func RegisterSource(name string, fn func(*http.Request) (any, error))

RegisterSource adds a custom input tag. A field tagged name:"" receives fn's result:

dygo.RegisterSource("user", func(r *http.Request) (any, error) { return auth.UserFrom(r) })

type In struct {
	User *auth.User `user:""`
}

Call it before creating the application.

func Request

func Request(ctx context.Context) *http.Request

Request returns the *http.Request of the request handled with ctx, or nil.

func ResponseStatus

func ResponseStatus(ctx context.Context) int

ResponseStatus returns the status set with SetStatus during this request, or 0. Interceptors use it to see the real status of a successful response, for example a health check that answers 503.

func SetCookie

func SetCookie(ctx context.Context, c *http.Cookie)

SetCookie adds a Set-Cookie header from inside a handler.

func SetHeader

func SetHeader(ctx context.Context, key, value string)

SetHeader sets a response header from inside a handler.

func SetStatus

func SetStatus(ctx context.Context, code int)

SetStatus overrides the success status code from inside a handler. To fix it for the whole route, use the HTTPCode route option.

func Stopping

func Stopping(ctx context.Context) <-chan struct{}

Stopping returns a channel that is closed when the server starts shutting down. Long running handlers, such as an SSE stream waiting for events, should select on it so that shutdown does not wait for the shutdown timeout. It returns nil (a channel that never closes) outside a request.

func WithDurableContext

func WithDurableContext(ctx context.Context, id string, payload any) context.Context

WithDurableContext returns ctx carrying a context ID, so that Scoped.Get resolves durable providers for it outside an HTTP request: in a queue job, an event listener or a microservice handler. Plain request scoped providers cannot be resolved with it. Inside a request it takes precedence over the strategy.

Types

type App

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

App is a running application context: every singleton is built and every startup hook has run.

func CreateApplicationContext

func CreateApplicationContext(ctx context.Context, root *Module, opts ...Option) (*App, error)

CreateApplicationContext scans the module tree from root, validates the whole dependency graph, builds every singleton, and runs OnModuleInit and OnApplicationBootstrap. Wiring problems are reported together in a *BootError. ctx is passed to constructors that take a context.Context and to the startup hooks.

func (*App) Close

func (a *App) Close(ctx context.Context) error

Close is Shutdown without a signal.

func (*App) ConnectMicroservice

func (a *App) ConnectMicroservice(t Transport)

ConnectMicroservice adds a transport to the application, for a hybrid app. HTTPApp.Listen and App.Run start it with App.StartAllMicroservices if that was not called; shutdown closes it after BeforeApplicationShutdown, together with the HTTP drain.

func (*App) Controllers

func (a *App) Controllers() []any

Controllers returns every controller instance, in module level order.

func (*App) DurableContexts

func (a *App) DurableContexts() []string

DurableContexts lists the context IDs that have durable instances.

func (*App) Get

func (a *App) Get(tok Token) (any, error)

Get returns the instance for tok. It first looks from the root module, then in every module. It returns ErrNotFound or ErrAmbiguous when the token does not match exactly one provider.

func (*App) Providers

func (a *App) Providers() []ProviderInfo

Providers lists every built singleton provider and controller in build order.

func (*App) ReleaseContext

func (a *App) ReleaseContext(ctx context.Context, id string) error

ReleaseContext drops the durable instances of a context ID, for example when a tenant is deleted, after calling OnApplicationShutdown on them. The next request with the ID builds new ones. Requests still using the old instances keep them.

func (*App) Run

func (a *App) Run(ctx context.Context) error

Run blocks until ctx is cancelled or the process receives SIGINT or SIGTERM, then shuts the application down within the shutdown timeout. Connected transports are started first (see App.ConnectMicroservice).

func (*App) Shutdown

func (a *App) Shutdown(ctx context.Context, signal string) error

Shutdown runs OnModuleDestroy, BeforeApplicationShutdown and OnApplicationShutdown on every initialized instance, in reverse startup order. It is safe to call more than once; later calls do nothing.

func (*App) StartAllMicroservices

func (a *App) StartAllMicroservices(ctx context.Context) error

StartAllMicroservices starts every connected transport that is not running. When one fails, the ones it started are closed again and the error is returned.

func (*App) WithRequestScope

func (a *App) WithRequestScope(ctx context.Context, r *http.Request) (_ context.Context, end func())

WithRequestScope returns ctx carrying a new request scope, for a transport whose unit of work is not an HTTP request, such as a WebSocket message: Scoped.Get with the returned context builds request scoped providers once for that unit, and end calls their OnRequestEnd hooks. Call end when the work is done, from the goroutine that did it. r is the request the work belongs to (the WebSocket handshake, for example), or nil; it is what request scoped providers get for *http.Request and what the ContextIDStrategy reads, so durable providers resolve for its context ID. The new scope takes precedence over the scope of a request ctx already belongs to; WithDurableContext still takes precedence over both.

type ArgumentsHost

type ArgumentsHost interface {
	// Kind is the transport: KindHTTP, KindRPC or KindWS.
	Kind() ContextKind
	// HTTP returns the request and response. It is nil unless Kind is KindHTTP.
	HTTP() HTTPHost
	// RPC returns the message of a microservice handler. It is nil unless
	// Kind is KindRPC.
	RPC() RPCHost
	// WS returns the client and message of a WebSocket gateway handler. It is
	// nil unless Kind is KindWS.
	WS() WSHost
	// GraphQL returns the field being resolved. It is nil unless Kind is
	// KindGraphQL.
	GraphQL() GraphQLHost
	// Context is the request context.
	Context() context.Context
}

ArgumentsHost is what an exception filter receives.

type BeforeApplicationShutdown

type BeforeApplicationShutdown interface {
	BeforeApplicationShutdown(ctx context.Context, signal string) error
}

BeforeApplicationShutdown runs after every OnModuleDestroy. signal is "SIGINT" or "SIGTERM" when shutdown came from a signal, and empty otherwise.

type BindError

type BindError = binder.Error

BindError is returned (and written as a 400) when request input does not fit the handler's input struct. It lists every failing field.

type BootError

type BootError struct {
	Problems []error
}

BootError lists every problem found while building the application. It is returned by CreateApplicationContext instead of stopping at the first one.

func (*BootError) Error

func (e *BootError) Error() string

func (*BootError) Unwrap

func (e *BootError) Unwrap() []error

Unwrap returns the individual problems, for errors.Is and errors.As.

type CallHandler

type CallHandler interface {
	Handle() (any, error)
}

CallHandler runs the rest of the pipeline: later interceptors, pipes and the handler. Handle may be called more than once, for a retry.

type ContextID

type ContextID struct {
	// ID is the context ID returned by the strategy, "" for none.
	ID string
	// Payload is the strategy's payload from the first request with this
	// ID.
	Payload any
}

ContextID is the durable context a durable provider is built for. Durable providers inject it to learn their tenant:

func NewTenantDB(cid dygo.ContextID, pools *Pools) (*TenantDB, error) {
	return pools.Open(cid.ID)
}

In a plain request scoped provider it holds the request's ID and payload, or nothing when there is no strategy.

type ContextIDStrategy

type ContextIDStrategy func(r *http.Request) (id string, payload any)

ContextIDStrategy returns the context ID of a request. An empty id means the request has none: durable providers then behave like plain request scoped ones for it.

type ContextKind

type ContextKind string

ContextKind names the transport an ArgumentsHost belongs to.

const (
	KindHTTP    ContextKind = "http"
	KindRPC     ContextKind = "rpc"
	KindWS      ContextKind = "ws"
	KindGraphQL ContextKind = "graphql"
)

The transports. KindHTTP is a controller route; KindRPC a microservice pattern (package micro); KindWS a WebSocket gateway message (package ws); KindGraphQL a query, mutation or subscription field (package graphql).

type Controller

type Controller interface {
	Routes(r Router)
}

Controller is implemented by every type listed in a module's Controllers. Routes is called once at startup to register the controller's routes.

type Endpoint

type Endpoint struct {
	// Kind is KindRPC, KindWS or KindGraphQL. For KindGraphQL, the msg given
	// to Run must implement [GraphQLHost].
	Kind ContextKind
	// Pattern is the subject, method or event the handler serves.
	Pattern string
	// Owner is the provider that declared the handler. Refs and enhancer
	// constructors resolve from its module.
	Owner any
	// Handler is the handler function name, for errors and [RouteInfo].
	Handler string
	// Input and Output are the handler's types, nil when it has none.
	Input, Output reflect.Type
	// ControllerOptions apply to every handler of the owner, like Router.Use;
	// Options to this handler only. Only enhancers and metadata are used.
	ControllerOptions, Options []RouteOption
}

Endpoint describes one transport handler for Enhancers.Pipeline.

type Enhancers

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

Enhancers resolves the enhancers of one transport's handlers.

func NewEnhancers

func NewEnhancers(a *App, global []RouteOption, inheritApp bool) (*Enhancers, error)

NewEnhancers prepares pipelines for a transport. global holds the transport's own global enhancers (dygo.Guards(...) and so on). With inheritApp the app wide ones apply too: the WithGlobal* options and the App* groups, for hybrid apps. Without it a transport does not run the HTTP app's global enhancers, which often read HTTPHost.

func (*Enhancers) Pipeline

func (e *Enhancers) Pipeline(ep Endpoint) (*Pipeline, error)

Pipeline resolves the enhancers of one handler.

type ExceptionFilter

type ExceptionFilter interface {
	Catch(err error, host ArgumentsHost) bool
}

ExceptionFilter handles errors. Catch returns true when it wrote the response; false passes the error to the next filter and in the end to the error writer.

func FilterFor

func FilterFor[E error](fn func(e E, host ArgumentsHost)) ExceptionFilter

FilterFor returns a filter for errors of type E, matched with errors.As, like @Catch(SomeException):

dygo.FilterFor(func(e *store.ConflictError, host dygo.ArgumentsHost) {
	errs.WriteJSON(host.HTTP().Response(), errs.ToBody(errs.Conflict(e.Error())))
})

type ExecutionContext

type ExecutionContext interface {
	ArgumentsHost
	// SetContext replaces the request context seen by later stages and the
	// handler. ctx must be derived from Context().
	SetContext(ctx context.Context)
	// Route describes the matched route.
	Route() RouteInfo
	// Controller is the type of the controller that declared the route.
	Controller() reflect.Type
	// RouteMetadata returns the value set with [SetMetadata] on the route.
	RouteMetadata(key any) (any, bool)
	// ControllerMetadata returns the value set with [SetMetadata] through
	// Router.Use, that is for the whole controller.
	ControllerMetadata(key any) (any, bool)
	// MergedMetadata returns the controller's and the route's values joined,
	// controller first, when both are slices of the same type (joined once at
	// startup; do not modify it). Otherwise it returns the route's value, or
	// else the controller's.
	MergedMetadata(key any) (any, bool)
}

ExecutionContext describes the request being handled, for guards, interceptors and pipes.

It is not itself a context.Context: call Context to pass the request context on, and SetContext to change it for later stages and the handler (for example to add the authenticated user).

type FieldError

type FieldError = binder.FieldError

FieldError is one failing field in a BindError.

type FilterFunc

type FilterFunc func(err error, host ArgumentsHost) bool

FilterFunc is a function used as an ExceptionFilter.

func (FilterFunc) Catch

func (f FilterFunc) Catch(err error, host ArgumentsHost) bool

Catch calls f.

type GraphDep

type GraphDep struct {
	Token     string `json:"token"`
	Kind      string `json:"kind,omitempty"`
	Providers []int  `json:"providers,omitempty"`
}

GraphDep is one dependency of a provider. Kind is empty for a plain dependency, otherwise optional, lazy, scoped, group, context, moduleRef or request. Providers lists the provider IDs it resolved to: one for a token, every member for a group, none when an optional dependency is missing.

type GraphInfo

type GraphInfo struct {
	Modules   []GraphModule   `json:"modules"`
	Providers []GraphProvider `json:"providers"`
}

GraphInfo describes a module graph: every module and every provider with its resolved dependencies. Describe returns it, and the dygo CLI renders it (dygo graph) and checks it (dygo check).

func Describe

func Describe(root *Module, opts ...Option) (*GraphInfo, error)

Describe scans and validates the module tree from root, like CreateApplicationContext, without building anything. It is the cheapest wiring check, for a unit test or CI:

func TestWiring(t *testing.T) {
	if _, err := dygo.Describe(app.Module); err != nil {
		t.Fatal(err)
	}
}

On a *BootError the graph is still returned when the module tree could be scanned, with unresolved dependencies left empty.

type GraphModule

type GraphModule struct {
	Name    string   `json:"name"`
	Path    string   `json:"path"`
	Global  bool     `json:"global,omitempty"`
	Level   int      `json:"level"`
	Imports []int    `json:"imports,omitempty"`
	Exports []string `json:"exports,omitempty"`
}

GraphModule is one module. Imports holds indexes into GraphInfo.Modules. The root module is first.

type GraphProvider

type GraphProvider struct {
	ID         int        `json:"id"`
	Module     int        `json:"module"`
	Type       string     `json:"type"`
	Tokens     []string   `json:"tokens,omitempty"`
	Source     string     `json:"source"`
	Scope      string     `json:"scope"`
	Controller bool       `json:"controller,omitempty"`
	Groups     []string   `json:"groups,omitempty"`
	Deps       []GraphDep `json:"deps,omitempty"`
}

GraphProvider is one provider or controller. ID is its index in GraphInfo.Providers and Module its module's index in GraphInfo.Modules.

type GraphQLHost

type GraphQLHost interface {
	// Field is the root field as "Type.field", such as "Query.user".
	Field() string
	// Args are the field's arguments.
	Args() map[string]any
	// Request is the HTTP request that carried the operation, nil for a
	// subscription over a WebSocket after the handshake.
	Request() *http.Request
}

GraphQLHost gives access to the GraphQL field being resolved.

type Guard

type Guard interface {
	CanActivate(ec ExecutionContext) (bool, error)
}

Guard decides whether a request may go on. Returning false gives a 403; returning an error sends that error to the filters, so a guard can return errs.Unauthorized for a 401.

type GuardFunc

type GuardFunc func(ec ExecutionContext) (bool, error)

GuardFunc is a function used as a Guard.

func (GuardFunc) CanActivate

func (f GuardFunc) CanActivate(ec ExecutionContext) (bool, error)

CanActivate calls f.

type HTTPApp

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

HTTPApp is an application with an HTTP server. It embeds the application context, so Get, Providers and Shutdown work as on App.

func Create

func Create(ctx context.Context, root *Module, opts ...Option) (*HTTPApp, error)

Create builds the application like CreateApplicationContext, then asks every controller for its routes and compiles them. Route problems (bad patterns, duplicates, conflicts, bad handler input types) are reported in the same *BootError as wiring problems, before any startup hook runs.

func (*HTTPApp) Handler

func (a *HTTPApp) Handler() http.Handler

Handler returns the application's http.Handler, for httptest or a server you manage yourself.

func (*HTTPApp) Listen

func (a *HTTPApp) Listen(ctx context.Context, addr string) error

Listen serves on addr until ctx is cancelled or the process gets SIGINT or SIGTERM, then shuts down: OnModuleDestroy, BeforeApplicationShutdown, drain in-flight requests, OnApplicationShutdown. It returns nil after a clean shutdown.

func (*HTTPApp) Routes

func (a *HTTPApp) Routes() []RouteInfo

Routes lists every route, sorted by path.

func (*HTTPApp) Serve

func (a *HTTPApp) Serve(ctx context.Context, ln net.Listener) error

Serve is Listen on an existing listener. Connected transports are started first (see App.ConnectMicroservice).

type HTTPHost

type HTTPHost interface {
	Request() *http.Request
	Response() http.ResponseWriter
}

HTTPHost gives access to the HTTP request and response.

type Handler

type Handler interface {
	// contains filtered or unexported methods
}

Handler is a compiled route handler. Create one with Handle, HandleNoInput or HandleRaw.

func Handle

func Handle[In, Out any](fn func(context.Context, In) (Out, error)) Handler

Handle turns a typed function into a route handler. In is a struct whose tagged fields are filled from the request:

type GetUserIn struct {
	ID     uuid.UUID `path:"id"`
	Expand bool      `query:"expand"`
	Tenant string    `header:"X-Tenant" required:"true"`
	Body   CreateDTO `body:"json"`
}

Tags: path, query, header, cookie, form, file, body ("json", "form" or "raw"), plus default:"..." and required:"true". Out is written as JSON unless it is a Responder, NoContent, string or []byte. A returned error is written by the error writer; see package errs.

The binding plan is compiled when routes are built, so a bad In type is a startup error.

func HandleNoInput

func HandleNoInput[Out any](fn func(context.Context) (Out, error)) Handler

HandleNoInput is Handle for a handler that needs nothing from the request.

func HandleRaw

func HandleRaw(fn func(w http.ResponseWriter, r *http.Request) error) Handler

HandleRaw is the escape hatch: fn gets the plain ResponseWriter and Request. An error it returns is written by the error writer if nothing was written yet.

type In

type In struct{}

In marks a parameter struct. Embed it in a struct used as a constructor parameter and the container fills each exported field:

type Params struct {
	dygo.In
	DB      *sql.DB `name:"db.primary"`
	Cache   Cache   `optional:"true"`
	Plugins []Plugin `group:"plugins"`
}

Supported tags: name (named token, see NewToken), optional ("true" gives the zero value when nothing is provided) and group (a slice of group members).

type Interceptor

type Interceptor interface {
	Intercept(ec ExecutionContext, next CallHandler) (any, error)
}

Interceptor wraps the handler. Work before next.Handle runs before the handler; the result can be changed, replaced or mapped to another error afterwards:

func (Envelope) Intercept(ec dygo.ExecutionContext, next dygo.CallHandler) (any, error) {
	out, err := next.Handle()
	if err != nil {
		return nil, err
	}
	return map[string]any{"data": out}, nil
}

type InterceptorFunc

type InterceptorFunc func(ec ExecutionContext, next CallHandler) (any, error)

InterceptorFunc is a function used as an Interceptor.

func (InterceptorFunc) Intercept

func (f InterceptorFunc) Intercept(ec ExecutionContext, next CallHandler) (any, error)

Intercept calls f.

type Lazy

type Lazy[T any] struct {
	// contains filtered or unexported fields
}

Lazy defers resolving a dependency until Get is called, which is how a dependency cycle is broken. Do not call Get inside a constructor; call it later, for example in OnModuleInit or in a request handler.

func (Lazy[T]) Get

func (l Lazy[T]) Get() (T, error)

Get resolves the dependency. The result is cached after the first call.

func (Lazy[T]) MustGet

func (l Lazy[T]) MustGet() T

MustGet is Get that panics on error.

type Middleware

type Middleware = func(http.Handler) http.Handler

Middleware is standard net/http middleware, so any existing Go middleware works.

type Module

type Module struct {
	// Name identifies the module in error messages. Required.
	Name string

	// Global makes the module's exports visible to every module without an
	// import.
	Global bool

	// Imports are modules whose exports this module can inject.
	Imports []*Module

	// Providers are constructed by the container and visible inside the module.
	Providers []Provider

	// Controllers are built like singleton providers but cannot be injected or
	// exported. The HTTP layer (phase 2) registers their routes.
	Controllers []Provider

	// Exports lists the tokens other modules may inject. A module can export
	// its own providers or re-export tokens it imports.
	Exports []Token
}

Module groups providers. Declare modules as package level pointers so that importing the same module from several places shares one set of instances:

var Module = &dygo.Module{Name: "users", ...}

A dynamic module (the ForRoot pattern) is a function that returns a new *Module:

func ForRoot(opts Options) *dygo.Module {
	return &dygo.Module{
		Name:      "config",
		Global:    true,
		Providers: []dygo.Provider{dygo.Value(opts), dygo.Provide(NewService)},
		Exports:   []dygo.Token{dygo.TypeOf[*Service]()},
	}
}

type ModuleRef

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

ModuleRef gives a provider access to the container from its own module's point of view. Inject it as a *dygo.ModuleRef constructor parameter.

func (*ModuleRef) App

func (r *ModuleRef) App() *App

App returns the application, for packages that discover handlers and build their pipelines with NewEnhancers from a provider (package ws). It is nil while constructors run; call it from OnModuleInit or later.

func (*ModuleRef) Create

func (r *ModuleRef) Create(ctor any) (any, error)

Create calls ctor with its parameters resolved from this module, without registering the result. The returned value gets no lifecycle hooks.

func (*ModuleRef) Get

func (r *ModuleRef) Get(tok Token) (any, error)

Get returns the instance for tok if it is visible in this module: its own providers, its imports' exports, or a global module's exports. A transient provider is built anew on each call.

func (*ModuleRef) Module

func (r *ModuleRef) Module() string

Module returns the name of the module this reference belongs to.

type NamedToken

type NamedToken[T any] struct {
	// contains filtered or unexported fields
}

NamedToken is a typed, named token. Two values of the same type can be told apart by name:

var PrimaryDB = dygo.NewToken[*sql.DB]("db.primary")
dygo.Provide(OpenPrimary, dygo.For(PrimaryDB))

Inject it with a field of type *sql.DB tagged name:"db.primary" in a parameter struct that embeds In.

func NewToken

func NewToken[T any](name string) NamedToken[T]

NewToken creates a named token for values of type T. It panics if name is empty, because an empty name would collide with the plain type token.

func (NamedToken[T]) Name

func (t NamedToken[T]) Name() string

Name returns the token's name.

func (NamedToken[T]) String

func (t NamedToken[T]) String() string

String describes the token in error messages.

func (NamedToken[T]) Type

func (t NamedToken[T]) Type() reflect.Type

Type returns T.

type NoContent

type NoContent struct{}

NoContent as Out writes 204 with no body.

type OnApplicationBootstrap

type OnApplicationBootstrap interface {
	OnApplicationBootstrap(ctx context.Context) error
}

OnApplicationBootstrap runs after every module has been initialized.

type OnApplicationShutdown

type OnApplicationShutdown interface {
	OnApplicationShutdown(ctx context.Context, signal string) error
}

OnApplicationShutdown runs last.

type OnModuleDestroy

type OnModuleDestroy interface {
	OnModuleDestroy(ctx context.Context) error
}

OnModuleDestroy runs first during shutdown.

type OnModuleInit

type OnModuleInit interface {
	OnModuleInit(ctx context.Context) error
}

OnModuleInit runs once the instance and all its dependencies are built.

type OnRequestEnd

type OnRequestEnd interface {
	OnRequestEnd(ctx context.Context)
}

OnRequestEnd is called on every request scoped instance when the request that created it finishes, in reverse creation order. Use it for per-request cleanup such as committing or rolling back a transaction.

type Option

type Option func(*options)

Option configures CreateApplicationContext.

func WithBodyLimit

func WithBodyLimit(n int64) Option

WithBodyLimit sets the maximum request body size in bytes. The default is 1 MiB; zero or less means no limit. Routes can override it with BodyLimit.

func WithContextIDStrategy

func WithContextIDStrategy(s ContextIDStrategy) Option

WithContextIDStrategy sets how requests map to durable contexts:

dygo.WithContextIDStrategy(func(r *http.Request) (string, any) {
	t := r.Header.Get("X-Tenant-ID")
	return t, t
})

The ID is trusted as is: validate it (for example against known tenants) in the strategy, since every new ID builds and keeps new instances.

func WithErrorWriter

func WithErrorWriter(w errs.Writer) Option

WithErrorWriter replaces the default error writer (errs.DefaultWriter).

func WithGlobalFilters

func WithGlobalFilters(f ...any) Option

WithGlobalFilters adds exception filters to every route. They run after route and controller filters, before the error writer.

func WithGlobalGuards

func WithGlobalGuards(g ...any) Option

WithGlobalGuards adds guards to every route, like app.useGlobalGuards. Constructors and Refs resolve from the root module.

func WithGlobalInterceptors

func WithGlobalInterceptors(i ...any) Option

WithGlobalInterceptors adds interceptors to every route.

func WithGlobalPipes

func WithGlobalPipes(p ...any) Option

WithGlobalPipes adds pipes to every typed route.

func WithGlobalPrefix

func WithGlobalPrefix(prefix string, exclude ...string) Option

WithGlobalPrefix puts prefix in front of every route. Routes whose path (without the prefix) equals or starts with one of exclude are left alone, for example "/health".

func WithHTTPServer

func WithHTTPServer(fn func(*http.Server)) Option

WithHTTPServer lets you change the *http.Server before it starts: timeouts, TLS, error log. Defaults: ReadHeaderTimeout 10s, IdleTimeout 120s.

func WithLogger

func WithLogger(l *slog.Logger) Option

WithLogger sets the logger the framework writes to. By default nothing is logged.

func WithMiddleware

func WithMiddleware(mw ...Middleware) Option

WithMiddleware adds application wide middleware. It wraps everything, including 404 responses. The first middleware is the outermost.

func WithOverride

func WithOverride(tok Token, p Provider) Option

WithOverride replaces the provider registered under tok, in every module that provides it, with p. The original provider is not built when all of its tokens are overridden. Mostly used by tests; see package dygotest.

func WithShutdownTimeout

func WithShutdownTimeout(d time.Duration) Option

WithShutdownTimeout bounds how long App.Run waits for shutdown hooks after a signal. The default is 10 seconds.

func WithVersioning

func WithVersioning(v VersioningOptions) Option

WithVersioning turns on API versioning.

type Optional

type Optional[T any] struct {
	// contains filtered or unexported fields
}

Optional is a dependency that may be missing.

func (Optional[T]) Get

func (o Optional[T]) Get() (T, bool)

Get returns the value and whether it was provided.

func (Optional[T]) OrElse

func (o Optional[T]) OrElse(def T) T

OrElse returns the value, or def when it was not provided.

type PanicError

type PanicError struct {
	Value any
	Stack []byte
}

PanicError is the error filters receive for a recovered panic. The default error writer answers 500 and logs it with the stack.

func (*PanicError) Error

func (e *PanicError) Error() string

type Pipe

type Pipe interface {
	Transform(ec ExecutionContext, in any) error
}

Pipe transforms or validates a handler's input after binding. in is a pointer to the bound input struct (the In of Handle), so a pipe can normalise fields in place. An error stops the request; return a *validate.ValidationError or an *errs.HTTPError for a 400. Pipes do not run for HandleRaw routes.

type PipeFunc

type PipeFunc func(ec ExecutionContext, in any) error

PipeFunc is a function used as a Pipe.

func (PipeFunc) Transform

func (f PipeFunc) Transform(ec ExecutionContext, in any) error

Transform calls f.

type Pipeline

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

Pipeline is the resolved guards, interceptors, pipes and filters of one transport handler.

func (*Pipeline) Fail

func (p *Pipeline) Fail(ctx context.Context, msg any, err error) error

Fail sends an error that happened before Run, such as a payload that does not decode, through the filters. It returns ErrFiltered or err.

func (*Pipeline) Info

func (p *Pipeline) Info() RouteInfo

Info describes the handler. Method is the kind ("rpc" or "ws") and Path the pattern.

func (*Pipeline) Run

func (p *Pipeline) Run(ctx context.Context, msg, in any, fn func(ctx context.Context) (any, error)) (out any, err error)

Run handles one message: guards, then interceptors around pipes and fn. in is the decoded input (a pointer, given to pipes and as Data), msg the transport's message or client. An error, or a panic recovered as a *PanicError, goes to the filters; Run returns ErrFiltered when one of them caught it and the error otherwise, for the transport to answer.

type ProvideOption

type ProvideOption func(*Provider)

ProvideOption configures a Provider.

func As

func As[T any]() ProvideOption

As also registers the provider under type T, which is usually an interface the concrete type implements. The same instance is shared across all tokens.

func Durable

func Durable() ProvideOption

Durable makes a RequestScoped provider durable: it is built once per context ID (usually a tenant) chosen by WithContextIDStrategy and reused by every request with that ID, instead of once per request. A durable provider may inject ContextID for the ID and payload, singletons and other durable providers, but not *http.Request or a request scoped provider that is not durable. Its instances get OnApplicationShutdown at shutdown or on App.ReleaseContext; OnRequestEnd is not called.

func For

func For(tok Token) ProvideOption

For registers the provider under tok instead of its own type. Use it with NewToken for named values. Can be given more than once.

func Group

func Group(name string) ProvideOption

Group adds the provider to a named group. Consumers receive every member as a slice through a field tagged group:"name" in an In struct. Groups are application wide. A provider with a group and no For or As option is not registered under its own type.

func WithScope

func WithScope(s Scope) ProvideOption

WithScope sets the provider's scope. The default is Singleton.

type Provider

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

Provider describes how the container gets a value. Create one with Provide, Value or Alias. The zero Provider is invalid.

func Alias

func Alias(alias, target Token) Provider

Alias makes alias resolve to the same instance as target. The target's type must be assignable to the alias's type.

func Provide

func Provide(ctor any, opts ...ProvideOption) Provider

Provide registers a constructor function. The container calls it once (or once per consumer for Transient) with its parameters resolved by type.

Accepted shapes:

func(deps...) T
func(deps...) (T, error)

A parameter may be any provided type, context.Context (the boot context), *ModuleRef, Optional, Lazy, or a struct embedding In.

By default the provider is registered under TypeOf[T]. For replaces that token, As adds more, and Group alone contributes only to the group.

func Value

func Value(v any, opts ...ProvideOption) Provider

Value registers an existing value. The default token is the value's dynamic type; use For or As to register it under an interface or named token.

type ProviderInfo

type ProviderInfo struct {
	Module     string
	Type       reflect.Type
	Source     string
	Instance   any
	Controller bool
}

ProviderInfo describes one built singleton, for discovery.

type RPCHost

type RPCHost interface {
	// Pattern is the pattern the handler was registered for.
	Pattern() string
	// Data is the decoded payload, a pointer to the handler's input.
	Data() any
	// Message is the transport's own message, for example a *nats.Msg.
	Message() any
}

RPCHost gives access to a microservice message.

type RawJSON

type RawJSON []byte

RawJSON as Out is a body already encoded as JSON. It is written as is, with the route's status and a JSON content type, and is not checked, so it must come from json.Marshal or another trusted encoder. The cache interceptor uses it to answer from stored bytes.

type Resolver

type Resolver interface {
	Get(tok Token) (any, error)
}

Resolver is anything providers can be looked up from: an *App or a *ModuleRef.

type Responder

type Responder interface {
	Respond(w http.ResponseWriter, r *http.Request) error
}

Responder is an Out value that writes its own response.

func File

func File(path string) Responder

File serves a file from disk with http.ServeContent, which handles Range, If-Modified-Since and content type detection. path must not come from user input without cleaning.

func RedirectTo

func RedirectTo(url string, code int) Responder

RedirectTo redirects to url with code (for example 302 or 307). Return it from a handler for a dynamic target; for a fixed one, use the Redirect route option.

func SSE

func SSE[T any](events iter.Seq[T]) Responder

SSE streams events as text/event-stream. Each value is JSON encoded (strings are sent as is). The stream ends when the sequence ends, the client disconnects, or the server shuts down. The sequence itself should also watch the request context if it can block for a long time.

func Stream

func Stream(r io.Reader, contentType string) Responder

Stream writes r as the body with the given content type. r is closed afterwards if it is an io.Closer.

type RouteInfo

type RouteInfo struct {
	// Method is the HTTP method, or "" for a route registered with All.
	Method string
	// Host is the host restriction, if any.
	Host string
	// Path is the full ServeMux path pattern, including the global prefix
	// and URI version.
	Path string
	// Version is the API version the route serves, if versioning is on.
	Version string
	// Controller and Module identify where the route was declared.
	Controller string
	Module     string
	// Handler is the handler function name.
	Handler string
	// Input and Output are the In and Out types of a typed handler, nil for
	// HandleRaw. Tools such as package openapi read them.
	Input, Output reflect.Type
	// Status is the success status set with HTTPCode, or 0 for the default.
	Status int
	// contains filtered or unexported fields
}

RouteInfo describes one registered route.

func RouteOf

func RouteOf(ctx context.Context) RouteInfo

RouteOf describes the route handling ctx. The zero RouteInfo is returned outside a request.

func RoutesOf

func RoutesOf(ctx context.Context) []RouteInfo

RoutesOf returns the application's route table from inside a request, for handlers that describe the API, such as package openapi. It returns nil outside a request.

func (RouteInfo) Metadata

func (ri RouteInfo) Metadata(key any) (any, bool)

Metadata returns the route's metadata for key, as ExecutionContext.MergedMetadata does: slices set on both the controller and the route joined, otherwise the route's value, otherwise the controller's.

func (RouteInfo) String

func (ri RouteInfo) String() string

type RouteOption

type RouteOption interface {
	// contains filtered or unexported methods
}

RouteOption configures a route. Options given to Router.Use apply first, at controller level, then the route's own options, at route level.

func BodyLimit

func BodyLimit(n int64) RouteOption

BodyLimit overrides the application body size limit for the route. Zero or less means no limit.

func Filters

func Filters(f ...any) RouteOption

Filters adds exception filters, like @UseFilters.

func Guards

func Guards(g ...any) RouteOption

Guards adds guards, like @UseGuards. On Router.Use they guard every route of the controller.

func HTTPCode

func HTTPCode(code int) RouteOption

HTTPCode sets the success status code. The default is 201 for POST and 200 otherwise. A handler can still change it per request with SetStatus.

func Header(key, value string) RouteOption

Header sets a static response header.

func Interceptors

func Interceptors(i ...any) RouteOption

Interceptors adds interceptors, like @UseInterceptors.

func Options

func Options(opts ...RouteOption) RouteOption

Options combines several route options into one:

func AdminOnly() dygo.RouteOption { return dygo.Options(authMiddleware, dygo.Header("Cache-Control", "no-store")) }

func Pipes

func Pipes(p ...any) RouteOption

Pipes adds pipes, like @UsePipes.

func Redirect

func Redirect(url string, code int) RouteOption

Redirect makes the route redirect after the handler succeeds. Return RedirectTo from the handler for a dynamic target.

func RouteMiddleware

func RouteMiddleware(mw ...Middleware) RouteOption

RouteMiddleware adds net/http middleware to the route. With Router.Use it applies to every route of the controller.

func SetMetadata

func SetMetadata(key, value any) RouteOption

SetMetadata attaches a value to the route, or to every route of the controller when given to Router.Use. Guards and interceptors read it from the ExecutionContext; package meta adds typed keys. Use a key of an unexported type to avoid collisions.

func StrictJSON

func StrictJSON() RouteOption

StrictJSON rejects JSON bodies that contain unknown fields.

func Version

func Version(v ...string) RouteOption

Version sets the route's API versions, overriding Router.Version and the default version. Use VersionNeutral for a route that matches every version.

type Router

type Router interface {
	// Prefix adds a path prefix for routes registered through the child.
	Prefix(p string) Router
	// Host restricts routes to a host, like "api.example.com" or "{tenant}.example.com".
	Host(h string) Router
	// Version sets the API versions of routes registered through the child.
	Version(v ...string) Router
	// Use applies options, such as middleware, to every route registered through the child.
	Use(opts ...RouteOption) Router

	Get(path string, h Handler, opts ...RouteOption)
	Post(path string, h Handler, opts ...RouteOption)
	Put(path string, h Handler, opts ...RouteOption)
	Patch(path string, h Handler, opts ...RouteOption)
	Delete(path string, h Handler, opts ...RouteOption)
	Head(path string, h Handler, opts ...RouteOption)
	Options(path string, h Handler, opts ...RouteOption)
	// All matches every method.
	All(path string, h Handler, opts ...RouteOption)
}

Router registers routes. Prefix, Host, Version and Use return a child router and leave the receiver unchanged:

func (c *UsersController) Routes(r dygo.Router) {
	r = r.Prefix("/users")
	r.Get("/", dygo.Handle(c.List))
	r.Get("/{id}", dygo.Handle(c.Get))
}

Paths use Go's pattern syntax: {id} for a parameter, {path...} for the rest of the path. GET routes also answer HEAD.

type SSEEvent

type SSEEvent struct {
	ID    string
	Event string
	Data  any
	Retry time.Duration
}

SSEEvent is a server-sent event with optional id, event name and retry. Yield it from an SSE sequence to control those fields; any other value is sent as a data-only event.

type Scope

type Scope int

Scope controls how many instances of a provider exist.

const (
	// Singleton providers are built once at boot and shared. This is the default.
	Singleton Scope = iota
	// Transient providers are built again for every consumer that injects them.
	// Lifecycle hooks are not called on transient instances.
	Transient
	// RequestScoped providers are built at most once per HTTP request. Only
	// other request scoped providers may inject them directly; singletons and
	// controllers use [Scoped] instead. Lifecycle hooks are not called on them;
	// implement [OnRequestEnd] for per-request cleanup.
	RequestScoped
)

func (Scope) String

func (s Scope) String() string

type Scoped

type Scoped[T any] struct {
	// contains filtered or unexported fields
}

Scoped gives a singleton (for example a controller) access to a RequestScoped provider. Get returns the instance for the request carried by ctx, building it on first use within that request.

type Controller struct{ tx dygo.Scoped[*sql.Tx] }

func (c *Controller) Create(ctx context.Context, in CreateIn) (*User, error) {
	tx, err := c.tx.Get(ctx)
	...
}

func (Scoped[T]) Get

func (s Scoped[T]) Get(ctx context.Context) (T, error)

Get resolves the value for the request in ctx. It returns an error when ctx does not belong to a request handled by Dygo.

func (Scoped[T]) MustGet

func (s Scoped[T]) MustGet(ctx context.Context) T

MustGet is Get that panics on error.

type Token

type Token interface {
	// String describes the token in error messages.
	String() string
	// Type is the Go type of the value the token resolves to.
	Type() reflect.Type
	// contains filtered or unexported methods
}

Token identifies a provider in the container. Create one with TypeOf or NewToken.

func TypeOf

func TypeOf[T any]() Token

TypeOf returns the token for type T. This is the token a constructor returning T is registered under, and the token a constructor parameter of type T asks for.

type Transport

type Transport interface {
	// Listen finds its handlers in a (usually with [ProvidersImplementing]),
	// builds their pipelines and starts serving. It returns once the
	// transport takes messages; a wiring problem is returned as an error.
	Listen(ctx context.Context, a *App) error
	// Close stops taking messages and waits for running handlers until ctx
	// is done.
	Close(ctx context.Context) error
}

Transport is a server other than the HTTP one: a message broker consumer, a gRPC server. Packages such as micro/nats implement it.

type VersioningOptions

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

VersioningOptions configures API versioning. Create one with URIVersioning, HeaderVersioning, MediaTypeVersioning or CustomVersioning and pass it to WithVersioning.

func CustomVersioning

func CustomVersioning(extract func(*http.Request) []string, defaultVersion ...string) VersioningOptions

CustomVersioning reads versions with extract, in order of preference.

func HeaderVersioning

func HeaderVersioning(header string, defaultVersion ...string) VersioningOptions

HeaderVersioning reads the version from a request header, for example "X-API-Version". Requests without the header get the default version.

func MediaTypeVersioning

func MediaTypeVersioning(key string, defaultVersion ...string) VersioningOptions

MediaTypeVersioning reads the version from an Accept header parameter, for example key "v" in "Accept: application/json;v=2".

func URIVersioning

func URIVersioning(defaultVersion ...string) VersioningOptions

URIVersioning puts the version in the path: /v1/users. Routes without a version get defaultVersion.

type WSHost

type WSHost interface {
	// Pattern is the event name the handler was registered for.
	Pattern() string
	// Data is the decoded payload, a pointer to the handler's input.
	Data() any
	// Client is the connection that sent the message, a *ws.Client.
	Client() any
}

WSHost gives access to a WebSocket message.

Directories

Path Synopsis
Package cache is a key-value cache with a time to live: a Store (in memory by default), typed helpers, an HTTP response cache interceptor and Wrap to cache a function.
Package cache is a key-value cache with a time to live: a Store (in memory by default), typed helpers, an HTTP response cache interceptor and Wrap to cache a function.
cmd
dygo command
Command dygo is the Dygo CLI.
Command dygo is the Dygo CLI.
Package config loads typed configuration from the environment and .env files:
Package config loads typed configuration from the environment and .env files:
Package console runs one-off commands inside the application context: a seed script, a data fix or a report that needs the same services as the app, without starting the HTTP server.
Package console runs one-off commands inside the application context: a seed script, a data fix or a report that needs the same services as the app, without starting the HTTP server.
Package cqrs has command and query buses with typed handlers.
Package cqrs has command and query buses with typed handlers.
Package dygotest builds Dygo applications in tests:
Package dygotest builds Dygo applications in tests:
Package errs defines HTTP errors for Dygo handlers and the default writer that turns any error into a JSON response:
Package errs defines HTTP errors for Dygo handlers and the default writer that turns any error into a JSON response:
Package events is an in-process event emitter.
Package events is an in-process event emitter.
examples
orders command
Command orders is the phase 6 example: one HTTP route creates an order through the command bus, the order service emits an event, a listener puts a confirmation email on the queue, and a scheduled job reports the count.
Command orders is the phase 6 example: one HTTP route creates an order through the command bus, the order service emits an event, a listener puts a confirmation email on the queue, and a scheduled job reports the count.
worker command
Command worker is the phase 1 acceptance app: modules, a dynamic global module, interface binding, a provider group, lifecycle hooks and graceful shutdown, with no HTTP.
Command worker is the phase 1 acceptance app: modules, a dynamic global module, interface binding, a provider group, lifecycle hooks and graceful shutdown, with no HTTP.
worker/config
Package config is a dynamic, global module: ForRoot returns a new module configured for the caller.
Package config is a dynamic, global module: ForRoot returns a new module configured for the caller.
worker/report
Package report runs a background loop over every reporter in the application, collected through a provider group.
Package report runs a background loop over every reporter in the application, collected through a provider group.
worker/store
Package store is a fake database with connection lifecycle hooks.
Package store is a fake database with connection lifecycle hooks.
worker/users
Package users shows interface binding with dygo.As and a module that imports another module.
Package users shows interface binding with dygo.As and a module that imports another module.
Package health serves liveness and readiness checks:
Package health serves liveness and readiness checks:
Package interceptors holds ready made interceptors.
Package interceptors holds ready made interceptors.
internal
binder
Package binder fills a handler's input struct from an HTTP request using struct tags.
Package binder fills a handler's input struct from an HTTP request using struct tags.
pattern
Package pattern joins and checks route paths written in Go's net/http pattern syntax ("/users/{id}", "/files/{path...}").
Package pattern joins and checks route paths written in Go's net/http pattern syntax ("/users/{id}", "/files/{path...}").
Package logger builds the application's *slog.Logger and provides it through DI:
Package logger builds the application's *slog.Logger and provides it through DI:
Package meta adds typed route metadata on top of dygo.SetMetadata:
Package meta adds typed route metadata on top of dygo.SetMetadata:
Package micro is the transport-independent part of Dygo microservices: message and event handlers declared by providers, a client to call other services, and an in-process transport for tests.
Package micro is the transport-independent part of Dygo microservices: message and event handlers declared by providers, a client to call other services, and an in-process transport for tests.
nats module
Package middleware holds net/http middleware for production services: request IDs, request logging, CORS, security headers, CSRF protection and compression.
Package middleware holds net/http middleware for production services: request IDs, request logging, CORS, security headers, CSRF protection and compression.
Package openapi generates an OpenAPI 3.1 document from the route table.
Package openapi generates an OpenAPI 3.1 document from the route table.
Package queue runs background jobs: producers add jobs to a named queue, and processors handle them in workers with retries.
Package queue runs background jobs: producers add jobs to a named queue, and processors handle them in workers with retries.
Package ratelimit limits requests per client:
Package ratelimit limits requests per client:
Package schedule runs jobs on a cron schedule, at an interval or once after a delay.
Package schedule runs jobs on a cron schedule, at an interval or once after a delay.
sql module
Package validate checks handler input after binding.
Package validate checks handler input after binding.

Jump to

Keyboard shortcuts

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