Apollo Federation

This guide shows how to create a subgraph using the Neo4j GraphQL Library, for composition into a supergraph using Apollo Federation.

The objective is to convert the following monolithic schema into a subgraph schema for use behind a Federation gateway:

import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
import { Neo4jGraphQL } from "@neo4j/graphql";
import neo4j from "neo4j-driver";

const typeDefs = `#graphql
  type User {
    id: ID!
    name: String!
  }
`;

const driver = neo4j.driver(NEO4J_URI, neo4j.auth.basic("username", "password"));

const neo4jGraphQL = new Neo4jGraphQL({
  typeDefs,
  driver,
})

const schema = await neo4jGraphQL.getSchema();

const server = new ApolloServer({
  schema,
});

const { url } = await startStandaloneServer(server);
console.log(`🚀  Server ready at ${url}`);

Setup

To proceed with the conversion, follow these steps:

  1. Create a directory for a new project and cd into it:

    mkdir neo4j-graphql-subgraph-example
    cd neo4j-graphql-subgraph-example
  2. Initialize a new Node.js project with npm:

    npm init --yes
    npm pkg set type="module"

    This how-to guide sets up the project using ES Modules, which allows the usage of features such as top-level await.

  3. Choose TypeScript or JavaScript to proceed with the setup:

  1. Create a src directory with an empty index.js file to contain the entrypoint to your code:

    mkdir src
    touch src/index.js
  2. Replace the default scripts entry in your package.json file with the following:

    {
      // ...etc.
      "scripts": {
        "start": "node index.js"
      }
      // other dependencies
    }
  1. Create a src directory with an empty index.ts file to contain the entrypoint to your code:

    mkdir src
    touch src/index.ts
  2. Install the development dependencies required for working with a TypeScript project:

    npm install --save-dev typescript @types/node @tsconfig/node-lts
  3. Create an empty tsconfig.json file containing the compiler configuration for TypeScript:

    touch tsconfig.json
  4. Add the following configuration to the tsconfig.json file:

    {
      "extends": "@tsconfig/node-lts/tsconfig.json",
      "compilerOptions": {
        "rootDir": "src",
        "outDir": "dist",
      }
    }

    This configuration extends the community base for Node.js LTS, provided by the @tsconfig/node-lts package installed above. For more information on the available options, see the TypeScript Compiler docs.

  5. Replace the default scripts entry in your package.json file with the following:

    {
      // ...etc.
      "scripts": {
        "compile": "tsc",
        "start": "npm run compile && node ./dist/index.js"
      }
      // other dependencies
    }
  1. To proceed with the setup, install the required dependencies running the following command:

    npm install @apollo/server @neo4j/graphql graphql neo4j-driver

    There are the dependencies to be installed:

    • @apollo/server, the library for Apollo Server, is used in this guide to host the subgraph.

    • @neo4j/graphql is the Neo4j GraphQL Library, which translates GraphQL into Cypher and returns the results.

    • graphql is the reference implementation of the GraphQL specification. It is required for @neo4j/graphql to function.

    • neo4j-driver is the library for the Neo4j driver, which is required to execute Cypher queries against the database.

Opt in to Federation

For a set of type definitions to be usable as a subgraph for Federation, they must include the following schema extension:

const typeDefs = `#graphql
  extend schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key"])

  type User {
    id: ID!
    name: String!
  }
`;

This example only includes the Federation @key directive. To use more Federation directives, add them to the import array.

Define an entity

Defining a type as an entity allows other subgraphs to contribute with fields to the Movie type. To achieve that, use the @key directive to designate a field (or fields) as a key:

const typeDefs = `#graphql
  extend schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key"])

  type User @key(fields: "id") {
    id: ID!
    name: String!
  }
`;

Although only the @key directive has been added to this example, consider using either the @id or the @unique directives on the id field. The Federation gateway expects each key to resolve to one result, so it is good practice to ensure that these values are unique in the database.

Generate a subgraph schema

When using the Neo4j GraphQL Library, generating the subgraph schema can be achieved by calling getSubgraphSchema instead of getSchema. For that, the following line needs to be changed:

const schema = neo4jGraphql.getSubgraphSchema();

Conclusion

By combining all previous snippets, you should get this:

import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
import { Neo4jGraphQL } from "@neo4j/graphql";

const typeDefs = `#graphql
  type User @key(fields: "id") {
    id: ID!
    name: String!
  }
`;

const driver = neo4j.driver("bolt://localhost:7687", neo4j.auth.basic("username", "password"));

const neo4jGraphQL = new Neo4jGraphQL({
  typeDefs,
  driver,
})

const schema = await neo4jGraphQL.getSubgraphSchema();

const server = new ApolloServer({
  schema,
});

const { url } = await startStandaloneServer(server);
console.log(`🚀  Server ready at ${url}`);

For further iteration, this subgraph can also be composed into a supergraph. Check Apollo’s guides for more instructions: