An Introduction to GraphQL with Apollo

Feb 11, 2020

The apollo-server package provides a framework for building GraphQL APIs. There are 2 components you need to implement to build a GraphQL API:

Schema and Resolvers

With a GraphQL schema and resolvers, you can define a read-only API with Apollo.

First, a GraphQL schema is a string that defines every type your API returns and every operation your API allows. For example, the below GraphQL schema defines one query operation, getCount(), that returns an object of type CountResult.

const schema = `
  type Query {
    getCount: CountResult
  }

  type CountResult {
    count: Int
    time: Float
  }
`;

In a GraphQL schema, the Query type is special: it lists out all queries (read-only operations) that the server allows.

Resolvers allow you to actually implement the getCount() function. The below example shows how you can start up an Apollo server with the above schema, and make an HTTP request using Axios:

const { ApolloServer, gql } = require('apollo-server');

let count = 0;

// The `gql()` function parses the schema
const schema = gql(`
  type Query {
    getCount: CountResult
  }

  type CountResult {
    count: Int
    time: Float
  }
`);

// Resolvers define how the actual operations are implemented.
// The `Query.getCount()` resolver defines what happens when
// you call `getCount()`, and the `Query.CountResult` resolvers
// define how to transform the individual properties.
const resolvers = {
  Query: {
    getCount: () => ({ count, time: Date.now() })
  },
  CountResult: {
    count: obj => obj.count,
    time: obj => obj.time
  }
};

const server = new ApolloServer({ typeDefs: schema, resolvers });
const handle = await server.listen();

// Make a request to the Apollo server. GraphQL requests are
// just plain old HTTP requests.
const axios = require('axios');
const { data } = await axios.post(handle.url, {
  query: `
    { getCount { count, time } }
  `
});

data.data; // { getCount: { count: 0, time: 1581442587371 } }

Mutations

The previous Apollo server is read-only. It just allows you to get the current count, not increment it. In GraphQL, an operation that modifies data is called a mutation.

Like Query, Mutation is a special type that lists out every mutation your API allows.

const schema = `
  type Query {
    getCount: CountResult
  }

  type Mutation {
    increment: CountResult
  }

  type CountResult {
    count: Int
    time: Float
  }
`;

In Apollo, mutations are just resolvers for the Mutation type as shown below.

const { ApolloServer, gql } = require('apollo-server');

let count = 0;

const schema = gql(`
  type Query {
    getCount: CountResult
  }

  type Mutation {
    increment: CountResult
  }

  type CountResult {
    count: Int
    time: Float
  }
`);

const resolvers = {
  Query: {
    getCount: () => ({ count, time: Date.now() })
  },
  // `increment` is just a resolver for the Mutation type
  Mutation: {
    increment: () => ({ count: ++count, time: Date.now() })
  },
  CountResult: {
    count: obj => obj.count,
    time: obj => obj.time
  }
};

const server = new ApolloServer({ typeDefs: schema, resolvers });
const handle = await server.listen();

const axios = require('axios');
// Call the `increment` mutation
await axios.post(handle.url, {
  query: 'mutation { increment { count, time } }'
});

// After the `increment` mutation, `count` is now 1
const { data } = await axios.post(handle.url, {
  query: '{ getCount { count, time } }'
});

data.data; // { getCount: { count: 1, time: 1581442587371 } }

Did you find this tutorial useful? Say thanks by starring our repo on GitHub!

More Graphql Tutorials