GraphQL Mutations in Apollo
A GraphQL mutation is an
API operation that modifies data. Like Query
, Mutation
is a special
type in your GraphQL schema:
const schema = `
type Query {
getCount: CountResult
}
type Mutation {
increment: CountResult
}
type CountResult {
count: Int
time: Float
}
`;
Every member of the Mutation
type is a distinct API operation that
you can use to modify data. In the above schema, there is exactly
one mutation: increment()
. The increment()
operation returns
an object of type CountResult
.
Implementing a Mutation
A GraphQL schema is just a list of type definitions. You also need
to implement the business logic of the increment()
mutation.
Like for queries, you implement the increment()
mutation as a
resolver
on the Mutation
type:
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 } }
Note that, to actually call a mutation, you need to start your
GraphQL query with the string 'mutation'
:
await axios.post(handle.url, {
// Note 'mutation' below. Not necessary for queries, but
// necessary for mutations.
query: 'mutation { increment { count, time } }'
});
Mutation Arguments
A GraphQL mutation is a function like any other. You can pass arguments
to your mutation as well. For example, if you want to allow increment()
with a value other than 1, you can add a Number
parameter to the
increment()
mutation:
const schema = `
type Query {
getCount: CountResult
}
type Mutation {
increment(num: Int): CountResult
}
type CountResult {
count: Int
time: Float
}
`;
Apollo passes the arguments passed in to your mutation as the 2nd parameter to your mutation's resolver function:
increment: (obj, args) => {
args.num; // Whatever the user passed in `increment()`
}
Below is a full implementation of increment()
with arguments:
let count = 0;
const schema = gql(`
type Query {
getCount: CountResult
}
type Mutation {
increment(num: Int!): 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: (obj, args) => {
count += args.num;
return { 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();
let axios = require('axios');
// Call the `increment` mutation with an argument. Note that
// GraphQL arguments are named: you need to put `num: 5`, not
// just `5`.
await axios.post(handle.url, {
query: 'mutation { increment(num: 5) { count, time } }'
});
// After the `increment` mutation, `count` is now 5
const { data } = await axios.post(handle.url, {
query: '{ getCount { count, time } }'
});
data.data; // { getCount: { count: 5, time: 1581442587371 } }