nexus

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Apr 22, 2026 License: MIT Imports: 11 Imported by: 0

README

nexus

A thin Go framework over Gin that registers every endpoint — REST, GraphQL, WebSocket — into a central registry, traces each request through an in-memory event bus, and exposes the lot at /__nexus for a Vue dashboard that renders live service topology, endpoint catalog, and request traces.

nexus does not replace your GraphQL layer. Hand it a *graphql.Schema (typically assembled with go-graph) and it mounts, introspects, and surfaces every field.

What you get

  • Unified endpoint registry — REST, GraphQL, and WebSocket handlers registered through one API land on a single dashboard.
  • Live architecture view — services, resources (DBs, caches, queues), and the edges between them, drawn with Vue Flow.
  • Request traces — bounded ring buffer with pub/sub over a WebSocket. Slow UIs drop events rather than block the request path.
  • Resource health — register databases/caches/queues once; their status bubbles up to the dashboard and is referenced by services via .Using("name").
  • Multi-instance dispatch — the multi package routes N named instances of any type (e.g. multiple *gorm.DB) behind a single .Using(name) call, with optional hooks so nexus can auto-draw service→resource edges as lookups happen.
  • GraphQL introspection — via graphfx, resolvers built with go-graph expose return type, per-arg validators and defaults, middleware chains, and deprecation info to the registry without extra declarations.
  • fx integrationfxmod and graphfx slot into go.uber.org/fx graphs; lifecycle and shutdown are handled for you.

Install

go get nexus

Requires Go 1.25+.

Quick start

package main

import (
    "net/http"

    "github.com/gin-gonic/gin"
    "nexus"
)

func main() {
    app := nexus.New(
        nexus.WithTracing(1000),
        nexus.WithDashboard(),
        nexus.WithDashboardName("Petstore"),
    )

    pets := app.Service("pets").Describe("Pet inventory")

    pets.REST("GET", "/pets").
        Describe("List all pets").
        Handler(func(c *gin.Context) {
            c.JSON(http.StatusOK, gin.H{"pets": []string{"Rex", "Whiskers"}})
        })

    _ = app.Run(":8080")
}

Open http://localhost:8080/__nexus/ for the dashboard.

Core concepts

App

Built via nexus.New(opts...). Options:

Option Purpose
WithEngine(*gin.Engine) Supply a pre-configured Gin engine (otherwise a bare engine with Recovery is created).
WithTracing(capacity int) Enable per-request trace events in a ring buffer of capacity events.
WithDashboard() Mount /__nexus/* (endpoints, resources, events, embedded UI).
WithDashboardName(string) Brand shown in the dashboard header and tab title.
Service

A named group of endpoints — one node in the architecture graph.

pets := app.Service("pets").Describe("Pet inventory")

pets.REST("GET", "/pets").Describe("List").Handler(handler)
pets.WebSocket("/pets/stream").OnMessage(echoHandler).Mount()
pets.MountGraphQL("/graphql", schema)
Resource

Register any dependency whose health the dashboard should surface:

mainDB := resource.NewDatabase("main-db", "Primary Postgres",
    map[string]any{"engine": "postgres"},
    dbm.IsConnected,
    resource.AsDefault(),
)
app.Register(mainDB)

app.Service("pets").Using("main-db")          // explicit
app.Service("owners").Using("")               // default DB
app.Service("graph").UsingDefaults()          // default of every kind

Kinds: KindDatabase, KindCache, KindQueue, KindOther.

Tracing

WithTracing(n) installs a pub/sub ring buffer (trace.Bus) that the dashboard streams from over /__nexus/events. Handlers record child spans with:

start := time.Now()
// ... do work ...
trace.Record(c, "db.pets.list", start, nil)
multi — named instances
dbs := multi.New[*gorm.DB]().
    Register("main", mainDB, multi.AsDefault()).
    Register("questions", qbDB).
    Register("uaa", uaaDB)

dbs.Using("main").Find(&rows)
dbs.UsingCtx(ctx, "questions").Find(&rows)   // fires hooks; nexus draws edges

Install the auto-attach hook so resource edges appear as lookups fire inside a request:

app.OnResourceUse(dbs)

fx integration

fx.New(
    fx.Supply(fxmod.Config{
        Addr:            ":8080",
        DashboardName:   "Fx Petstore",
        TraceCapacity:   1000,
        EnableDashboard: true,
    }),
    fxmod.Module,
    petsModule,
    ownersModule,
).Run()

See examples/fxapp for a multi-domain setup.

GraphQL with graphfx + go-graph

fx.New(
    fxmod.Module,
    graphfx.Module,
    fx.Provide(
        graphfx.AsQuery(NewGetAllAdverts),
        graphfx.AsMutation(NewCreateAdvert),
    ),
    graphfx.ServeAt("adverts", "/graphql",
        graphfx.Describe("Job adverts catalog"),
        graphfx.UseDefaults(),
    ),
)

graphfx introspects every mounted resolver and enriches the registry with return type, per-arg Required/default/validator metadata, named middleware chains, and deprecation reasons — all of which the dashboard renders automatically.

See examples/graphapp for a full GraphQL service wired to two named databases and a cache.

Dashboard

Mounted at /__nexus when WithDashboard() is set:

Route Description
GET /__nexus/ Embedded Vue dashboard (Architecture, Endpoints, Traces tabs)
GET /__nexus/config Dashboard config (name, etc.)
GET /__nexus/endpoints Services + endpoints from the registry
GET /__nexus/resources Registered resources and health
GET /__nexus/middlewares Declared middleware names
GET /__nexus/events WebSocket stream of trace events (with ?since=N for backlog)
Developing the UI
cd dashboard/ui
npm install
npm run dev       # Vite dev server
npm run build     # writes dist/ which is embedded into Go binaries

Examples

Path What it shows
examples/petstore Minimal REST + WebSocket app with tracing and dashboard.
examples/fxapp fx-driven multi-domain app with resources.
examples/graphapp Full GraphQL service via graphfx + go-graph + multiple named DBs.
examples/wstest WebSocket echo playground.

Run any example with e.g. go run ./examples/graphapp.

Package layout

nexus/              top-level App, Service, options
├── registry/       metadata store — services, endpoints, resources, middleware
├── resource/       database / cache / queue abstractions
├── trace/          ring-buffer event bus + middleware
├── transport/
│   ├── rest/       REST builder
│   ├── gql/        GraphQL adapter (registers fields into the registry)
│   └── ws/         WebSocket builder
├── dashboard/      /__nexus HTTP surface + embedded Vue UI
├── middleware/     shared middleware descriptors
├── multi/          N named instances behind .Using(name)
├── fxmod/          go.uber.org/fx integration for *nexus.App
├── graphfx/        go.uber.org/fx integration for go-graph schemas
├── db/             opinionated GORM helpers
└── examples/       runnable demos

License

MIT

Documentation

Overview

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/go-graph) and it mounts + introspects.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type App

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

func New

func New(opts ...Option) *App

func (*App) Bus

func (a *App) Bus() *trace.Bus

func (*App) Engine

func (a *App) Engine() *gin.Engine

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:

  1. reads the current trace.Span from ctx so we know which service made the call
  2. AttachResource(service, resource) on the registry — edge appears live
  3. 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) Register

func (a *App) Register(r resource.Resource)

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.

func (*App) Registry

func (a *App) Registry() *registry.Registry

func (*App) Run

func (a *App) Run(addr string) error

func (*App) ServeHTTP

func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request)

func (*App) Service

func (a *App) Service(name string) *Service

type Option

type Option func(*App)

func WithDashboard

func WithDashboard() Option

WithDashboard mounts /__nexus/endpoints (always) and /__nexus/events (if tracing is on).

func WithDashboardName

func WithDashboardName(name string) Option

WithDashboardName sets the brand shown in the dashboard header and the browser tab title. Defaults to "Nexus". The name is served over /__nexus/config so the client picks it up without a rebuild.

func WithEngine

func WithEngine(e *gin.Engine) Option

WithEngine supplies a pre-configured Gin engine. Without it, nexus builds a bare engine with just Recovery so the caller can bring their own logger.

func WithTracing

func WithTracing(capacity int) Option

WithTracing enables per-request trace events, buffered in a ring of the given capacity. Required for the dashboard's event stream to show anything.

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.

func (*Service) Attach

func (s *Service) Attach(r resource.Resource) *Service

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) Describe

func (s *Service) Describe(desc string) *Service

func (*Service) MountGraphQL

func (s *Service) MountGraphQL(path string, schema *graphql.Schema, opts ...gql.Option)

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) REST

func (s *Service) REST(method, path string) *rest.Builder

func (*Service) Using

func (s *Service) Using(names ...string) *Service

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

func (s *Service) UsingDefaults() *Service

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.

func (*Service) WebSocket

func (s *Service) WebSocket(path string) *ws.Builder

type UseReporter

type UseReporter interface {
	OnUse(func(ctx context.Context, name string))
}

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.

Directories

Path Synopsis
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.
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 integrated with go.uber.org/fx in the style of the oats_admin_backend / applicant services: per-domain fx.Module, fx.Provide for the service struct, fx.Invoke to register endpoints against *nexus.App.
An example showing nexus integrated with go.uber.org/fx in the style of the oats_admin_backend / applicant services: per-domain fx.Module, fx.Provide for the service struct, fx.Invoke to register endpoints against *nexus.App.
graphapp command
Example: a complete GraphQL service built with github.com/paulmanoni/go-graph and registered into a nexus dashboard.
Example: a complete GraphQL service built with github.com/paulmanoni/go-graph and registered into a nexus dashboard.
petstore command
wstest command
Package fxmod integrates nexus with go.uber.org/fx.
Package fxmod integrates nexus with go.uber.org/fx.
Package graphfx is the glue between nexus and github.com/paulmanoni/go-graph.
Package graphfx is the glue between nexus and github.com/paulmanoni/go-graph.
Package middleware is the metadata side of nexus middleware handling.
Package middleware is the metadata side of nexus middleware handling.
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 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/go-graph) onto Gin and introspects its operations into the nexus registry.
Package gql mounts a GraphQL schema (typically assembled by github.com/paulmanoni/go-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.

Jump to

Keyboard shortcuts

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