federation

package
v1.1.4 Latest Latest
Warning

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

Go to latest
Published: May 21, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package federation implements GraphQL Federation support for multi-service nSelf deployments. Federation is opt-in via NSELF_FEDERATION=true or nself config set federation=true. Single-service deployments continue to use Hasura as the sole GraphQL engine (no Apollo Router injected).

Architecture:

Client
  → Apollo Router (CS_7, port 4000)   — supergraph gateway
    ├─ Hasura subgraph
    ├─ ai subgraph (if installed)
    ├─ claw subgraph (if installed)
    └─ … other plugin subgraphs

Build pipeline (federation mode):

  1. Registry.FromManifests reads installed plugins, collects graphql blocks.
  2. compose.BuildSupergraphYAML writes rover supergraph compose config.
  3. External: rover supergraph compose → supergraph.graphql.
  4. router.ComposeService returns the Apollo Router docker-compose block (CS_7 slot).
  5. nginx template routes /graphql to port 4000 instead of 8080.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BuildSupergraphYAML

func BuildSupergraphYAML(entries []SubgraphEntry) ([]byte, error)

BuildSupergraphYAML renders the rover supergraph compose configuration from the provided subgraph entries and returns the YAML content as a byte slice. The caller is responsible for writing the result to disk (typically at .nself/federation/supergraph.yaml).

entries must be non-empty. At minimum, the Hasura subgraph must be present.

func ComposeService

func ComposeService(opts RouterComposeOptions) (string, error)

ComposeService returns the docker-compose YAML block for the Apollo Router CS_7 service. The returned string is ready to be injected into the services: section of docker-compose.yml when NSELF_FEDERATION=true.

func NginxDirective

func NginxDirective(federationEnabled bool) string

NginxDirective returns the nginx upstream + location block to redirect /graphql traffic to Apollo Router (port 4000) when federation is enabled, or to Hasura (port 8080) when disabled.

federationEnabled should mirror the NSELF_FEDERATION env var.

func RouterBaseConfig

func RouterBaseConfig() string

RouterBaseConfig returns the base Apollo Router YAML configuration content. This is written to .nself/federation/router.yaml and mounted into the Apollo Router container.

func RunRoverCompose

func RunRoverCompose(ctx context.Context, opts ComposeOptions) error

RunRoverCompose executes `rover supergraph compose --config <yaml> --output <out>`. It returns an error if rover is not found, exits non-zero, or produces no output file. This satisfies the acceptance criterion: "Plugin with invalid schema fails nself build with clear error."

Types

type ComposeOptions

type ComposeOptions struct {
	// SupergraphYAMLPath is the path to the rover supergraph compose config.
	SupergraphYAMLPath string
	// OutputPath is where rover writes supergraph.graphql.
	OutputPath string
	// RoverBin is the path to the rover binary. Defaults to "rover" on PATH.
	RoverBin string
}

ComposeOptions controls the behaviour of RunRoverCompose.

type EntityKey

type EntityKey struct {
	// Type is the GraphQL type name (e.g. "User").
	Type string `yaml:"type" json:"type"`
	// Key is the field used as the @key directive value (e.g. "id").
	Key string `yaml:"key" json:"key"`
}

EntityKey describes a single Apollo Federation entity type owned by a subgraph.

type ManifestGraphQLBlock

type ManifestGraphQLBlock struct {
	// PluginName is the plugin.yaml name field (used in error messages).
	PluginName string
	// PluginPort is the plugin's declared port (substituted for ${PORT}).
	PluginPort int
	// GraphQL is the graphql: block from the manifest.
	GraphQL SubgraphConfig
}

ManifestGraphQLBlock is the subset of the plugin manifest that carries federation registration. It mirrors the YAML fields that plugin authors write in their plugin.yaml under the graphql: key.

This type lives here (not in plugin/) to avoid a circular import: federation → plugin is not allowed because plugin/ is a lower-level package. The caller (build/) reads manifests with plugin.PluginManifest and then calls federation.FromManifestBlocks with the extracted GraphQL fields.

type RouterComposeOptions

type RouterComposeOptions struct {
	// SupergraphPath is the absolute host path to supergraph.graphql.
	SupergraphPath string
	// RouterConfigPath is the absolute host path to router.yaml base config.
	RouterConfigPath string
}

RouterComposeOptions controls the Apollo Router service block generation.

type SubgraphConfig

type SubgraphConfig struct {
	// Enabled must be true for the plugin to participate in federation.
	Enabled bool `yaml:"enabled" json:"enabled"`
	// SubgraphName is the unique lowercase name used in the supergraph schema.
	// Must be a valid GraphQL SDL name: [a-z][a-z0-9_]*.
	SubgraphName string `yaml:"subgraph_name" json:"subgraph_name"`
	// SubgraphURL is the HTTP endpoint that serves the subgraph SDL and
	// resolves federation queries. May contain ${PORT} which is interpolated
	// from the plugin's Port field at build time.
	SubgraphURL string `yaml:"subgraph_url" json:"subgraph_url"`
	// SchemaPath is a repo-relative path to the plugin's static SDL file.
	// Used by rover supergraph compose. Either SchemaPath or SubgraphURL
	// must be non-empty for rover to compose the schema.
	SchemaPath string `yaml:"schema_path,omitempty" json:"schema_path,omitempty"`
	// Entities lists the Apollo Federation entity types this subgraph owns.
	// Each entry has a Type name and the Key field used for cross-subgraph
	// entity resolution.
	Entities []EntityKey `yaml:"entities,omitempty" json:"entities,omitempty"`
}

SubgraphConfig describes a single plugin's GraphQL subgraph registration, parsed from the graphql block in plugin.yaml.

type SubgraphEntry

type SubgraphEntry struct {
	// Name is the unique subgraph identifier in the supergraph schema.
	Name string
	// URL is the resolved HTTP endpoint.
	URL string
	// SchemaPath is the rover-usable schema path (may be empty).
	SchemaPath string
}

SubgraphEntry is the resolved form of a plugin subgraph — name, URL, and schema path are fully interpolated and validated. Used as input to compose.BuildSupergraphYAML.

func FromManifestBlocks

func FromManifestBlocks(blocks []ManifestGraphQLBlock, hasuraURL string) ([]SubgraphEntry, error)

FromManifestBlocks converts a slice of plugin manifest GraphQL blocks into a deduplicated, validated list of SubgraphEntry values ready for supergraph composition. Hasura is prepended as the first entry.

Rules:

  • Plugins with graphql.enabled == false are silently excluded.
  • Each enabled plugin must have a non-empty SubgraphName and SubgraphURL.
  • SubgraphName must match [a-z][a-z0-9_]* and must not be "hasura".
  • Duplicate SubgraphName values cause an error (fail-closed).
  • ${PORT} in SubgraphURL is substituted with the plugin's declared port.

hasuraURL is the Hasura GraphQL endpoint used as the first subgraph.

type SubgraphStatus

type SubgraphStatus struct {
	// Name is the subgraph name.
	Name string `json:"name"`
	// URL is the subgraph endpoint.
	URL string `json:"url"`
	// SchemaHash is the SHA-256 hex digest of the last composed schema.
	SchemaHash string `json:"schema_hash"`
	// LastComposed is the RFC 3339 timestamp of the last successful composition.
	LastComposed string `json:"last_composed"`
	// Status is one of "active", "inactive", "error".
	Status string `json:"status"`
}

SubgraphStatus is the runtime health record for a single subgraph, returned by StatusReport.

Jump to

Keyboard shortcuts

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