Documentation
¶
Overview ¶
Package nexus deployment annotations.
DeployAs marks a module as a candidate deployment unit — when the framework later supports independent rollout (`nexus gen clients` + `NEXUS_DEPLOYMENT` boot selector), the tag identifies which binary the module belongs to. In today's monolith mode the tag is metadata only: it surfaces on the dashboard so readers can see the planned split topology before any splitting happens.
var users = nexus.Module("users",
nexus.DeployAs("users-svc"),
nexus.Provide(NewUsersService),
nexus.AsRest("GET", "/users/:id", NewGetUser),
)
Untagged modules are "always local" — they ride along with whichever deployment is active. Reserve DeployAs for modules with a real chance of being peeled out (separate codebase boundary, separate scaling needs, separate on-call rotation).
Package nexus is a thin framework over Gin that registers every endpoint (REST, GraphQL, WebSocket) into a central registry, traces every request into an in-memory event bus, and exposes both under /__nexus for tooling — notably the Vue dashboard.
nexus does NOT replace the caller's GraphQL layer: hand it a *graphql.Schema (typically built with github.com/paulmanoni/nexus/graph) and it mounts + introspects.
Index ¶
- Constants
- func CallerAuthorization(ctx context.Context) string
- func ClientIPFromCtx(ctx context.Context) string
- func DeploymentFromEnv() string
- func GqlCall[T any](ctx context.Context, callable ClientCallable, opType, opName string, args any, ...) (T, error)
- func RegisterAutoClient(fn any)
- func RegisterCrossModuleDep(consumer, dep string)
- func RegisterModuleDeployment(moduleName, tag string)
- func RegisterRemoteServicePlaceholder(name, tag string)
- func RoutePrefix(p string) routePrefixOption
- func Run(cfg Config, opts ...Option)
- func SetDeploymentDefaults(d DeploymentDefaults)
- func SetGraphStatus(ctx context.Context, code int)
- func WithCallerAuthorization(ctx context.Context, header string) context.Context
- func WithClientIP(ctx context.Context, ip string) context.Context
- func WithRouteKey(ctx context.Context, key string) context.Context
- type App
- func (a *App) Bus() *trace.Bus
- func (a *App) Cache() *cache.Manager
- func (a *App) Cron(name, schedule string) *CronBuilder
- func (a *App) Deployment() string
- func (a *App) Engine() *gin.Engine
- func (a *App) Metrics() metrics.Store
- func (a *App) OnResourceUse(target UseReporter)
- func (a *App) Peer(tag string) (Peer, bool)
- func (a *App) RateLimiter() ratelimit.Store
- func (a *App) Register(r resource.Resource)
- func (a *App) Registry() *registry.Registry
- func (a *App) Run(addr string) error
- func (a *App) Scheduler() *cron.Scheduler
- func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request)
- func (a *App) Service(name string) *Service
- func (a *App) Topology() Topology
- func (a *App) Version() string
- type AuthPropagator
- type AuthPropagatorFunc
- type CORSConfig
- type ClientCallable
- type Config
- type CronBuilder
- type DashboardConfig
- type DeploymentDefaults
- type GqlField
- type GqlOption
- func Deprecated(reason string) GqlOption
- func Desc(s string) GqlOption
- func GraphMiddleware(name, description string, mw graph.FieldMiddleware) GqlOption
- func Middleware(name, description string, mw graph.FieldMiddleware) GqlOptiondeprecated
- func OnService[S any]() GqlOption
- func Op(name string) GqlOption
- func RateLimit(l ratelimit.Limit) GqlOption
- func WithArgValidator(arg string, vs ...graph.Validator) GqlOption
- type GqlOptions
- type GraphQLConfig
- type Listener
- type ListenerScope
- type LocalInvoker
- type LocalInvokerOption
- type MiddlewareConfig
- type MiddlewareOption
- type NexusResourceProvider
- type Option
- func AsMutation(fn any, opts ...GqlOption) Option
- func AsQuery(fn any, opts ...GqlOption) Option
- func AsRest(method, path string, fn any, opts ...RestOption) Option
- func AsRestHandler(method, path string, factory any, opts ...RestOption) Option
- func AsSubscription(fn any, opts ...GqlOption) Option
- func AsWS(path, msgType string, fn any, opts ...WSOption) Option
- func AsWorker(name string, fn any) Option
- func DeployAs(tag string) Option
- func Invoke(fns ...any) Option
- func Module(name string, opts ...Option) Option
- func Provide(fns ...any) Option
- func Raw(opt fx.Option) Option
- func Supply(values ...any) Option
- type Params
- type Peer
- type RemoteCaller
- type RemoteCallerOption
- func WithAuthPropagator(p AuthPropagator) RemoteCallerOption
- func WithEjectDuration(d time.Duration) RemoteCallerOption
- func WithLocalVersion(v string) RemoteCallerOption
- func WithMinVersion(v string) RemoteCallerOption
- func WithRemoteHTTPClient(c *http.Client) RemoteCallerOption
- func WithRemoteTimeout(d time.Duration) RemoteCallerOption
- func WithRetries(n int) RemoteCallerOption
- type RemoteError
- type RestOption
- type ServerConfig
- type Service
- func (s *Service) AtGraphQL(path string) *Service
- func (s *Service) Attach(r resource.Resource) *Service
- func (s *Service) Auth(fn UserDetailsFn) *Service
- func (s *Service) Describe(desc string) *Service
- func (s *Service) GraphQLPath() string
- func (s *Service) MountGraphQL(path string, schema *graphql.Schema, opts ...gql.Option)
- func (s *Service) Name() string
- func (s *Service) REST(method, path string) *rest.Builder
- func (s *Service) Using(names ...string) *Service
- func (s *Service) UsingDefaults() *Service
- func (s *Service) WebSocket(path string) *ws.Builder
- type StoreConfig
- type Topology
- type UseReporter
- type UserDetailsFn
- type UserError
- type WSOption
- type WSSession
- func (s *WSSession) ClientID() string
- func (s *WSSession) Context() context.Context
- func (s *WSSession) Emit(eventType string, data any)
- func (s *WSSession) EmitToClient(eventType string, data any, clientIDs ...string)
- func (s *WSSession) EmitToRoom(eventType string, data any, room string)
- func (s *WSSession) EmitToUser(eventType string, data any, userIDs ...string)
- func (s *WSSession) JoinRoom(room string)
- func (s *WSSession) LeaveRoom(room string)
- func (s *WSSession) Metadata() map[string]any
- func (s *WSSession) Send(eventType string, data any) error
- func (s *WSSession) SendRaw(data []byte)
- func (s *WSSession) UserID() string
Constants ¶
const DefaultGraphQLPath = "/graphql"
DefaultGraphQLPath is the mount path nexus.AsQuery / AsMutation use when a service hasn't called AtGraphQL.
const GqlFieldGroup = "nexus.graph.fields"
GqlFieldGroup is the single fx value-group name every reflective GraphQL registration feeds. fxmod's auto-mount Invoke reads this group, partitions entries by ServiceType, and mounts one schema per service.
Variables ¶
This section is empty.
Functions ¶
func CallerAuthorization ¶ added in v0.10.0
CallerAuthorization returns the Authorization header captured for this request, or "" when none. Used by DefaultAuthPropagator and available for custom propagators that want to inspect/decorate it.
func ClientIPFromCtx ¶ added in v0.3.0
ClientIPFromCtx pulls the IP stashed via WithClientIP (or ratelimit.WithClientIP). Empty when absent.
func DeploymentFromEnv ¶ added in v0.9.0
func DeploymentFromEnv() string
DeploymentFromEnv reads NEXUS_DEPLOYMENT. The single-binary, multi-shape pattern: the same compiled binary boots as different deployment units based on the env var alone — no rebuild, no flags. Returns "" when unset, which the framework treats as monolith mode.
func main() {
nexus.Run(nexus.Config{
Deployment: nexus.DeploymentFromEnv(),
// ...
}, allModules...)
}
func GqlCall ¶ added in v0.13.0
func GqlCall[T any](ctx context.Context, callable ClientCallable, opType, opName string, args any, opts GqlOptions) (T, error)
GqlCall executes a GraphQL operation through callable. The query string is constructed from opName + args (inlined as JSON literals) + a selection set walked from T's exported struct fields. Returns the decoded data slot (or a typed error if the peer reported one).
Limitations of the v1 helper:
- Args are inlined into the query body; no $variables pass. Works fine with graphql-go's permissive scalar parsing for strings/ints/bools/maps; complex inputs may need manual escaping. This keeps the helper schema-free at the cost of parameter type-safety from the server's side.
- The selection set descends one struct level. Slices/pointers unwrap to their element. Scalars get no sub-selection.
- Output type T must be a struct or pointer-to-struct (or a slice thereof) — scalars at the top level don't carry a selection set in GraphQL.
For richer cases (variables, fragments, custom scalars) call into the peer's /graphql endpoint directly with your own request body.
func RegisterAutoClient ¶ added in v0.14.0
func RegisterAutoClient(fn any)
RegisterAutoClient stores a generated-client factory function so the framework can auto-Provide it at Run time. Generated client files (zz_*_client_gen.go) call this from their init() block; user code should not call it directly.
fn must be a function suitable for fx.Provide — typically `func(*nexus.App) SomeClient`. Passing a non-function will fail at fx.New time, not here, since the registry stays type-erased to keep init() ordering simple.
func RegisterCrossModuleDep ¶ added in v0.15.0
func RegisterCrossModuleDep(consumer, dep string)
RegisterCrossModuleDep records that a service field of type *<dep>.Service is referenced from <consumer>'s package (typically on the consumer's own Service struct). The build tool scans source statically and emits one call per detected dependency in zz_deploy_gen.go's init().
User code does not call this directly.
func RegisterModuleDeployment ¶ added in v0.14.1
func RegisterModuleDeployment(moduleName, tag string)
RegisterModuleDeployment associates a module name with a DeployAs tag. Called from a codegen'd init() block when the manifest declares this module under a split-unit deployment's owns list.
Re-registration replaces the previous mapping (last write wins), matching how SetDeploymentDefaults handles repeated calls.
func RegisterRemoteServicePlaceholder ¶ added in v0.14.8
func RegisterRemoteServicePlaceholder(name, tag string)
RegisterRemoteServicePlaceholder records a remote-module placeholder from a codegen'd init() block. Same pattern as RegisterAutoClient: the shadow generator's zz_shadow_gen.go emits one init() per non-owned module with a single call here, and the framework reconciles them with the *Registry at App construction time.
Why init() and not an fx.Invoke inside the shadow's nexus.Module: Module() in options.go runtime-filters modules whose DeployAs tag doesn't match NEXUS_DEPLOYMENT, dropping the whole option list (including any Invoke). init() runs at package load, before fx touches anything, so the registration always lands.
User code does not call this directly — codegen emits it.
func RoutePrefix ¶ added in v0.7.5
func RoutePrefix(p string) routePrefixOption
RoutePrefix prepends a string to the paths of the REST endpoints it applies to. Two usage patterns:
// Module-wide: every AsRest / AsRestHandler in the module sees "/api/v1".
nexus.Module("adverts", nexus.RoutePrefix("/api/v1"),
nexus.AsRest("GET", "/adverts", NewListAdverts), // → /api/v1/adverts
nexus.AsRest("POST", "/adverts", NewCreateAdvert),
)
// Per-endpoint:
nexus.AsRest("GET", "/health", NewHealth, nexus.RoutePrefix("/ops"))
The prefix is stored verbatim — include (or omit) the leading slash yourself; nexus does not normalize. Stacking within a single Module concatenates left-to-right, so `Module(..., RoutePrefix("/a"), RoutePrefix("/b"), AsRest("GET", "/x", ...))` mounts at /a/b/x. Prefixes do NOT stack across nested Module calls — the inner module already stamped its children before the outer sees them. If you need stacking, compose the prefix string explicitly.
func Run ¶ added in v0.3.0
Run builds and runs the app. Blocks until SIGINT/SIGTERM, then gracefully shuts the HTTP server + cron scheduler. Returns nothing — identical to fx.App.Run(). For tests where you need explicit Start/Stop control, build the app via a test helper that calls fxBootOptions.
func main() {
nexus.Run(
nexus.Config{Addr: ":8080", EnableDashboard: true},
nexus.Provide(NewDBManager),
advertsModule,
)
}
When NEXUS_FX_QUIET=1 is set in the environment, fx's startup log (PROVIDE/INVOKE/HOOK lines) is suppressed. The splitter sets this in subprocesses so the prefixed log streams don't drown in fx scaffolding noise; users hitting framework-level issues can unset it for full diagnostics.
func SetDeploymentDefaults ¶ added in v0.14.0
func SetDeploymentDefaults(d DeploymentDefaults)
SetDeploymentDefaults stores manifest-derived configuration that newApp consults when Config fields are zero. Called from a codegen'd init() block — user code should not call this directly.
Calling it twice replaces the previous defaults; the last write wins. That makes hot-restart in tests predictable.
func SetGraphStatus ¶ added in v0.20.0
SetGraphStatus overrides the HTTP status code for the current GraphQL request. Call from a graph.FieldMiddleware (the Graph realization of a middleware.Middleware bundle) or from a resolver to translate a decision into a non-200 response code:
authMw := middleware.Middleware{
Name: "auth",
Graph: func(p graphql.ResolveParams, next graphql.FieldResolveFn) (any, error) {
if !authed(p.Context) {
nexus.SetGraphStatus(p.Context, http.StatusUnauthorized)
return nil, errors.New("unauthorized")
}
return next(p)
},
}
Without this call the framework returns 200 OK with errors in the GraphQL response body — the GraphQL-spec default. When called multiple times within one request, the LAST value wins.
No-op when ctx didn't pass through the framework's GraphQL adapter — useful for resolver code under test with a bare graphql.Do call.
Re-export of gql.SetStatusCode so user code stays on the `nexus.` import without pulling in the transport package.
func WithCallerAuthorization ¶ added in v0.10.0
WithCallerAuthorization stamps the inbound Authorization header onto ctx so DefaultAuthPropagator can forward it. Called by the auth middleware on every authenticated request.
Generated client code never calls this directly — the auth surface in nexus.auth wires it for you. Exposed so custom middleware (or a non-auth.Module setup) can plug in.
func WithClientIP ¶ added in v0.3.0
WithClientIP is a thin pass-through to ratelimit.WithClientIP so nexus callers can thread IP into context without importing the lower-level ratelimit package. Kept here for API consistency with other nexus helpers.
func WithRouteKey ¶ added in v0.16.0
WithRouteKey decorates ctx with a routing key. When the call lands on a multi-replica RemoteCaller, the key is hashed to a stable replica index so calls with the same key land on the same replica. This is the load-bearing primitive for stateful workloads — WS hubs, per-user caches, idempotency stores — that need affinity across a split deployment.
Empty key is treated as no routing — falls back to round-robin.
Compose with the existing call site: a generated client method or hand-written caller wraps ctx before calling the RemoteCaller:
ctx = nexus.WithRouteKey(ctx, args.UserID) return client.Call(ctx, "POST", "/messages", args, &out)
When the chosen replica is currently ejected (recent failure), the caller falls back to round-robin so the call still has a chance to land — affinity is best-effort, not a hard guarantee.
Types ¶
type App ¶
type App struct {
// contains filtered or unexported fields
}
func New ¶
New constructs an *App from a single Config. The canonical (and, since v0.18, only) public constructor — both nexus.Run and the lower-level "build app, then app.Run(addr)" pattern feed through here.
Behavior:
- Manifest-derived defaults (codegen'd by `nexus build --deployment X`) fill any zero Config field; explicit Config fields always win.
- The framework owns engine creation, scope-filter middleware, /__nexus/health + /ready, the cache + ratelimit + metrics stores, and (when EnableDashboard is true) the dashboard mount.
- Listeners with empty Addrs auto-fill from the resolved Config.Addr (admin = port+1000, internal = port+2000).
- Global rate limit and global middlewares are installed at the engine root in registration order.
The returned *App is fully constructed and safe to register endpoints/services on, but listeners aren't bound until Run is invoked (either nexus.Run or App.Run for direct callers).
func (*App) Cron ¶ added in v0.3.0
func (a *App) Cron(name, schedule string) *CronBuilder
Cron starts building a scheduled job. Finalize with .Handler(fn). Jobs run bare — middleware chains do not apply — but the scheduler still emits request.start / request.end trace events so they appear on the dashboard Traces tab.
app.Cron("refresh-pets", "*/5 * * * *").
Describe("Warm the pet cache").
Handler(func(ctx context.Context) error { return nil })
func (*App) Deployment ¶ added in v0.9.0
Deployment is the deployment-unit name this binary boots as, or "" for monolith. Read by future cross-module clients to choose the in-process shortcut over HTTP.
func (*App) OnResourceUse ¶
func (a *App) OnResourceUse(target UseReporter)
OnResourceUse installs an auto-attach hook onto any UseReporter (typically a *multi.Registry or a user wrapper around one). Whenever code calls target.UsingCtx(ctx, "resource-name") during a request, the hook:
- reads the current trace.Span from ctx so we know which service made the call
- AttachResource(service, resource) on the registry — edge appears live
- emits a "downstream" trace event so the Traces tab shows the lookup
Calls with no span in context (e.g. UsingCtx fired from main or a cron job outside the trace middleware) are silently ignored — there's no service to attribute the usage to.
func (*App) Peer ¶ added in v0.14.0
Peer returns the topology binding for the given DeployAs tag. Generated remote clients call this at construction time to resolve the peer's URL/Timeout/Auth/MinVersion/Retries. The second return is false when the tag isn't declared in Config.Topology — codegen'd factories use that signal to fail fast with a precise error message.
func (*App) RateLimiter ¶ added in v0.3.0
func (*App) Register ¶
Register adds a resource (database, cache, queue) to the app so its health shows up on the dashboard. Use Service.Attach(r) to also draw an edge between the owning service(s) and the resource.
type AuthPropagator ¶ added in v0.10.0
AuthPropagator decides what (if any) caller identity to attach to a cross-module request. The default forwards the inbound Authorization header from ctx so user identity threads through the call chain without any handler-side wiring. Service-to-service calls that need a service token instead swap in a custom implementation.
func DefaultAuthPropagator ¶ added in v0.10.0
func DefaultAuthPropagator() AuthPropagator
DefaultAuthPropagator forwards the inbound Authorization header unchanged. Most apps want this — the JWT (or bearer token) the edge service authenticated against follows the request to peer services for free.
type AuthPropagatorFunc ¶ added in v0.10.0
AuthPropagatorFunc adapts a function to AuthPropagator. Useful for one-off custom propagators without a struct:
caller := nexus.NewRemoteCaller(url, nexus.WithAuthPropagator(
nexus.AuthPropagatorFunc(func(ctx context.Context, req *http.Request) error {
req.Header.Set("Authorization", "Bearer "+mintServiceToken())
return nil
}),
))
type CORSConfig ¶ added in v0.19.0
type CORSConfig struct {
// AllowOrigins lists allowed Origin header values verbatim.
// Use "*" for "any origin" — note that AllowCredentials cannot
// be true with "*" per the CORS spec; the middleware will
// downgrade to echoing the request's Origin in that case.
// Empty defaults to ["*"].
AllowOrigins []string
// AllowMethods lists HTTP methods allowed on cross-origin
// requests. Empty defaults to GET, POST, PUT, PATCH, DELETE,
// OPTIONS — covers every method nexus handlers register.
AllowMethods []string
// AllowHeaders lists request headers the browser is allowed to
// send. Empty defaults to Origin, Content-Type, Accept,
// Authorization, X-Requested-With.
AllowHeaders []string
// ExposeHeaders lists response headers the browser is allowed
// to read from JavaScript. Empty omits the header (browser
// only sees the safelisted response headers).
ExposeHeaders []string
// AllowCredentials sets Access-Control-Allow-Credentials: true
// when an origin matches. Required when the SPA sends cookies
// or Authorization headers cross-origin.
AllowCredentials bool
// MaxAge caches the preflight response for this duration.
// Zero defaults to 12 hours — enough to amortize the OPTIONS
// round-trip across a session, conservative enough that policy
// changes propagate within a workday.
MaxAge time.Duration
}
CORSConfig declares the framework's built-in CORS policy. All fields are optional; reasonable defaults fill in for the common "allow my SPA's origin to hit my API" case.
type ClientCallable ¶ added in v0.13.0
type ClientCallable interface {
Invoke(ctx context.Context, method, path string, body, out any) error
}
ClientCallable is the seam every generated cross-module client dispatches through. Both LocalInvoker (in-process via httptest) and RemoteCaller (HTTP) satisfy it, so the helpers below can build a single transport-agnostic call path. The codegen picks the concrete impl per-deployment in the constructor.
type Config ¶ added in v0.3.0
type Config struct {
// Server bundles every network-binding knob: the single-listener
// fallback Addr, and the explicit Listeners map for multi-scope
// deployments. Both fields are optional; the framework supplies a
// :8080 default when both are empty.
//
// nexus.Config{
// Server: nexus.ServerConfig{
// Listeners: map[string]nexus.Listener{
// "public": {Addr: ":8080"},
// "admin": {Addr: "127.0.0.1:7000", Scope: nexus.ScopeAdmin},
// },
// },
// }
Server ServerConfig
// Dashboard bundles the /__nexus surface knobs (whether it
// mounts at all, the brand label). Middleware that gates the
// dashboard lives under Middleware.Dashboard so all middleware
// configuration stays in one place.
//
// nexus.Config{
// Dashboard: nexus.DashboardConfig{Enabled: true, Name: "MyApp"},
// }
Dashboard DashboardConfig
// TraceCapacity is the ring-buffer size for request traces. 0 disables
// tracing — the Traces tab will stay empty.
TraceCapacity int
// GraphQL bundles every environment-level GraphQL knob that
// applies across all services' mounted schemas. Set once on the
// app, not per-service.
//
// nexus.Config{
// GraphQL: nexus.GraphQLConfig{
// Path: "/api/graphql",
// Pretty: true,
// },
// }
GraphQL GraphQLConfig
// Middleware bundles every middleware-related knob: engine-root
// stacks, dashboard gating, and the built-in global rate limit.
//
// nexus.Config{
// Middleware: nexus.MiddlewareConfig{
// Global: []middleware.Middleware{requestID, logger, cors},
// Dashboard: []middleware.Middleware{bearerAuth, requireAdminRole},
// RateLimit: ratelimit.Limit{RPM: 600, Burst: 50},
// },
// }
Middleware MiddlewareConfig
// Stores groups the framework's pluggable backends for state
// nexus needs to keep around — rate-limit counters, metrics
// rings, the general-purpose cache. All optional; the framework
// supplies sensible defaults (in-memory / cache-backed) when
// fields are zero. Set explicitly to swap in Redis-backed,
// Prometheus-backed, or other implementations.
//
// nexus.Config{
// Stores: nexus.StoreConfig{
// RateLimit: ratelimit.NewRedisStore(rdb),
// Cache: myCacheManager,
// },
// }
Stores StoreConfig
// Deployment names the deployment unit this binary runs as. Empty
// = monolith mode (every module is local — current behavior).
// When set, the framework knows which DeployAs-tagged modules are
// "local" vs "remote" so future codegen'd clients can pick the
// in-process or HTTP path accordingly. Today this field is
// metadata only — surfaced on /__nexus/config so the dashboard
// can render the active deployment.
//
// Convention: pass DeploymentFromEnv() in main() so a single
// binary can boot as different units across environments without
// recompiling.
Deployment string
// Version stamps the binary's version on /__nexus/config. Used by
// generated clients to detect peer-version skew across services
// in a split deployment ("service A is on v2, service B on v1"
// is the source of most weird microservice bugs). Defaults to
// "dev" when unset. Stamp via -ldflags at release:
//
// go build -ldflags "-X main.version=$GIT_SHA"
// nexus.Config{Version: version}
Version string
// Topology declares the peer table for split deployments — one
// entry per DeployAs tag the binary calls into. Codegen'd clients
// look up the active peer here at construction time instead of
// reading hard-coded env vars (USERS_SVC_URL, etc.), so peer URLs,
// timeouts, auth, and version floors live in one declarative place.
//
// Empty is the monolith default — every module is local, no peer
// lookups happen. When non-empty in split mode, the active
// Deployment must be a key in Peers (Run fails fast otherwise).
//
// nexus.Config{
// Deployment: "checkout-svc",
// Topology: nexus.Topology{
// Peers: map[string]nexus.Peer{
// "users-svc": {URL: os.Getenv("USERS_SVC_URL"), Timeout: 2 * time.Second},
// "checkout-svc": {},
// },
// },
// }
Topology Topology
}
Config drives how nexus.Run builds the app. Supply it as the first argument to nexus.Run; users never construct a *App directly when using the top-level builder.
type CronBuilder ¶ added in v0.3.0
type CronBuilder struct {
// contains filtered or unexported fields
}
CronBuilder accumulates optional metadata before Handler registers the job with the scheduler.
func (*CronBuilder) Describe ¶ added in v0.3.0
func (c *CronBuilder) Describe(desc string) *CronBuilder
Describe sets a human-readable description shown on the dashboard.
func (*CronBuilder) Handler ¶ added in v0.3.0
func (c *CronBuilder) Handler(fn func(ctx context.Context) error)
Handler finalizes the registration. A bad schedule is logged and the job is dropped; the app keeps running.
func (*CronBuilder) Service ¶ added in v0.3.0
func (c *CronBuilder) Service(name string) *CronBuilder
Service groups the cron under a service on the dashboard. Optional.
type DashboardConfig ¶ added in v0.19.0
type DashboardConfig struct {
// Enabled mounts /__nexus/* on the engine when true. Pulls in
// the Architecture / Endpoints / Crons / Rate-limits / Traces
// tabs and the JSON API the dashboard reads from.
Enabled bool
// Name is the brand shown in the dashboard header and the
// browser tab title. Defaults to "Nexus" when empty. Served
// over /__nexus/config so you can change it per-environment
// without rebuilding the UI.
Name string
}
DashboardConfig groups the /__nexus surface knobs. Both fields are optional: leave the struct zero-valued and the dashboard stays unmounted (default).
type DeploymentDefaults ¶ added in v0.14.0
type DeploymentDefaults struct {
// Addr is the listen address (e.g. ":8081") baked from the
// active deployment's manifest port. Empty when the manifest
// omits port — Config.Addr / nexus's :8080 default takes over.
Addr string
// Deployment names the active unit. When non-empty, the
// codegen'd init() set this from --deployment X so the binary
// runs with the right tag without needing NEXUS_DEPLOYMENT.
Deployment string
// Topology is the peer table built from the manifest's `peers:`
// block plus each peer deployment's port (so URLs default to
// http://localhost:<peer-port> for local dev).
Topology Topology
// Listeners is the manifest-derived listener map. When non-nil
// AND Config.Listeners is empty, newApp adopts this. Lets the
// operator declare scope shape in nexus.deploy.yaml ("admin"
// listener at port+1000, etc.) without main.go touching the
// listener struct.
Listeners map[string]Listener
}
DeploymentDefaults is the manifest-derived configuration applied when Config.Addr / Config.Topology / Config.Deployment / Config.Version are not set explicitly. `nexus build --deployment X` codegens a zz_deploy_gen.go file in the main package whose init() calls SetDeploymentDefaults — so the binary boots with the right port and peer table without main.go declaring anything.
Explicit Config fields always win. Defaults fill the gaps; this is the same precedence Go's flag package uses for -flag-from-env-var patterns and matches the user's intuition about "main.go is the override, manifest is the baseline."
func Defaults ¶ added in v0.16.0
func Defaults() (DeploymentDefaults, bool)
Defaults returns the manifest-derived configuration (the same data New consults to fill in zero-valued Config fields). Exposed so main.go can read the active deployment's port — useful when the caller wants to derive listener addresses from the manifest's port without parsing nexus.deploy.yaml itself.
Returns the zero DeploymentDefaults and false when no codegen'd init() has run (typical of `go run` against a deployment-agnostic monolith). Callers should fall back to their own defaults in that case rather than treating the empty Addr as authoritative.
type GqlField ¶ added in v0.3.0
type GqlField struct {
Kind graph.FieldKind
ServiceType reflect.Type
Service *Service // nil if dep[0] didn't unwrap (misuse)
Module string // nexus.Module name this field was declared under; "" if unscoped
// Deployment is the DeployAs tag of the enclosing module; "" when
// the module is always-local. Forwarded to the registry entry so
// dashboard consumers can group by deployment unit.
Deployment string
Field any // graph.QueryField or graph.MutationField
DepTypes []reflect.Type // for resource auto-attach
Deps []reflect.Value // for resource auto-attach (NexusResourceProvider)
// RateLimit is the baseline rate limit this op declared. Auto-mount
// publishes it to the registry so the dashboard can render it and
// — once operator overrides land — show the effective limit beside
// the declared one.
RateLimit *ratelimit.Limit
}
GqlField is the shared-group payload that AsQuery / AsMutation produce and fxmod's auto-mount Invoke consumes. Exported so consumers building their own mount logic can see what's in the graph, but most users never touch it.
type GqlOption ¶ added in v0.3.0
type GqlOption interface {
// contains filtered or unexported methods
}
GqlOption tunes a GraphQL registration. An interface (not a func type) so a single value — notably the nexus.Use cross-transport bundle — can satisfy both GqlOption and RestOption by implementing each's applyToX.
func Deprecated ¶ added in v0.3.0
Deprecated marks the field deprecated. The reason shows up in SDL and the dashboard "deprecated" badge.
func Desc ¶ added in v0.3.0
Desc sets the resolver's description (shown on the dashboard and in SDL documentation).
func GraphMiddleware ¶ added in v0.3.0
func GraphMiddleware(name, description string, mw graph.FieldMiddleware) GqlOption
GraphMiddleware attaches a named graph-only middleware to the resolver. Equivalent to go-graph's WithNamedMiddleware — the name appears in FieldInfo.Middlewares for dashboard rendering (and "auth", "cors", etc. get labelled "builtin" via nexus/middleware.Builtins).
For cross-transport middleware, prefer nexus.Use(middleware.Middleware{...}) — it accepts the same bundle on REST and GraphQL alike.
func Middleware
deprecated
added in
v0.3.0
func Middleware(name, description string, mw graph.FieldMiddleware) GqlOption
Middleware is a deprecated alias for GraphMiddleware. Exists so existing call sites keep compiling while codebases migrate to nexus.Use for cross-transport middleware.
Deprecated: use GraphMiddleware for graph-only middleware, or nexus.Use with a middleware.Middleware bundle for cross-transport.
func OnService ¶ added in v0.3.0
OnService routes this registration onto the given service wrapper type without requiring the handler to take it as a dep. Use when the handler is minimal (`func NewListQuestions(q *QuestionsDB) (...)`) but still belongs to a particular service on the dashboard.
nexus.AsQuery(NewListQuestions, nexus.OnService[*AdvertsService]())
The resolver still needs the owning service to have been provided into the fx graph elsewhere so MountGraphQL can pick up the field.
func RateLimit ¶ added in v0.3.0
RateLimit declares a baseline rate limit for this op. The auto-mount registers it with the app's rate-limit store and wires an enforcement middleware that consults the store on every request. Operators can override the effective limit live from the dashboard — the declared baseline stays in source-of-truth, the override survives in the store.
nexus.AsMutation(NewCreateAdvert,
nexus.RateLimit(ratelimit.Limit{RPM: 30, PerIP: true}),
)
Burst defaults to RPM/6 when zero (10-second burst window). Set PerIP to true to scope the bucket to the caller's IP; leave false for a shared global bucket.
type GqlOptions ¶ added in v0.13.0
type GqlOptions struct {
Path string // defaults to "/graphql"
}
GqlOptions tunes a GraphQL invocation. Currently only the mount path; reserved space for future knobs (per-call headers, custom operationName, persisted-query IDs).
type GraphQLConfig ¶ added in v0.19.0
type GraphQLConfig struct {
// Path overrides the default mount path for auto-generated
// GraphQL services. Empty falls back to DefaultGraphQLPath
// ("/graphql").
Path string
// DisablePlayground turns OFF the GraphQL Playground served on
// GET <service>/<path>. Default is enabled — flip in prod
// wiring to hide the interactive console.
DisablePlayground bool
// Debug skips query validation + response sanitization in
// go-graph. Dev-only. Default false.
Debug bool
// Pretty pretty-prints JSON responses. Convenient while
// exploring; ship off in prod.
Pretty bool
}
GraphQLConfig groups the framework's environment-level GraphQL knobs. Per-service paths via (*Service).AtGraphQL still win over these defaults — these only apply to services that don't carry an explicit AtGraphQL call.
type Listener ¶ added in v0.16.0
type Listener struct {
// Addr is the listen address (e.g. ":8080", "127.0.0.1:9000").
// Required — an empty Addr is rejected by Run with a precise
// error message.
Addr string
// Scope decides which routes this listener exposes. Zero value
// is ScopePublic — the conservative default for an exposed port.
Scope ListenerScope
}
Listener declares one bound address with a scope. Multiple listeners can share a scope (e.g. one bound to 0.0.0.0:8080 and another to a loopback for sidecar health checks).
type ListenerScope ¶ added in v0.16.0
type ListenerScope int
ListenerScope decides which routes a listener exposes. The framework uses the request's bound local address (via http.LocalAddrContextKey) to look up the scope and 404s requests to routes outside that scope.
The scope abstraction is opt-in: when Config.Listeners is empty, a single listener bound to Config.Addr serves every route (today's behavior). The scope filter only fires for explicitly-declared listeners.
const ( // ScopePublic exposes user-facing routes (REST, GraphQL, WebSocket) // and hides the /__nexus dashboard surface. The default for any // listener whose Scope is left zero — public is the safe default // for the listener bound to the world. ScopePublic ListenerScope = iota // ScopeInternal exposes user-facing routes plus /__nexus/health // and /__nexus/ready, so peer services can call your handlers and // orchestrators (k8s probes, load balancers) can poll readiness. // The rest of /__nexus stays hidden. ScopeInternal // ScopeAdmin exposes everything — /__nexus surface AND user // routes. The admin listener is meant for operators (typically // bound to a private subnet or behind an SSH tunnel), so giving // it the full route set is a UX win: the dashboard's in-page // RestTester / GraphQLTester make relative fetch() calls, and // blocking user routes here would silently 404 those. // // If you need a strictly-dashboard-only listener, that's a // future ScopeIntrospection — the current ScopeAdmin trades // surface area for ergonomics. ScopeAdmin )
func (ListenerScope) String ¶ added in v0.16.0
func (s ListenerScope) String() string
String returns the lowercase scope name. Dashboards and logs render scopes by name; keeping the mapping in one place makes additions future-safe.
type LocalInvoker ¶ added in v0.10.0
type LocalInvoker struct {
// contains filtered or unexported fields
}
LocalInvoker is the in-process variant of a generated cross-module client: instead of speaking HTTP to a peer service, it synthesizes an httptest.Recorder request and routes it directly through the same Gin engine that serves the real endpoints.
This costs ~10-20µs per call (request building + middleware chain) vs ~5ns for a direct function call, but buys behavior parity: auth, rate limits, metrics, and trace events all run identically to a real HTTP request. Monolith and split deployments produce the same dashboard signals — you can develop and debug the same way.
func NewLocalInvoker ¶ added in v0.10.0
func NewLocalInvoker(app *App, opts ...LocalInvokerOption) *LocalInvoker
NewLocalInvoker grabs the engine from the App. Generated client constructors call this when the target module's deployment matches the running binary's deployment (or both are blank — monolith mode).
func (*LocalInvoker) Invoke ¶ added in v0.10.0
func (li *LocalInvoker) Invoke(ctx context.Context, method, path string, args, out any) (rerr error)
Invoke runs args through the Gin engine as if it were a real HTTP request to (method, path), then decodes the response into out.
The body/query/path encoding rules match RemoteCaller exactly so a handler whose generated client targets either path produces the same wire shape — the framework guarantees parity.
Non-2xx responses become *RemoteError, same shape as the remote path; callers can type-assert and react identically.
type LocalInvokerOption ¶ added in v0.10.0
type LocalInvokerOption func(*LocalInvoker)
LocalInvokerOption tunes a LocalInvoker. Currently only auth propagation; kept as a functional option to leave room for future knobs (e.g. skip-middleware fast path) without changing the constructor signature.
func WithLocalAuthPropagator ¶ added in v0.10.0
func WithLocalAuthPropagator(p AuthPropagator) LocalInvokerOption
WithLocalAuthPropagator swaps the default auth propagator. Same reasoning as the remote variant: most apps forward the inbound Authorization header; service-token minters override.
type MiddlewareConfig ¶ added in v0.19.0
type MiddlewareConfig struct {
// Global stacks on the Gin engine root, so every REST endpoint,
// GraphQL POST, WebSocket upgrade, and dashboard request flows
// through it in registration order. Use for cross-cutting
// concerns (request-id, logger, CORS, auth pre-gate, etc.).
// Each bundle's Gin field runs; nil Gin realizations are
// skipped silently. Per-op middleware (via nexus.Use on a
// registration) layers on top.
Global []middleware.Middleware
// Dashboard gates the /__nexus surface behind user-supplied
// middleware — typically auth + permission checks. Each
// bundle's Gin realization runs in registration order on the
// /__nexus route group BEFORE any dashboard handler, covering
// the JSON API, WebSocket events, and the embedded Vue UI in
// one pass.
//
// Bundles whose Gin field is nil are ignored — the dashboard
// is an HTTP surface, so graph-only bundles don't apply.
Dashboard []middleware.Middleware
// RateLimit is the built-in app-wide rate limit. When set,
// installs as a gin middleware on the engine root so every
// HTTP path consults the bucket. Combine with per-op
// nexus.RateLimit() declarations for layered protection: the
// request must pass both the global bucket and the op's bucket.
// Zero disables.
RateLimit ratelimit.Limit
// CORS configures the built-in CORS middleware. Nil = no CORS
// handling (the framework installs nothing — same-origin
// browsers work, cross-origin requests are rejected by the
// browser). Set to a populated struct to allow cross-origin
// requests with the listed origins / methods / headers. The
// middleware lands on the engine root before any route, so
// REST + GraphQL + WebSocket upgrades all see it.
//
// For finer control (per-route CORS, dynamic origin checks),
// install your own gin middleware via Global instead.
CORS *CORSConfig
}
MiddlewareConfig groups every middleware-related knob the framework recognizes. All fields are optional — leave the struct zero-valued for "no extra middleware" and the framework runs with its built-in stack alone.
type MiddlewareOption ¶ added in v0.3.0
type MiddlewareOption struct {
// contains filtered or unexported fields
}
MiddlewareOption carries a Middleware across the AsRest/AsQuery/... call sites. Each transport's option type embeds / converts this, so a single nexus.Use(...) expression can appear wherever the transport accepts it.
func Use ¶ added in v0.3.0
func Use(m middleware.Middleware) MiddlewareOption
Use attaches a transport-agnostic middleware bundle to a registration. Works on AsRest, AsQuery, AsMutation, (future AsSubscription / AsWebSocket) — each transport picks the realization it understands from the bundle (Gin for REST/WS upgrade, Graph for GraphQL). Missing fields are silently ignored so a single bundle can degrade gracefully across transports.
rl := ratelimit.NewMiddleware(store, key, ratelimit.Limit{RPM: 30})
fx.Provide(
nexus.AsMutation(NewCreateAdvert, nexus.Use(rl)),
nexus.AsRest("POST", "/quick", NewQuick, nexus.Use(rl)),
)
For app-wide coverage (every REST endpoint + GraphQL POST + WS upgrade + the dashboard itself) put the middleware in Config.GlobalMiddleware instead of naming it on each registration.
type NexusResourceProvider ¶ added in v0.3.0
NexusResourceProvider is implemented by managers that know the external resources they front. A manager's NexusResources slice is used in two places:
- Boot-time registration via nexus.ProvideResources — each returned resource.Resource is added to the app registry so it appears on the dashboard with its health, description, and details.
- Service attachment via the GraphQL auto-mount — whenever a resolver names this manager as a dep, every resource in the slice gets linked to the owning service by name, drawing the architecture edge.
A manager may list more resources than any one handler uses; the edge is drawn per named resource on every service that mentions the manager.
func (m *DBManager) NexusResources() []resource.Resource {
var out []resource.Resource
m.Each(func(name string, db *DB) {
out = append(out, resource.NewDatabase(name, ...))
})
return out
}
type Option ¶
type Option interface {
// contains filtered or unexported methods
}
Option composes a nexus app. Everything returned by Provide, Supply, Invoke, Module, AsRest, AsQuery, AsMutation, AsWebSocket, AsSubscription is an Option, ready to pass to Run. fx is an implementation detail — user code imports only nexus.
func AsMutation ¶ added in v0.3.0
AsMutation is the mutation analogue of AsQuery.
func AsQuery ¶ added in v0.3.0
AsQuery registers a GraphQL query from a plain Go handler. The handler's signature is inspected reflectively:
- First param should be the service wrapper (e.g. *AdvertsService). Its type is used as the fx value-group key so MountGraphQL[*AdvertsService] picks up this query.
- Subsequent params are fx-injected deps.
- Optional last param is an args struct. Field tags drive arg config: graphql:"name" — arg name (defaults to lowercased field name) graphql:"name,required" — NonNull validate:"required" — graph.Required() validate:"len=3|120" — graph.StringLength(3, 120) validate:"int=1|100" — graph.Int(1, 100) validate:"oneof=a|b|c" — graph.OneOf("a","b","c") Chain multiple rules with commas.
- Return type must be (T, error). T is the resolver's return; pointer and slice wrappers are honored.
Op name defaults to the handler's func name, stripping a leading "New" and lowercasing the first rune ("NewGetAllAdverts" → "getAllAdverts"). Override with nexus.Op("explicit").
fx.Provide(
nexus.AsQuery(NewGetAllAdverts),
nexus.AsMutation(NewCreateAdvert,
nexus.Middleware("auth", "Bearer token", AuthMw)),
)
func AsRest ¶ added in v0.3.0
func AsRest(method, path string, fn any, opts ...RestOption) Option
AsRest registers a REST endpoint from a plain Go handler. The handler's signature is inspected via reflection:
- Leading params are fx-injected deps. The first such param should be your service wrapper (see docs on Service) — its type grounds the endpoint in a service node on the dashboard.
- The optional last param is an "args" struct whose tags direct gin on how to bind from the request: uri:"id" → ShouldBindUri query:"x" → ShouldBindQuery header:"x" → ShouldBindHeader form:"x" → ShouldBind (multipart/url-encoded) json:"x" → ShouldBindJSON (for non-GET; default when other binders are absent)
- The return may be (T, error), (T), (error), or nothing. T gets JSON-marshalled with status 200 (201 for POST) on success; errors become status 500 with {"error": "..."}.
Returns an fx.Option; drop it into fx.Provide.
fx.Provide(
nexus.AsRest("GET", "/pets", NewListPets),
nexus.AsRest("POST", "/pets", NewCreatePet),
nexus.AsRest("GET", "/pets/:id", NewGetPet),
)
func AsRestHandler ¶ added in v0.7.3
func AsRestHandler(method, path string, factory any, opts ...RestOption) Option
AsRestHandler registers a REST endpoint whose handler is a plain gin.HandlerFunc supplied by a *factory* function. The factory is the fx-resolved piece: its parameters are the deps needed to build the handler (controllers, resources, other services), its single return is the gin.HandlerFunc that serves requests.
Use this when the handler already manages its own request binding and response shaping (typical for code migrated from ad-hoc Gin routes) but you still want module annotation, metrics, and the dashboard packet-animation treatment AsRest provides:
nexus.Module("oats-rest",
nexus.AsRestHandler("POST", "/api/devices/register",
func(d *DeviceController) gin.HandlerFunc { return d.RegisterDevice },
nexus.Description("Register a device"),
auth.Required(),
),
)
Factory signature requirements:
- Zero or more parameters (fx-injected deps).
- Exactly one return value of type gin.HandlerFunc.
On the dashboard this endpoint appears under its enclosing nexus.Module (same grouping as AsRest / AsQuery), with metrics + trace middleware attached so request.op events drive the live packet animation.
func AsSubscription ¶ added in v0.3.0
AsSubscription is reserved for a follow-up: subscriptions use a separate builder (SubscriptionResolver[T] with PubSub + channel plumbing) that we haven't taught the reflective path yet. Use graph.NewSubscriptionResolver directly for now; once the reflective SubscriptionResolverFromType exists this helper will mirror AsQuery/AsMutation.
func AsWS ¶ added in v0.9.0
AsWS registers one message-type-scoped handler on a WebSocket endpoint. Multiple AsWS calls with the same path share a single connection pool — the framework dispatches inbound messages by their envelope `type` to the matching handler.
type ChatPayload struct{ Text string }
func NewChatSend(svc *ChatSvc, sess *nexus.WSSession,
p nexus.Params[ChatPayload]) error {
sess.EmitToRoom("chat.message",
map[string]string{"text": p.Args.Text, "user": sess.UserID()},
"lobby")
return nil
}
nexus.AsWS("/events", "chat.send", NewChatSend, auth.Required())
Wire protocol — every message is wrapped in the framework's envelope:
{ "type": "chat.send", "data": {...}, "timestamp": <unix> }
The built-in types `ping`, `authenticate`, `subscribe`, `unsubscribe` are handled by the hub directly and never reach user handlers.
Handler signature: same reflective convention as AsRest / AsQuery —
- fx-injected deps anywhere (service wrappers, resources, other services);
- an optional *nexus.WSSession parameter gets the live connection handle;
- an optional nexus.Params[T] carries the decoded message payload in Args;
- return (error) — a non-nil error is sent back on the same connection as an `error` envelope event. The connection stays open.
Middleware (auth.Required, rate limits, etc.) on the FIRST AsWS call for a path is installed on the HTTP upgrade route and gates every subsequent connection. Middleware declared on later AsWS calls for the same path is ignored with a warning log — all dispatches share one upgrade route.
func AsWorker ¶ added in v0.7.0
AsWorker registers a long-lived background worker. The framework owns lifecycle — it starts the worker on fx.Start in its own goroutine, cancels its context on fx.Stop, and records status + last-error on the registry so the dashboard can surface it.
Signature requirements:
First parameter MUST be context.Context. The framework supplies a context that cancels when the app stops; workers are expected to honor it and return.
Remaining parameters are fx-injected deps (same rules as a constructor — they must exist in the graph).
Return is optional: a single (error) return lets the worker report a fatal error. context.Canceled / nil is treated as a clean stop; anything else sets Status="failed" + LastError.
nexus.AsWorker("cache-invalidation", func(ctx context.Context, db *OatsDB, cache *CacheManager, logger *zap.Logger) error { for !db.IsConnected() { select { case <-ctx.Done(): return ctx.Err() case <-time.After(time.Second): } } listener := pq.NewListener(db.ConnectionString(), ...) defer listener.Close() _ = listener.Listen("cache_invalidation") for { select { case <-ctx.Done(): return nil case n := <-listener.Notify: handle(n, cache) } } })
Resource / service deps (for the architecture graph) are detected the same way nexus.ProvideService does it — any param implementing NexusResourceProvider contributes its resources, any param whose type is a service wrapper contributes a service dep.
A worker panic is caught and reported as Status=failed; the app keeps running. For restart semantics, wrap your worker body in a loop that re-dials on ctx.Done() exit OR let the operator restart the app.
func DeployAs ¶ added in v0.9.0
DeployAs records the deployment tag for the enclosing nexus.Module. Multiple DeployAs calls in one Module are not allowed — the last one wins, matching the way Module() handles duplicated RoutePrefix today.
func Invoke ¶ added in v0.3.0
Invoke runs a function at startup, resolving its parameters from the graph. Use for side-effects on boot — attaching resources, registering hooks, seeding state. Multiple Invoke options run in registration order.
nexus.Invoke(func(app *nexus.App, dbs *DBManager) {
app.OnResourceUse(dbs)
})
func Module ¶ added in v0.3.0
Module groups options under a name. Mirrors fx.Module's logging — the group name appears in startup/shutdown logs and in error messages, which helps when several modules touch the same service or resource. The name is also stamped onto every AsQuery/AsMutation/AsRest registration inside the module so the dashboard's architecture view can group endpoints by module container.
var advertsModule = nexus.Module("adverts",
nexus.Provide(NewAdvertsService),
nexus.AsQuery(NewGetAllAdverts),
nexus.AsMutation(NewCreateAdvert, …),
)
func Provide ¶ added in v0.3.0
Provide registers one or more constructor functions with the dep graph and auto-detects two opt-in extensions:
Resource providers: any returned value implementing NexusResourceProvider has its resource.Resource list registered with the app at boot. Add UseReporter alongside and OnResourceUse wires automatically — service→resource edges appear on first UsingCtx call without manual plumbing.
Service wrappers: when the first return is a *T whose struct anonymously embeds *nexus.Service, the constructor's params are scanned for resource providers and other service wrappers. The resulting (resourceDeps, serviceDeps) lists are recorded on the service's registry entry so the dashboard's architecture view draws service→service and service→resource edges at the SERVICE layer with no extra annotation.
Constructors that don't trigger either detector behave like plain fx.Provide — return types enter the graph, params resolve from it. Mixed sets (one service wrapper + one resource manager + one plain helper) work in a single call.
nexus.Provide(
NewDBManager, // resource provider — auto-registered
NewCacheManager, // ditto
NewAdvertsService, // service wrapper — deps recorded
NewClock, // plain type — just enters the graph
)
func Raw ¶ added in v0.3.0
Raw is an escape hatch: accept any fx.Option and route it through nexus. For features nexus hasn't mirrored yet (fx.Decorate, fx.Replace, named values via fx.Annotate with ParamTags, etc.) or one-off integrations. Normal apps never need it.
nexus.Raw(fx.Decorate(wrapLogger))
func Supply ¶ added in v0.3.0
Supply puts concrete values into the graph (no constructor). Useful for config structs or pre-built instances created outside the fx graph.
nexus.Supply(nexus.Config{Server: ServerConfig{Addr: ":8080"}}) // rare — Run takes Config directly
nexus.Supply(myAlreadyBuiltClient) // typical
type Params ¶ added in v0.3.0
Params is the bundle a reflective resolver receives when it wants more than just typed args — namely the resolve context, parent source, or schema info. Use it as the last parameter of an AsQuery / AsMutation handler (or AsRest, where only Context is filled).
func NewCreateAdvert(
svc *AdvertsService,
dbs *DBManager,
cache *CacheManager,
p nexus.Params[CreateAdvertArgs],
) (*AdvertResponse, error) {
advert := Advert{Title: p.Args.Title, EmployerName: p.Args.EmployerName}
return create(p.Context, advert)
}
The type parameter T is the args struct — its fields carry the same `graphql:"..."` and `validate:"..."` tags as the legacy flat-args form. Use Params[struct{}] for resolvers that need Context/Source/Info but have no user-supplied args.
For simple handlers that only need a context.Context, you can still take that as a plain parameter; Params[T] is additive, not required.
type Peer ¶ added in v0.14.0
type Peer struct {
// URLs is the replica list for this peer. The runtime round-
// robins across entries and passively ejects any replica that
// returns transport errors / 5xx for a cooldown window — single-
// replica peers just declare a one-element slice.
//
// "users-svc": {URLs: []string{
// "http://users-1.cluster.local:8080",
// "http://users-2.cluster.local:8080",
// "http://users-3.cluster.local:8080",
// }},
//
// Required when the active deployment is not this peer's tag;
// ignored for the active peer's own entry.
URLs []string
// Timeout caps each remote call. Zero falls back to the
// RemoteCaller default (30s). Recommended: set to your
// infrastructure-level timeout minus a small slack so client-side
// errors fire before any LB resets the connection.
Timeout time.Duration
// Auth is invoked once per remote call to produce an
// Authorization header value (e.g. "Bearer <token>"). Returning
// an error aborts the call. Nil disables explicit auth — the
// default forwarding propagator still threads the inbound
// Authorization header from the request context, so most
// edge-token flows work without setting this.
Auth func(ctx context.Context) (string, error)
// MinVersion is the lowest peer Version (read from the peer's
// /__nexus/config) accepted on the first call. When non-empty
// it replaces the local-binary version as the comparison floor
// in the existing skew-probe path. Empty disables the floor and
// falls back to comparing against the local binary's Version.
// Soft-fail: a mismatch logs a single warning line and the call
// proceeds, same as today's WithLocalVersion behavior.
MinVersion string
// Retries caps the number of automatic retries on transport
// errors (connection reset, timeout, DNS failure). Only
// idempotent verbs (GET, HEAD, PUT, DELETE, OPTIONS, TRACE)
// retry — POST and PATCH never do, regardless of this value.
// Zero disables retries entirely. Backoff between attempts is
// 50ms * 2^n with full jitter.
Retries int
}
Peer is the per-deployment binding consumed by codegen'd remote clients. Every field is optional — zero values map to the framework's default behavior for that knob.
type RemoteCaller ¶ added in v0.10.0
type RemoteCaller struct {
// contains filtered or unexported fields
}
RemoteCaller is the HTTP variant of a generated cross-module client. One per peer service: replicas hold one base URL each, the embedded http.Client is wrapped via trace.HTTPClient so traceparent is auto-injected on every call (request stitching across services is free).
Multi-replica behavior: when len(replicas) > 1, calls round-robin across replicas and passively eject any replica that returns a transport error or 5xx for a cooldown window. Idempotent verbs retry on a different replica when their first pick errors; non- idempotent verbs (POST, PATCH) still don't retry but the chosen replica is updated for the next caller.
Generated client code never constructs this directly — see NewRemoteCaller / NewRemoteCallerWithReplicas / NewPeerCaller.
func NewPeerCaller ¶ added in v0.14.0
func NewPeerCaller(peer Peer, opts ...RemoteCallerOption) *RemoteCaller
NewPeerCaller builds a RemoteCaller from a Topology Peer entry. Generated client constructors call this when the active deployment differs from the target module's tag.
Field mapping:
- peer.URLs → replica list (required; empty panics — codegen should resolve missing-peer cases before reaching this constructor)
- peer.Timeout → WithRemoteTimeout
- peer.Auth → wrapped as an AuthPropagator that sets the returned string on the Authorization header
- peer.MinVersion→ WithMinVersion (overrides localVersion as the skew-probe floor)
- peer.Retries → WithRetries (idempotent verbs only)
Additional opts run after the peer-derived options so callers can override on a per-client basis (e.g. WithLocalVersion to thread app.Version() in for the skew probe).
func NewRemoteCaller ¶ added in v0.10.0
func NewRemoteCaller(baseURL string, opts ...RemoteCallerOption) *RemoteCaller
NewRemoteCaller wraps a single base URL — sugar for the single- replica case. Equivalent to NewRemoteCallerWithReplicas with a one-element slice. Trailing slashes are trimmed so callers don't double-slash when handler paths begin with "/".
func NewRemoteCallerWithReplicas ¶ added in v0.16.0
func NewRemoteCallerWithReplicas(urls []string, opts ...RemoteCallerOption) *RemoteCaller
NewRemoteCallerWithReplicas wraps multiple replica base URLs with round-robin balancing and passive ejection. Calls pick the next replica in cursor order; transport errors and 5xx responses mark the replica ejected for the eject duration (30s default), so the next caller skips it.
At least one URL is required — zero URLs is a programming error, not a runtime case, and panics here so codegen surfaces the bug at boot rather than on the first cross-module call.
func (*RemoteCaller) Call ¶ added in v0.10.0
Call serializes args into the appropriate place (path, body, query), dispatches the request, and decodes the JSON response into out. Pointer-to-pointer is fine — ListUsers returns *[]*User, so callers pass &out where out is *[]*User.
Non-2xx responses become *RemoteError with the status code and the server's response body (best-effort JSON-decoded into the .Body field). 5xx errors are still considered "the call returned" — they don't trigger retries here; the caller decides.
First-call side effect: if WithLocalVersion was set, the caller fetches the peer's /__nexus/config once and logs a single warning line on version skew. The probe never fails the user's call — errors fetching config are swallowed so an unrelated transient on the peer doesn't masquerade as the caller's request failing.
func (*RemoteCaller) Invoke ¶ added in v0.13.0
Invoke is an alias for Call exposed so RemoteCaller satisfies the same ClientCallable interface as LocalInvoker. New code should prefer Invoke for shape consistency across the in-process and HTTP paths; Call stays for backward compatibility with already-generated client files.
type RemoteCallerOption ¶ added in v0.10.0
type RemoteCallerOption func(*RemoteCaller)
RemoteCallerOption tunes a RemoteCaller. Functional-option pattern matches AppOption — keeps the constructor signature stable as new knobs land.
func WithAuthPropagator ¶ added in v0.10.0
func WithAuthPropagator(p AuthPropagator) RemoteCallerOption
WithAuthPropagator swaps the default Authorization-forwarding propagator for a service-token minter or any other custom strategy.
func WithEjectDuration ¶ added in v0.16.0
func WithEjectDuration(d time.Duration) RemoteCallerOption
WithEjectDuration overrides how long a replica stays ejected after a transport error or 5xx. Defaults to 30s. Tests use shorter values to exercise re-add behavior in seconds; production rarely needs to tune this — the default is conservative enough for typical pod restart times.
func WithLocalVersion ¶ added in v0.12.0
func WithLocalVersion(v string) RemoteCallerOption
WithLocalVersion stamps the caller's own version onto the RemoteCaller so it can detect peer-version skew on the first HTTP call. Generated client constructors thread app.Version() in here so deployments where service A is on v2 and service B on v1 surface a single warning line instead of being a silent source of "weird microservice bugs."
Empty version disables the probe (a binary without a stamped version can't meaningfully claim drift).
func WithMinVersion ¶ added in v0.14.0
func WithMinVersion(v string) RemoteCallerOption
WithMinVersion sets a comparison floor for the peer-version skew probe that's independent of the local binary's stamped version. When set, the probe compares the peer's reported Version against this value instead of localVersion. Soft-fail same as today — mismatch logs a single warning, the call proceeds.
func WithRemoteHTTPClient ¶ added in v0.10.0
func WithRemoteHTTPClient(c *http.Client) RemoteCallerOption
WithRemoteHTTPClient swaps the default http.Client. Callers that already wrap their own client in trace.HTTPClient (for custom transports, retries, mTLS) pass it through here. Note: nexus does not re-wrap — if you opt out of trace.HTTPClient you opt out of automatic traceparent injection.
func WithRemoteTimeout ¶ added in v0.14.0
func WithRemoteTimeout(d time.Duration) RemoteCallerOption
WithRemoteTimeout overrides the default 30s per-call timeout on the underlying http.Client. NewPeerCaller threads Peer.Timeout through here when non-zero. Setting to zero leaves the existing timeout in place — use a custom http.Client via WithRemoteHTTPClient if you genuinely want to remove timeouts.
func WithRetries ¶ added in v0.14.0
func WithRetries(n int) RemoteCallerOption
WithRetries caps automatic retries on transport errors. Only idempotent HTTP verbs (GET/HEAD/PUT/DELETE/OPTIONS/TRACE) retry — POST and PATCH never do. Backoff between attempts is 50ms * 2^n with full jitter. Zero disables retries entirely.
type RemoteError ¶ added in v0.10.0
type RemoteError struct {
Status int // HTTP status code from the peer
Method string // request method
TargetPath string // logical path before substitution (the AsRest path)
TargetURL string // the full URL we hit (for log debugging)
Message string // best-effort extracted from the body
RawBody []byte // raw response body when JSON decode didn't yield Message
}
RemoteError is what a non-2xx peer response unmarshals to. Generated clients return it through the function's `error` slot so callers can type-assert and react on Status without parsing strings.
func (*RemoteError) Error ¶ added in v0.10.0
func (e *RemoteError) Error() string
type RestOption ¶ added in v0.3.0
type RestOption interface {
// contains filtered or unexported methods
}
RestOption tunes an AsRest registration. Interface (not a func) so nexus.Use can satisfy both GqlOption and RestOption from a single value. The one-off func-shaped helpers below adapt via restOptionFn.
func Description ¶ added in v0.3.0
func Description(s string) RestOption
Description sets the human-readable description shown on the dashboard.
type ServerConfig ¶ added in v0.19.0
type ServerConfig struct {
// Addr is the HTTP listen address used in single-listener
// mode (default ":8080"). Ignored when Listeners is non-empty.
// Manifest-driven defaults via DeploymentDefaults.Addr fill
// this when zero, so split binaries each pick up their own
// per-deployment port.
Addr string
// Listeners declares one or more named listeners with explicit
// scopes. Empty Addrs auto-fill from the resolved Addr above
// (admin = port+1000, internal = port+2000); explicit Addrs
// are passed through unchanged.
Listeners map[string]Listener
}
ServerConfig groups the network-binding knobs. Addr is the single-listener fallback (used when Listeners is empty); Listeners declares one or more named listeners with explicit scopes. Both optional — leaving both zero binds a single listener at :8080 with ScopePublic.
When Listeners is set, Addr is ignored and every declared listener binds. The framework installs a scope-filter middleware that 404s out-of-scope routes per listener (e.g. requests to /__nexus/* on the public listener).
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service is a named group of endpoints. Services are the nodes the dashboard draws in the architecture view.
A Service also carries the GraphQL mount path for reflective controllers registered via nexus.AsQuery / AsMutation. The auto-mount step inside fxmod.Module reads this path at fx.Start and wires the schema onto the engine. Default is "/graphql"; override via (*Service).AtGraphQL.
func (*Service) AtGraphQL ¶ added in v0.3.0
AtGraphQL overrides the GraphQL mount path for this service. Most apps keep the default ("/graphql") — override only when you need a per-service path (e.g. "/admin/graphql") or want to unify multiple nexus apps behind the same reverse proxy.
app.Service("admin").AtGraphQL("/admin/graphql").Describe("Admin ops")
func (*Service) Attach ¶
Attach links a resource to this service so the dashboard draws an edge. If the resource isn't already registered, Attach registers it too — that's convenient for ad-hoc services but means typos silently create orphan nodes. For centrally-declared resources, prefer .Using("name") instead.
func (*Service) Auth ¶ added in v0.3.0
func (s *Service) Auth(fn UserDetailsFn) *Service
Auth wires a Bearer-token → user hook. Resolvers read the user via graph.GetRootInfo(p, "details", &user) after successful authentication. Per-service because different services often use different auth mechanisms (admin vs public).
func (*Service) GraphQLPath ¶ added in v0.3.0
GraphQLPath returns the mount path set via AtGraphQL (or the default). Read by the auto-mount Invoke; users rarely need this.
func (*Service) MountGraphQL ¶
MountGraphQL attaches schema (assembled by go-graph or graphql-go) and auto-registers every operation into the nexus registry. Pass gql.With* options for auth (UserDetailsFn), Playground, Pretty, and DEBUG.
func (*Service) Name ¶ added in v0.3.0
Name returns the service's identifier (same string used on the dashboard and passed to *App.Service). Exposed so framework internals (the auto- mount Invoke, service wrappers) can identify a service without reaching into the private field.
func (*Service) Using ¶
Using attaches already-registered resources by name so the dashboard draws edges. An empty string resolves to the default database (the resource of kind Database marked resource.AsDefault(), or the lexically-first if none is marked). Unknown names are attached anyway so the registry shows a disconnected edge — surfacing the typo rather than hiding it.
app.Service("adverts").Using("").MountGraphQL(...) // default DB
app.Service("qb").Using("questions", "session").MountGraphQL(...) // explicit
func (*Service) UsingDefaults ¶
UsingDefaults attaches the default resource of every kind that has at least one registered (database, cache, queue). Useful for services that touch the common "main DB + session cache" pair without naming either.
type StoreConfig ¶ added in v0.19.0
type StoreConfig struct {
// RateLimit replaces the default in-memory rate-limit store.
// Set when you want to share the store between the app and
// externally-built middleware bundles (ratelimit.NewMiddleware
// consumes a Store), or for persistence / multi-replica via a
// Redis-backed implementation. Nil → app builds its own
// MemoryStore (or cache-backed when Cache is set).
RateLimit ratelimit.Store
// Metrics replaces the default cache-backed metrics store. Use
// for Prometheus / StatsD / OTel-backed implementations. The
// dashboard's /__nexus/stats endpoint reads from whichever
// Store is installed.
Metrics metrics.Store
// Cache is the framework's general-purpose cache.Manager. When
// set, nexus uses it as the default backing for the metrics +
// rate-limit stores (so counters and overrides benefit from
// the app's cache tier). Pass your own when user code already
// runs a cache.Manager — framework + app share one tier.
//
// Explicit RateLimit / Metrics settings still win; Cache is
// just the default when those are nil.
Cache *cache.Manager
}
StoreConfig groups the framework's pluggable backends. All fields are optional — leave them nil and the framework supplies in- memory / cache-backed defaults. Set explicitly to share state across replicas, push to a monitoring stack, or hand the framework an existing cache tier.
type Topology ¶ added in v0.14.0
type Topology struct {
// Peers is keyed by DeployAs tag. The active deployment's own
// entry is permitted (URL is ignored for the active unit since
// it's never called over HTTP from itself); a placeholder entry
// keeps the map a complete inventory of every unit in the
// deployment, which is convenient for dashboards and validation.
Peers map[string]Peer
}
Topology is the peer table for cross-module HTTP calls in a split deployment. Each entry names a deployment unit (matching a DeployAs tag) and binds the transport details for reaching it.
type UseReporter ¶
UseReporter is satisfied by any type that exposes an OnUse hook with this exact signature. multi.Registry and anything embedding it fit — including the project's own DBManager wrapper. This is a structural interface so nexus doesn't need to import nexus/multi directly.
type UserDetailsFn ¶ added in v0.3.0
UserDetailsFn, when set on a service, routes GraphQL requests through graph.NewHTTP so resolvers can read the authenticated user via graph.GetRootInfo(p, "details", &user). Returning an error aborts the request with the framework's standard unauthenticated shape.
type UserError ¶ added in v0.14.0
type UserError struct {
Op string // short verb-noun: "topology", "remote call", "path expand"
Msg string // primary one-line description
Notes []string // optional context lines (peer list, body snippet, etc.)
Hint string // optional fix recipe; single line
Cause error // optional wrap — accessible via errors.Unwrap
}
UserError is the framework's developer-facing error envelope. Fields produce a multi-line format with an optional `hint:` recipe and an optional `cause:` wrap so a developer hitting a framework error sees what went wrong, what to do about it, and the underlying cause in one block — instead of having to chase the message through several fmt.Errorf wraps.
nexus error [topology]: Deployment "users-svc" not in Topology.Peers declared peers: [checkout-svc orders-svc] hint: add Topology.Peers["users-svc"] in main.go's nexus.Config — URL may be empty for the active unit
User code typically doesn't construct these — the framework emits them at known failure boundaries. They behave like normal errors (Error / Unwrap), so existing error-handling paths work unchanged.
type WSOption ¶ added in v0.9.0
type WSOption interface {
// contains filtered or unexported methods
}
WSOption tunes an AsWS registration. Interface (not a func) so nexus.Use and auth.Required() — which return middleware bundles — can satisfy both RestOption and WSOption from a single value.
type WSSession ¶ added in v0.9.0
type WSSession struct {
// contains filtered or unexported fields
}
WSSession is the per-connection handle injected into AsWS handlers. Every handler that declares `*nexus.WSSession` as a parameter receives the session tied to the connection that produced the current inbound message. Safe for concurrent use — wraps a ws.Hub under the hood.
The framework uses the same envelope protocol as the built-in ws.Hub:
{ "type": "chat.send", "data": {...}, "timestamp": <unix> }
Emit / EmitToUser / EmitToRoom / EmitToClient publish in that shape; SendRaw is the escape hatch for non-envelope payloads.
func (*WSSession) ClientID ¶ added in v0.9.0
ClientID is the UUID the hub minted for this connection at upgrade time.
func (*WSSession) Context ¶ added in v0.9.0
Context returns a context cancelled when the connection disconnects. Safe to pass downstream — long-running work will unblock on hangup.
func (*WSSession) Emit ¶ added in v0.9.0
Emit broadcasts an envelope to every connection on this endpoint.
func (*WSSession) EmitToClient ¶ added in v0.9.0
EmitToClient sends an envelope to the connections with the given IDs.
func (*WSSession) EmitToRoom ¶ added in v0.9.0
EmitToRoom sends an envelope to every connection subscribed to room.
func (*WSSession) EmitToUser ¶ added in v0.9.0
EmitToUser sends an envelope to every connection authed as one of userIDs.
func (*WSSession) JoinRoom ¶ added in v0.9.0
JoinRoom subscribes this connection to a room. Matching server-side helper for the client's `{"type":"subscribe","room":"..."}` message.
func (*WSSession) Metadata ¶ added in v0.9.0
Metadata is the map the hub's identify hook populated at upgrade time. Read freely; mutation is not safe across goroutines.
func (*WSSession) Send ¶ added in v0.9.0
Send wraps data in an envelope and unicasts it to this connection.
Source Files
¶
- as_graph.go
- as_rest.go
- as_ws.go
- auto_client.go
- automount.go
- client_auth.go
- client_gql.go
- client_helpers.go
- client_local.go
- client_peer.go
- client_remote.go
- config.go
- cors.go
- cron_builder.go
- deploy.go
- deploy_defaults.go
- endpoint_chain.go
- endpoint_config.go
- graph_status.go
- health.go
- integration.go
- listeners.go
- module_deployment.go
- nexus.go
- options.go
- params.go
- reflect.go
- reflect_runtime.go
- remote_service.go
- routing.go
- service.go
- use.go
- usererror.go
- websocket.go
- workers.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package auth is nexus's built-in authentication surface.
|
Package auth is nexus's built-in authentication surface. |
|
Package cache provides a Redis + in-memory hybrid cache for nexus apps, ported from the oats_applicant implementation.
|
Package cache provides a Redis + in-memory hybrid cache for nexus apps, ported from the oats_applicant implementation. |
|
cmd
|
|
|
nexus
command
Command nexus is the developer CLI for the nexus framework.
|
Command nexus is the developer CLI for the nexus framework. |
|
Package cron registers and runs scheduled jobs alongside the app's HTTP surface.
|
Package cron registers and runs scheduled jobs alongside the app's HTTP surface. |
|
Package dashboard mounts the nexus introspection surface under /__nexus.
|
Package dashboard mounts the nexus introspection surface under /__nexus. |
|
Package db is nexus's driver-agnostic GORM manager.
|
Package db is nexus's driver-agnostic GORM manager. |
|
examples
|
|
|
fxapp
command
An example showing nexus's top-level builder: nexus.Run composes modules, nexus.Provide / Invoke / Module replace fx.Provide / Invoke / Module — no go.uber.org/fx import in user code.
|
An example showing nexus's top-level builder: nexus.Run composes modules, nexus.Provide / Invoke / Module replace fx.Provide / Invoke / Module — no go.uber.org/fx import in user code. |
|
graphapp
command
Example: a complete GraphQL service wired with nexus's reflective controller API.
|
Example: a complete GraphQL service wired with nexus's reflective controller API. |
|
microsplit
command
Command microsplit is the runnable demo for the deployable-modules preview.
|
Command microsplit is the runnable demo for the deployable-modules preview. |
|
microsplit/checkout
Package checkout demonstrates a module that *consumes* another module by importing its *Service directly.
|
Package checkout demonstrates a module that *consumes* another module by importing its *Service directly. |
|
microsplit/users
Package users is the canonical "owns its data, exposes typed REST" module: a minimal user catalog tagged DeployAs("users-svc") so it can be peeled out into its own binary later.
|
Package users is the canonical "owns its data, exposes typed REST" module: a minimal user catalog tagged DeployAs("users-svc") so it can be peeled out into its own binary later. |
|
petstore
command
|
|
|
wsecho
command
Command wsecho is a runnable demo of nexus.AsWS: one WebSocket path (/events) with two typed message handlers (chat.send + chat.typing) sharing one connection pool.
|
Command wsecho is a runnable demo of nexus.AsWS: one WebSocket path (/events) with two typed message handlers (chat.send + chat.typing) sharing one connection pool. |
|
wstest
command
|
|
|
Package graph provides a modern, secure GraphQL handler for Go with built-in authentication, validation, and an intuitive builder API.
|
Package graph provides a modern, secure GraphQL handler for Go with built-in authentication, validation, and an intuitive builder API. |
|
Package metrics records per-endpoint request counts + errors so the dashboard can show at-a-glance health next to each op: how busy it is, whether it's failing, and if so, what the last error was.
|
Package metrics records per-endpoint request counts + errors so the dashboard can show at-a-glance health next to each op: how busy it is, whether it's failing, and if so, what the last error was. |
|
Package middleware defines nexus's cross-transport middleware model.
|
Package middleware defines nexus's cross-transport middleware model. |
|
Package multi routes N named instances of the same type behind a single .Using(name) dispatcher.
|
Package multi routes N named instances of the same type behind a single .Using(name) dispatcher. |
|
Package ratelimit provides the rate-limit primitives nexus uses to throttle endpoints: a Limit shape, a Store interface (pluggable to memory, Redis, or any backend), and a token-bucket MemoryStore.
|
Package ratelimit provides the rate-limit primitives nexus uses to throttle endpoints: a Limit shape, a Store interface (pluggable to memory, Redis, or any backend), and a token-bucket MemoryStore. |
|
Package registry stores metadata about every endpoint a nexus app exposes.
|
Package registry stores metadata about every endpoint a nexus app exposes. |
|
Package resource defines the abstractions nexus uses to know about databases, caches, message queues, and other external dependencies so they show up in the dashboard's Architecture view with health status.
|
Package resource defines the abstractions nexus uses to know about databases, caches, message queues, and other external dependencies so they show up in the dashboard's Architecture view with health status. |
|
Package trace captures request-lifecycle events (start, end, downstream calls, logs) into an in-memory ring buffer and fans them out to subscribers such as the dashboard.
|
Package trace captures request-lifecycle events (start, end, downstream calls, logs) into an in-memory ring buffer and fans them out to subscribers such as the dashboard. |
|
transport
|
|
|
gql
Package gql mounts a GraphQL schema (typically assembled by github.com/paulmanoni/nexus/graph) onto Gin and introspects its operations into the nexus registry.
|
Package gql mounts a GraphQL schema (typically assembled by github.com/paulmanoni/nexus/graph) onto Gin and introspects its operations into the nexus registry. |
|
rest
Package rest wires REST endpoints onto a Gin engine and records metadata about them in the nexus registry.
|
Package rest wires REST endpoints onto a Gin engine and records metadata about them in the nexus registry. |
|
ws
Package ws wires WebSocket endpoints onto a Gin engine using gorilla/websocket and records metadata about them in the nexus registry.
|
Package ws wires WebSocket endpoints onto a Gin engine using gorilla/websocket and records metadata about them in the nexus registry. |

