Skip to main content

Apollo Gateway w/ Subgraphs (JS Middleware)

The Inigo plugin for Apollo Gateway provides full observability and controls on both the supergraph and all the individual subgraphs. Follow the instructions to get up and running with your gateway.

A working example of this integration is available at https://github.com/inigolabs/workshops/blob/main/apollo-gateway-fed-2-demo

Installation

Inigo supports Node v18 and v20 LTS releases.

  • Install the inigo.js package
    npm install inigo.js
  • Install your platform specific library:
    npm install inigo-linux-amd64
    Available libraries:
    • inigo-linux-amd64
    • inigo-linux-arm64
    • inigo-darwin-amd64
    • inigo-darwin-arm64
    • inigo-windows-amd64

Get token

  • Set up a service and a token. If you still need one, follow Getting Started.

Configuration

  • Create a gateway.yaml configuration file
    Replace the service names and urls with your own subgraph configurations.
    Any subgraphs omitted from this list will still work as normal, but will not go through the Inigo plugin.

    ```yaml
    kind: Gateway
    name: <service_name> # service name created in the previous command
    label: <service_label> # optional service label
    spec:
    services:
    - name: accounts
    url: "http://localhost:4001/graphql"
    - name: reviews
    url: "http://localhost:4002/graphql"
    - name: products
    url: "http://localhost:4003/graphql"
    - name: inventory
    url: "http://localhost:4004/graphql"
    ```
  • Apply the gateway configuration

inigo apply gateway.yaml
  • When adding or removing subgraphs, the apply command above needs to be rerun and the gateway needs to be restarted.

Integration

The following code contains ApolloServer, ApolloGateway, Inigo, and other supporting objects and libraries to have a complete solution. The code following is from the example application gateway.js implementation.

const { ApolloServer } = require('@apollo/server');
const { startStandaloneServer } = require('@apollo/server/standalone');
const { ApolloGateway } = require("@apollo/gateway");
const { Inigo, InigoRemoteDataSource, InigoSchemaManager } = require("inigo.js");
const { readFileSync } = require("fs");
const { resolve } = require("path");
require("dotenv").config()

// If you want to use a locally composed schema:
// 1. Run "inigo compose ./inigo/gateway.yaml > supergraph.graphql"
// 2. Add "LOCAL_COMPOSED_SCHEMA=supergraph.graphql" to the .env
// 3. Start the gateway with "npm run start-gateway"
// 4. If you change your local subgraph schemas, run "inigo compose" again and restart the gateway

var supergraphSchemaConfig;

if(process.env.LOCAL_COMPOSED_SCHEMA) {
console.log("💻 You're using a local federated schema from .env.LOCAL_COMPOSED_SCHEMA");
var cwd = resolve(__dirname, ".");
var supergraphSdl = resolve(cwd, process.env.LOCAL_COMPOSED_SCHEMA);
supergraphSchemaConfig = readFileSync(supergraphSdl, "utf-8");
}
else {
console.log("⛅ You're using a federated schema pulled from Inigo's schema repository");
supergraphSchemaConfig = new InigoSchemaManager()
}

const gateway = new ApolloGateway({
supergraphSdl: supergraphSchemaConfig,
buildService(service) {
return new CustomRemoteDataSource(service, inigo);
}
});

const inigo = new Inigo();

const server = new ApolloServer({
gateway,
plugins: [
inigo.plugin(),
],
introspection: true,
});

startStandaloneServer(server, {
listen: { port: 4000 },
}).then(({ url }) => console.log(`🚀 Supergraph ready at ${url}`));


// Optionally needed for headers to be propagated to the subgraphs
class CustomRemoteDataSource extends InigoRemoteDataSource {
async onBeforeSendRequest({ request, context }) {
if (context.req && context.req.headers) {
// pass all headers to subgraph
Object.keys(context.req.headers || []).forEach(key => {
if (context.req.headers[key]) {
request.http.headers.set(key, context.req.headers[key]);
}
});
}
}
}

Existing RemoteDataSource

If you already have a custom RemoteDataSource, the InigoDataSourceMixin provides an easier way to integrate the InigoRemoteDataSource into your existing code using TypeScript.

new (InigoDataSourceMixin(BaseDataSource, inigo))(...)

In this example code, inigo is the instance of Inigo class, and BaseDataSource is your custom RemoteDataSource implementation.

Set Up

It is recommended that you have a .env file set up (as shown in the demo), but you can also use environment variables.

Set Up for a Locally Composed Schema

Here is an example .env file that sets up a LOCAL_COMPOSED_SCHEMA variable that can be used to load a composed supergraph that was create with inigo compose, rover supergraph compose, or created manually.

INIGO_SERVICE_TOKEN=eyJhbGc...
LOCAL_COMPOSED_SCHEMA=supergraph.graphql

You can use inigo compose, as documented in the example application as such:

inigo compose inigo/gateway.yaml > supergraph.graphql

Set Up a Composed Schema from the Inigo Schema Registry

Here is an example .env file that pulls a composed supergraph from the Inigo schema registry.

INIGO_SERVICE_TOKEN=eyJhbGc...

Execution

Running Apollo Gateway with Inigo

You can run Apollo Gateway as normal, assuming that you minimally have INIGO_SERVICE_TOKEN set as an environment variable or in your .env file. For the example application it can be run as such:

npm run start-gateway

Depending on your configuration, the composed schema will be loaded either from the local file or pulled down from the Inigo Registry.

Optional Flags

Other optional available environment flags:

INIGO_ENABLE=[true, false]                      # default is true
LOG_LEVEL=[disabled, debug, info, error, fatal] # default log level is info

Limitations

  • Alpine docker support is currently unavailable.