
In our last post, we built a robust way to search through 157 Hammer classics. But what happens when you finally sit down to watch The Brides of Dracula? You need a way to update that record.
In GraphQL, any operation that changes data is called a Mutation.
If you have not followed part 1 of this tutorial go there now to pull the code from my Github repository.
1. Updating the Schema
First, we need to tell our server what these changes look like. We’ll add a Mutation type to our typeDefs. We have one to update a film entry(updateWatched) and one to delete a film(deleteFilm).
type Mutation {
# Toggle the watched status of a film
updateWatched(id: ID!, watched: Boolean!): Film
# Delete a film from our collection
deleteFilm(id: ID!): [Film]
}
2. Writing the Resolvers
Now, we implement the logic to update and delete a film record. Since we’re working with a local array of films data we’ll use standard JavaScript array methods to find and modify our data. Here we are using splice and find.
const resolvers = {
// ... query resolvers
Mutation: {
updateWatched: (parent, { id, watched }) => {
const film = films.find(f => f.id == id);
if (!film) {
throw new Error("Film not found");
}
film.watched = watched;
return film;
},
deleteFilm: (parent, { id }) => {
const index = films.findIndex(f => f.id == id);
if (index == -1) {
throw new Error("Film not found");
}
// Remove the film and return the updated list
films.splice(index, 1);
return films;
}
}
};3. Testing in the Playground
Once you restart your server, you can test these live.
node index.js
🚀 Server ready at http://localhost:4000/Navigating to http://localhost:4000/ will redirect to the GraphQL sandbox. Click the ‘Query your server’ button and you will be presented with something like this.

First of all we need to find all unwatched Dracula films returning the id. Quick quiz! Do you remember how to craft the query? Here it is:
query GetNotWatched {
films(watched: false, searchTerm: "dracula") {
id
title
}
}This will return the following.
{
"data": {
"films": [
{
"id": "70",
"title": "The Brides of Dracula"
},
{
"id": "102",
"title": "Dracula: Prince of Darkness"
},
{
"id": "115",
"title": "Dracula Has Risen from the Grave"
},
{
"id": "122",
"title": "Scars of Dracula"
},
{
"id": "125",
"title": "Countess Dracula"
}
]
}
}Pick a film and remember the ID. This will be used in the next step. In my case I will pick the first film which has an id of 70.
Mark “Brides of Dracula” (ID: 70) as watched:
Paste this query into the sandbox(remember to substitute your own id if it is different).
mutation {
updateWatched(id: "70", watched: true) {
title
watched
}
}After running the update query run the GetNotWatched query again to check that the film is not in the list.
Removing a film
Let’s remove “Brides of Dracula”.
mutation {
deleteFilm(id: "70") {
title
}
}If we run a query to return the film with id 70 GraphQL will now return null.
query GetFilm {
film(id: 70) {
id
watched
year
}
}Results from the query
{
"data": {
"film": null
}
}Adding a film
Let’s add the film back!
When adding a record, passing four separate arguments (ID, Title, Year, Watched) can get messy. Instead, we define an input type in our schema to group them together.
Update the Schema
We create a new input which specifies which fields are mandatory when creating a new Film. In our case all fields must be specified(indicated by the “!”). This input spec is then specified in our addFilm mutation.
input CreateFilmInput {
id: ID!
title: String!
year: Int!
watched: Boolean!
}
type Mutation {
# ... previous mutations
addFilm(input: CreateFilmInput!): Film
}Update the Resolver
const resolvers = {
Mutation: {
// ... updateWatched and deleteFilm
addFilm: (parent, { input }) => {
// Check if ID already exists to prevent duplicates
const exists = films.find(f => f.id === input.id);
if (exists) {
throw new Error("A film with this ID already exists.");
}
const newFilm = { ...input };
films.push(newFilm);
return newFilm;
}
}
};
Testing the “Add” Mutation
Enter the query into the sandbox
mutation CreateNewHammerFilm($input: CreateFilmInput!) {
addFilm(input: $input) {
id
title
year
}
}Under the query box, enter the variables JSON.
{
"input": {
"id": "70",
"title": "The Brides of Dracula",
"year": 1960,
"watched": false
}
}After running the mutation you can run the GetFilm query, which will show the resurrected film in all its glory!
query GetFilm {
film(id: 70) {
id
watched
year
}
}Why use input types?
Using an input object instead of flat arguments makes your API much more maintainable. If you decide to add a director or studio field later, you only have to update the input type, rather than changing the signature of the mutation across your entire codebase.
Why “Mutation” instead of “Query”?
While you could technically change data inside a Query resolver, it’s a major “no-go” in the GraphQL world. Using the Mutation keyword tells the server (and other developers) that this operation has side effects. It also ensures that if you send multiple mutations in one request, they run serially (one after another) to prevent data race conditions.
Conclusion
We’ve come a long way from a simple JavaScript array of my favourite films. By implementing Mutations, we’ve transformed our Hammer dataset into a functional API. We can now:
- Create new entries to keep our database growing.
- Update existing records to track our viewing progress.
- Delete entries to keep our data clean and accurate.
This “CRUD” (Create, Read, Update, Delete) cycle is the backbone of almost every application you use daily. While we are currently managing this data in local memory via a simple array, the patterns we’ve used here—Input Types, Non-Nullable arguments, and Serial Mutation execution—are the exact same patterns you would use when connecting to a production-grade database like MongoDB or PostgreSQL.
What’s Next?
Now that the backend logic is solid, the next logical step is to explore Data Persistence. In the next post, we’ll look at how to hook this GraphQL server up to a database so that our “Watched” status doesn’t disappear every time we restart the server!
Until then, happy coding!

