Starting Github repository. Use start-mutations branch
Get the full GraphQL series here
In this post we’re going to look at working with GraphQL Mutations to perform CRUD operations on our MySQL database managed by Prisma.
Learn to code with our beginner friendly tutorials on programming, Linux, Docker, and more
So we have an empty database. Let’s setup some Mutations so we can do some CRUD with GraphQL!
We have two places we need to edit in our code. The “resolvers” object that defines how to retrieve, add, update, and delete the data, and the “typeDefs” that defines the “layout” of the server (allowable operations, parameters accepted, return values, etc)
Create a database record: CreateUser
The first thing we’ll add is a createUser
operation. Edit your schema.graphql
file by adding the Mutation root type below:
type Query {
helloWorld: String!
users: [User!]!
user(userId: ID!): User
}
type Mutation {
createUser(email: String!, firstName: String!): User
}
type User {
id: ID!
firstName: String!
email: String!
}
The above Mutation creates a “createUser” operation that takes in a required “email” parameter of type String, and a required firstName paremeter of type String. it returns a User type meaning the return value of createUser() must look exactly like the type User (defined right below type Mutation).
Now let’s define how our server will actually create the record in our const resolvers
in index.js
Right after the Query: { … } put in the following code:
const resolvers = {
Query: {
//...
},
Mutation: {
createUser: (parent, args, context, info) => {
const newUser = context.prisma.user.create({
data: {
email: args.email,
firstName: args.firstName,
},
});
return newUser;
},
},
// User below...
Now we create a new user with context.prisma.user.create
. The arguments passed into the mutation (email and firstName) are accessed via the args
parameter. If you go look at the schema.prisma
file you’ll see that we need an “id”, “createdAt”, “firstName”, and “email”. Prisma automatically takes care of id
and createdAt
but doesn’t know by default what to do with email
and firstName
So we tell prisma to set those values to args.firstName
and args.email
Finally, we return the newUser
object because in our typeDefs in schema.graphql, the createUser function is expected to return a User object. Refresh your server and let’s give it a shot by entering the following query into the playground:
mutation {
createUser(email: "joe@joe.com", firstName: "Joe") {
email
id
firstName
}
}

Note that I’m using a separate tab in the playground. This way I can switch between various queries quickly.
Delete Mutations in GraphQL & Prisma
Now that we have some records in our database we can setup the ability to delete them.
We already know everything we need to delete a record using Mutations and prisma. Think about what we need:
- The id of the record to delete
- a prisma function that deletes (We can check context for available functions by logging, breakpoint, or docs)
- typeDefinition for deleteUser
- resolver that actually does the deleting
Let’s get to it! deleteUser will “mutate” the database, so it belongs in Mutations. deleteUser needs an ID and will return the type of object it deletes… type User.
Put this code in your schema.graphql
// ... type Query {...}
type Mutation {
createUser(email: String!, firstName: String!): User
deleteUser(userId: ID!): User
}
Note: userId is just a parameter name. You could name it elephant, but that’d be confusing.
Now let’s make the resolver. Inside the “Mutation” root type, add the deleteUser function in src/index.js
:
Mutation: {
//... createUser: (...){...},
deleteUser: (parent, args, context, info) => {
return context.prisma.user.delete({
where: { id: parseInt(args.userId) },
});
},
In the above code we run the delete() operation where the user’s id is equal to the userId passed in as an argument (args.userId), and return the deleted User. Returning the deleted User is nice because you can do stuff to the user. (like say “John has been destroyed!” in the UI) We’re using parseInt to make sure GraphQL doesn’t complain about ID being the wrong type. Adjust as necessary.
Ok now open a new tab in the GraphQL playground and enter the following Mutation to delete a user:
mutation {
deleteUser(userId: 1) {
id
firstName
email
}
}
Challenge Time: See if you can delete a user by passing in the userId via Query variables at the bottom tab in the playground.

Update Mutations in GraphQL
Update mutations are just about the same thing, but we’re going to do it a little different to show you various ways of setting things up. Based on what we know now, you COULD do something like the following:
// Example only. We're not using this code.
type Mutation {
// other stuff
updateUser(userId: ID!, firstName: String, email: String): User
}
// bla bla
const resolvers = {
// other stuff
Mutation: {
updateUser: (parent, args, context, info) => {
console.log(args);
return context.prisma.user.update({
where: {
id: parseInt(args.userId),
},
data: { firstName: args.firstName, email: args.email },
});
}
}
Interestingly the above code works. Both the firstName and email are optional parameters. I originally thought that leaving a parameter blank would cause that data to be updated as a blank field, but somewhere in the code it’s smart enough to only update if the field is populated. I’m too lazy to figure it out, but I suspect it’s an internal thing where JS drops the key value pair if the value is blank, OR Prisma recognizes a blank parameter and ignores it.
Despite the fact the above code works. Let’s try something different.
Input Types in GraphQL
Input types allow you to reuse bits of code in your Schema. If you find yourself re-using the same input parameters over and over you can stick them in an Input type and reuse it. They currently only work with primitive data types though. Edit your schema.graphql
with the following changes:
type Mutation {
createUser(email: String!, firstName: String!): User
deleteUser(userId: ID!): User
updateUser(userId: ID!, input: UserInput!): User
}
input UserInput {
firstName: String
email: String
}
Now we can package all the User input fields into a nice little package. I left the id outside because it’s a required field and it’s used to identify the user rather than be part of the update. Do it however you want.
and in our const resolvers
in index.js
add the updateUser mutation:
Mutation: {
updateUser: (parent, args, context, info) => {
return context.prisma.user.update({
where: {
id: parseInt(args.userId),
},
data: { ...args.input },
});
},
createUser: // ....
The above code now uses the single argument args.input to populate the data fields that are to be updated by Prisma. It does so with destructuring the input parameters into the data: { } value.
Ok we’re ready to restart the server and try an update. Run the below query in the playground (obviously find a userId that works):
mutation {
updateUser(userId: 2, input: {firstName: "Jolene", email: "jolene@jolene.com"}) {
id
email
firstName
}
}

Because we’re passing in a parameter named “input” with the type of “UserInput” the argument has to look like UserInput.
Let’s Refactor and clean up a little
First let’s delete the hard coded array from a few tutorials back:
// Delete this
let users = [
{
id: "123",
firstName: "Cindy",
email: "cindy@cindy.com",
},
{
id: "456",
firstName: "Todd",
email: "todd@todd.com",
},
];
Also remove the helloWorld string in the schema.graphql
, which looks like the line below:
helloWorld: String!
Also remove the helloWorld Query in the resolvers:
helloWorld: () => `Hello World! What a day!`,
and edit the existing “user” function to grab data from the real database instead of our hard coded array. The way to find a single user is almost identical to how we delete a single user. Here’s the code to find by User id:
const resolvers = {
Query: {
users: async (parent, args, context, info) => {
console.log(context);
return context.prisma.user.findMany();
},
user: (parent, args, context, info) => {
return context.prisma.user.findOne({
where: {
id: parseInt(args.userId),
},
});
},
//...
We’ll move the resolvers into their own files later on. Let’s stop here, and do a quick Mutations Part Two for UpdateMany and DeleteMany.
The final code for this tutorial can be found in the done-mutations branch on Github
Source code for completed version of this part coming soon.