Modularise our Apollo Server schema

July 08, 2019

When our schema starts to become long and complex one of the technique we have is schema stitching. Apollo team is working really hard to provide a better way to split our schema into multiple files introducing Modules.

Modules

The better way to describe how modules work is giving a small example and explain step by step what to do to implement it. Let try to build a query that displays a list of books with author and a list of Authors:

type Book {
  title: String
  author: Author
}
 type Author {
  name: String
  books: [Book]
}

As usual we start from our index.js:

const {ApolloServer} = require('apollo-server');
 const server = new ApolloServer({
    modules: [
        require('./modules/author'),
        require('./modules/books')
    ]
})
 server
    .listen()
    .then(({url}) => console.log(`server is running at ${url}`));

As we can see the main change is the modules array that includes 2 requires: author and books.

Let's create our ./modules/author/index.js:

const {gql} = require('apollo-server');
 const typeDefs = gql`
    extend type Query {
        author(id: ID!): Author
        authors: [Author]
    }
     type Author {
        id: ID!
        name: String
        surname: String
    }
`;
 const resolvers = {
    Query: {
        author(_, {id}) {
            return {
                id,
                name: 'Daniele',
                surname: 'Zurico'
            }
        },
        authors() {
            return [
                {
                    id: Math.round(Math.random() * 100000),
                    name: 'Daniele',
                    surname: 'Zurico',
                },
                {
                    id: Math.round(Math.random() * 100000),
                    name: 'Alex',
                    surname: 'Michaels',
                }
            ]
        }
    }
};
 module.exports = {
    typeDefs,
    resolvers
}

Our author file has no difference with what we already learnt. We created 2 queries:

  • list of authors;
  • The author has given the id.

Is time to move to ./modules/books/index.js:

const {gql} = require('apollo-server');
 const typeDefs = gql`
    extend type Query {
        book(id: ID!): Book
        books: [Book]
    }
     type Book {
        id: ID!
        title: String
        author: Author
    }
     extend type Author {
        books: [Book]
    }
`;
 const resolvers = {
    Query: {
        book(_, {id}) {
            return {
                id,
                title: 'test',
                author: {
                        id: Math.round(Math.random() * 100000),
                        name: 'Daniele',
                        surname: 'Zurico'
                    }
            }
        },
        books() {
            return [
                {
                    id: Math.round(Math.random() * 100000),
                    title: 'test',
                    author:{
                        id: Math.round(Math.random() * 100000),
                        name: 'Daniele',
                        surname: 'Zurico'
                    }
                },
                {
                    id: Math.round(Math.random() * 100000),
                    title: 'test2',
                    author: {
                        id: Math.round(Math.random() * 100000),
                        name: 'Alex',
                        surname: 'Michaels'
                    },
                }
            ]
        }
    },
    Author: {
        books() {
            return [{
                id: Math.round(Math.random() * 100000),
                title: 'test',
            }]
        }
    }
 };
 module.exports = {
    typeDefs,
    resolvers
}

Our books contain something more then we probably didn't see before:

extend type Author {
  posts: [Book]
}

And this is the glue between our Author and Books that allow us to extend the Author schema introducing the list of Books.

Test our Server

To explore the newly created GraphQL API, open a browser to the link shown in the console, http://localhost:4000/

query {
  books {
    id
    title
    author {
      id
      name
        surname
    }
  }
}
query {
  authors {
    id
    name
    surname
    books {
      id
      title
    }
  }
}

Conclusion

Modules currently lack support for some things, like custom scalars, but will work for some simple cases, and we plan on expanding the support.