An Introduction to GraphQL with Apollo
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: What types exist in your system and what operations are allowed on those types.
- Resolvers: How to load individual properties of your types.
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 } }