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):
- Registry.FromManifests reads installed plugins, collects graphql blocks.
- compose.BuildSupergraphYAML writes rover supergraph compose config.
- External: rover supergraph compose → supergraph.graphql.
- router.ComposeService returns the Apollo Router docker-compose block (CS_7 slot).
- nginx template routes /graphql to port 4000 instead of 8080.
Index ¶
- func BuildSupergraphYAML(entries []SubgraphEntry) ([]byte, error)
- func ComposeService(opts RouterComposeOptions) (string, error)
- func NginxDirective(federationEnabled bool) string
- func RouterBaseConfig() string
- func RunRoverCompose(ctx context.Context, opts ComposeOptions) error
- type ComposeOptions
- type EntityKey
- type ManifestGraphQLBlock
- type RouterComposeOptions
- type SubgraphConfig
- type SubgraphEntry
- type SubgraphStatus
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 ¶
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.