Skip to main content

Schema Composition and Registry

Using GraphQL federation allows for a single GraphQL endpoint to combine multiple GraphQL api endpoints (referred to as subgraphs in this document) which can each be developed and deployed independently. It is a great way to break down a single monolithic GraphQL application into several services. Federation enables extension and sharing of types across the different services.

Inigo supports both schema composition and schema registry. The main components involved in federating schemas are the InigoCLI, Inigo Cloud, and the Inigo Registry.

  • Inigo CLI can be used to compose schemas locally as well as apply composed schemas to Inigo Cloud.
  • Inigo Cloud manages versions of all the composed schemas. It adds the ability to check that a new schema can be composed by comparing it with the previous schema. Cloud also adds the ability to check for breaking schema changes using real analytics data to determine if breaking changes are safe.
  • Inigo Registry is a component designed to run together with the deployment of the GraphQL gateways. The registry fetches the latest composed schema from Inigo Cloud and publishes the new schema to all gateways. The Inigo Registry is distributed as a docker container and can be configured to have different storage methods such as S3, GCS, or local file store. Having the registry run locally with the deployment minimizes deployment issues and potential downtime. In the rare case of Inigo Cloud downtimes, newly applied schemas will not be available for the local registry, however all current operations will keep going, and new pods will be able to fetch the most current schema and deploy without interruption.

The following diagram illustrates the different components of the schema composition and registry process:

Schema Composition

Configuration

The process of taking multiple subgraph schemas and composing them into a single federated graph requires some basic configuration describing the different subgraphs and the gateway. Just like the rest of Inigo, this is achieved using yaml configuration files.
There are two approaches to configuring schema composition, a centralized approach and a distributed approach.

  • Centralized : a single configuration file includes all the subgraph schema information. This approach works best for mono repository setups where all subgraphs share the same codebase.
    To configure an Inigo service to support and compose subgraphs, create a gateway.yml configuration file. The filename has no significance and can be named anything as long as the kind field inside is set to Gateway.
    Inside the Gateway configuration, you supply each subgraph with a name, url of the subgraph, and schema. Inigo will use this information to compose the federated schema.
kind: Gateway
name: federated_service_name
spec:
composition: ApolloFederation_v1
services:
- name: service_one
url: http://service_one:80/query
schema_files:
- ../graphql/service_one.graphql

- name: service_two
url: http://service_two:80/query
schema_files:
- ../service_two.graphql

- name: service_three
url: http://service_three:80/query
schema_files:
- ../service_three.graphql
  • Distributed : Multiple configuration files that can live in a single or multiple code repositories. The subgraph configuration is independent from other subgraph configurations and is designed to live in the repository of the subgraph implementation. Each subgraph can be checked and applied separately. A single gateway.yml configuration only holds the global federation configuration. The information for each subgraph is split into separate subgraph.yml configuration files.

    Note: the gateway name in each subgraph configuration must match the name of the gateway configuration.

kind: Gateway
name: federated_service_name
spec:
composition: ApolloFederation_v1
kind: Subgraph
name: service_one
spec:
gateway: federated_service_name
url: http://service_one:80/query
schema_files:
- ../graphql/service_one.graphql
kind: Subgraph
name: service_two
spec:
gateway: federated_service_name
url: http://service_one:80/query
schema_files:
- ../graphql/service_two.graphql
kind: Subgraph
name: service_three
spec:
gateway: federated_service_name
url: http://service_three:80/query
schema_files:
- ../graphql/service_three.graphql

Schema Check

Use the inigo check command to validate and make sure a schema can be composed and has no breaking changes. The check command can be run locally or as part of ci.

The check command has four stages:

  • Validation: Makes sure all subgraph schema can be parsed and are valid.
  • Composition: Makes sure all subgraph schemas can be composed to a single federated schema.
  • Operational: Makes sure there are no breaking changes in the schema. Run time analytics from Inigo is used to show if breaking changes to the schema have been used by any clients in the past 30 days. This allows for safer removal of old and deprecated fields from the schema.
  • Evaluation: Makes sure all Inigo schema directive configurations are valid.

Note: this command has no side effects in Inigo Cloud.

inigo check requires a viewer role to run.

Examples:

> inigo check gateway.yml
federated_service_name no changes

> inigo check gateway.yml
Service: federated_service_name

Validation: passed
Composition: failed
Operational: omitted
Evaluation: omitted

Errors:
-------
Extension duplicates field. Field is present on base. It should be either renamed or marked @external.
subgraph: service_one
location: ../graphql/service_one.graphql:27:5
attribute: Service.FooBar

error: check failed, see report above for details

> inigo check gateway.yml
Service: federated_service_name

Validation: passed
Composition: passed
Operational: failed
Evaluation: omitted

Errors:
-------
Detected 1 breaking change(s), 1 non-breaking change(s).
New schema is validated against traffic from Tue, 27 Jun 2023 10:28:39 PDT.

Schema changes:
---------------
SAFE: Field Query.foo was added.
Location: ../graphql/service_two.graphql:47:5
+ foo: String

BREAKING: Field Query.bar was removed.
Location: composed:1163:2
- bar: String
Usage:
Operation (2) Client (2) Calls (95) LastCalled (Thu, 27 Jul 2023 08:00:00 PDT)
-------------- ----------- ------------ ------------------------------------------
QueryFoo UI_Client 26 2023-07-16 20:00:00 -0700 PDT
FooList CLI_Client 69 2023-06-30 14:00:00 -0700 PDT

error: check failed, see report above for details

Error Handling

When running inigo check as part of continuous integration there are times that breaking composition or breaking changes to the schema are expected and these checks need to be skipped in order to pass the ci. In the cases where composition will be temporarily broken or breaking changes are validated and deemed to be ok, some of the errors from the check command can be skipped or bypassed.

  • Validation Errors

    • Includes invalid configuration or schema parsing errors.
    • Are not overridable (one cannot add a force option to cause the check to pass).
  • Composition Errors

    • All schemas are parsed correctly but cannot be composed together.
    • Can use an override by providing -–skip-composition flag or by using the inigo bypass command.
      • In the case where composition is skipped or bypassed, no operational checks will take place.
  • Operational Check Errors

    • Breaking changes detected in schema.
    • Can use an override by providing -–skip-operational-check flag or by using the inigo bypass command.
  • Evaluation Errors

    • Inigo configuration which depend on schema including access control and rate limiting. If updates to the schema break these configurations, they will show up under the evaluation stage.
    • Are not overridable (one cannot add a force option to cause the check to pass).

The inigo bypass command can be used in order skip the checks on the following run of the check command. With this approach one can run the bypass command manually and then kick of another ci job which will skip the checks.

Note: bypass command requires configurator role to run

Examples:

> inigo check gateway.yml --skip-composition

> inigo check gateway.yml --skip-operational-check

> inigo bypass check <hash>

Schema Apply

The inigo apply command is used to push the latest composed schema to Inigo Cloud. Apply runs all the checks that are done in inigo check, and if everything passes, it will apply the new composed schema to Inigo Cloud making it the latest version of federated schema, and available to be published. A history of all the schema versions is maintained and can be explored in the Inigo UI. The apply command can run with both Gateway and Subgraph configuration kinds.

inigo apply requires a configurator role to run.

Examples:

> inigo apply gateway.yml

> inigo apply subgraph.yml

Error Handling

The inigo apply command runs the same checks as the inigo check command, and the same skip and bypass options are available to force apply a change with errors.

Schema Publish

The inigo publish command pushes the schema to the registry where it will be pushed to all the running gateways pods. The registry is a separate container provided by Inigo that is designed to be run together in the same deployment as the actual gateways. When a schema is published, it will be pushed to the registry and from there will be picked up by all the pods that are configured to receive this schema. Different versions of the schema can be published making it easy to rollback a failed deployment.

inigo publish requires a configurator role to run.

> inigo publish federated_service_name:prod

> inigo publish federated_service_name:prod --version 42

Local Development

Often you may want to generate a composed schema for local development without making any changes to your schemas in Inigo Cloud.
The simplest way to compose a schema is to use the inigo compose command. This command will take all the subgraph schema files configured in the Gateway configuration and output a composed schema. By default the schema is printed to stdout, but an output file can also be supplied.
If any composition errors occur during composition, the command will print out the errors and exit, no federated schema will be printed.

Note: this command only works for the centralized configuration approach.
Note: the command runs locally and has no side effects on Inigo Cloud.

inigo compose requires a viewer role to run.

Example command:

> inigo compose gateway.yml

> inigo compose gateway.yml --output federated_schema.graphql

Another common use case during development is to test a particular subgraph in which you have made changes together with a federated graph. The compose command also accepts a LocalCompose configuration file which can be used to achieve this. Inside the LocalCompose configuration, you can supply the federated graph to use as a base and subgraphs to override. For each subgraph override, you can specify where to get the schema for that subgraph. Schema source can come from a local schema file, fetched via sdl given a url endpoint, or fetched from the Inigo cloud.

Note: in order to run the local development compose, a composed schema must be available in Inigo Cloud in order to use as a base. See the apply command above in order to upload a composed schema to Inigo cloud.
Note: just like the schema compose command above, this command is also run locally and has no side effects in the cloud.

In the example below each subgraph fetches his or her schema using a different source. New subgraphs can also be added by providing a new subgraph name that is not currently part of the federated schema.

kind: LocalCompose
name: federated_service_name
spec:
services:
- name: service_one
url: http://service_one:8000/query
source:
schema_files:
- ../graphql/service_one.graphql

- name: service_two
url: http://service_two:8000/query
source:
ref: service_two:dev

- name: service_three
url: http://service_three:8000/query
source:
sdl: http://service_three:8000/query

- name: service_new
url: http://service_new:8000/query
source:
schema_files:
- ../graphql/new.graphql

Creating a composed schema from a LocalCompose configuration file is also done using the inigo compose command.

> inigo compose local.yml