Anatomy of a Mutation (Apollo GraphQL)
Today I wanted to write up a quick post about GraphQL mutations.
What is a Mutation?
Mutations are like queries, but they are called mutations. Thats it. Funny, you can probably write a query with a side-effect in the resolver. But, since there IS a difference between these concepts in GraphQL, we should keep Mutations separate from Queries.
Here’s a cheat code: Anything that changes data e.g. database altering events, is a Mutation.
You’ve seen the type Query, now we will add a type Mutation.
What does a Mutation look like?
In Apollo it’s quite simple:
Our Root Schema, passed along to our Apollo Server, will now have definitions for mutations our clients can call. When receiving these mutations, our server will resolve these calls just like a Query.
Let’s take a look at the resolver for submitRepository.
Once again, the mutation syntax points to a resolver of the same name. This resolver is just a function. Yes. Just a plain old function. We leverage this function to make the change we need.
What are the parameters?
So we have some positional arguments here, but what you need to know in order to be successful with resolvers is that the param structure reads like this:
“ROOT” to be honest, I have never used this parameter for anything in my GraphQL career. And don’t really know what it’s used for. Community chime in so I have something to write here!
“YOUR_PARAMS” represent the parameters of the Mutation designated in the rootSchema. Most of the time you will be deconstructing these params for more readable code.
“CONTEXT” is an object that can bind data you want to send with every request. e.g. user information for permissions checks and security.
Resolvers have 2 use cases.
For Queries, resolvers are tools for fetching and transforming data for consumption by Web/Native clients.
For Mutations, resolvers are tools for changing data from the Web/Native clients.
In the example, our Mutation for submitRepository uses the “context” to hold APIs. This is optional and not necessarily the only way to do this. You can still resort to importing your APIs from modules and use them directly in your resolvers.
Also, in our example above, you can see we are doing our Mutation, and returning the Entry to our clients as a response to this Mutation. You can then power UI based on this Entry going forward.
What about Optimistic UI?
The great thing about Apollo Client is it’s forward thinking design. From experience, we needed a way to optimistically update data already fetched in the store with the results of our Mutations. Thanks to Slava Kim and David Woody Apollo Client now gives users the tools to keep updates to the store as efficient as possible while keeping re-renders at a minimum.
Here is a link to Slava’s post about this here.
The Anatomy of Optimistic UI
I wanted to take some time and explain what this diagram doing, because to a beginner in Server/Client development this may be a little daunting.
- EVERYTHING BEGINS AND END WITH THE USER. They are the power driving mutations through their interface, and they are the ones expecting the side effects of those mutations reflective in the views they are interacting with.
- The flow is as Unidirectional as possible. Much like the paradigms of Flux, this flow moves in one way starting from the User to the Server then back to the user.
- An Optimistic Response is an illusion. Programmers are magicians, and thus we THINK we know that you know what you just mutated. So what we do in optimistic scenarios is give you what you thought was going to happen. A perfect example is adding a post to a list of posts. You are the author of the post in question, so our optimistic response is taking this post and adding it to the list right away. Why? So this looks like our website is super fast, and the user gets INSTANT feedback on actions they take in the system.
- The Server is the source of truth. You can see once the Optimistic Response is sent to the User’s view, the server takes the same request and goes through its processing. Once its ready to reaffirm the client that what it has is correct, it jumps over the latency divide and updates the store. Most of the time, the user will not notice a change. But there will be instances that the server may have a more complete view of the world and will update the optimistic response with the truth. Bottom line, design systems that provide the least amount of judder to the user. Keep optimistic responses similar to the latency bound response.
- All of this is possible because Redux is awesome. Shameless plug.
This was pretty much a some random ramblings about GraphQL Mutations. As you can see, and I’ve been trying to stress in all my posts, Mutations/Queries are just pointers to some function. They’re super harmless and easily approachable! So let’s get this going and start using Apollo today!