A walk in GraphQL — Mutations — Day 4

8 articles to learn GraphQL incrementally, keeping the implementation agnostic spirit of the SDL

Javier Valderrama
5 min readMay 21, 2021

Mutation

What is CRUD without CUD huh?!! In a REST-full API you have specific HTTP Verbs (like PUT) to create and/or update a resource, in GraphQL —strictly talking— you don’t. Queries and Mutations are more similar to POST and GET in the aspect that nothing stops you from producing data side-effects through a query or a mutation even though they are —respectively— designed to have significant differences on their behavior.

Let’s compare them.

( 0 _ 0 ) SAY AGAIN?!

If the operation is a mutation, the result of the operation is the result of executing the mutation’s top level selection set on the mutation root object type. This selection set should be executed serially.

It is expected that the top level fields in a mutation operation perform side‐effects on the underlying data system. Serial execution of the provided mutations ensures against race conditions during these side‐effects.

Source: GraphQL Spec (June 2018) — Mutation

That makes total sense.

Normally the executor can execute the entries in a grouped field set in whatever order it chooses (normally in parallel). Because the resolution of fields other than top‐level mutation fields must always be side effect‐free and idempotent, the execution order must not affect the result, and hence the server has the freedom to execute the field entries in whatever order it deems optimal.

When executing a mutation, the selections in the top most selection set will be executed in serial order, starting with the first appearing field textually.

When executing a grouped field set serially, the executor must consider each entry from the grouped field set in the order provided in the grouped field set. It must determine the corresponding entry in the result map for each item to completion before it continues on to the next item in the grouped field set.

Source: GraphQL spec (June 2018) — Normal and Serial Execution

For example:

A valid GraphQL executor can resolve the query in whatever order it considers optimal including parallel (normal execution):

  • Run ExecuteField() for buckLanders or shireLanders normally, which during CompleteValue() will execute the { id name } sub‐selection set normally.
  • Run ExecuteField() for the remaining field (buckLanders or shireLanders), which during CompleteValue() will execute the { id name } sub‐selection set normally.

Even though the execution order cannot be determined a priori, the response can be, and it’ll reflect the lexical order of the query (as shown below). This response will be returned once all operations are completed.

As opposite to queries, in the following example of a mutation we’ll see a completely different behavior:

A valid GraphQL executor MUST resolve the mutation selection set SERIALLY:

  • Resolve the moveKindToHomeland(input: { kind: HOBBIT, homeland: "Buckland" }) field
  • Execute the { id name } sub‐selection set of makeEmBuckLanders normally
  • Resolve the moveKindToHomeland(input: { kind: HOBBIT, homeland: "The Shire" }) field
  • Execute the { id name } sub‐selection set of makeEmShireLanders normally

A correct executor must generate the following result for that selection set:

Obviously the execution order is critical even in such a silly example. All ShireLanders where moved to Buckland first, then all BuckLanders were moved to The Shire and they had one beer each one at the Green Dragon back and forth. If the execution order wasn’t predictable and respected, the owner wouldn’t know beforehand if the minimum available stock should be 11 or 10 for this operation, but that’s another story … is it? … nope, that’s exactly the point.

So far so good? Now, if you were attentive you might have noticed the following:

GraphQL spec determines only top‐level mutation fields to be executed serially; that means every nested field level will be executed normally!!!!

… what if we define all operations to use a single entity? (not saying this is a right or wrong approach, it’s just a possibility)

( ´◔ ω◔`) Can you spot the problem here?

OOPS! There’s absolutely no guarantee the create field is executed before update, GraphQL won’t do it for you. There are plenty of solutions and it’ll depend on the language, architecture, underlying data system, etc. The important thing is that you’re aware of this and design your solutions accordingly.

Exercise

For a given datasource (abstracted as json here) containing n rows of skills and n rows of persons we provided a sample implementation of a GraphQL server for each technology containing:

  • a server app
  • a schema
  • a resolver map
  • an entity model
  • a db abstraction

The code contains the solution for previous exercises so you can have a starting point example.

Exercise requirements

  • Update the type definition and the resolvers to be be able to perform the mutation operations listed below (can you provide other sample mutations when your code is completed?).
  • Discuss with someone else which would be the best way to use Input Objects here.
  • You’ll notice something about the new IDs, it’s a good opportunity to ask, discuss and investigate the reasons behind the change.
  • May the variable definitions be with you …. oops sorry :) , let the variable definitions in both operations help you with the Schema definition.

Operations list

NOTES:

  1. There are many topics around mutation bests practices, optimizations, “do’s and don’ts”; some are excellent, all of them way beyond the scope of this stage of the course (we might get there), some super detailed and precise, some fuzzy or inaccurate. Usually the rule of thumb for finding this kind of info is “first the authors, then the SMEs (subject matter expert), then the official community, then the rest”, e.g. Apollo has a huge community and a YouTube channel where actual Apollo engineers — and even the creators of GraphQL, like Lee Byron — do conferences and share tons of invaluable insights related to the technology itself and the engineering decisions you’ll have to make on top and under GraphQL’s layer.
  2. Whenever you struggle finding the root cause of a problem whilst working with GraphQL step aside and ask you this question: « Is this a GraphQL problem? » MOST of the time the answer is NO, it’s about engineering and probably related to a non-graph state of mind; you might be still thinking in REST.

Technologies

Select the exercise on your preferred technology:

Learning resources

GraphQL Spec (June 2018)

GraphQL Org

How to GraphQL

Other articles

A walk in GraphQL Series at Medium

Github Pages

A Walk in GraphQL

Collaborators

  • Ezequiel Alvarez — @ealvarezk
    Reviewer
  • Ezequiel Tejerina — @quequitejerina
    Python exercises contributor and reviewer
  • Franco Gribaudo — @fgriba
    Java exercises contributor and reviewer
  • Cristian Buffa — @cristianbuffa & José Ignacio Aguilera — @jiaguilera
    NetCore exercises contributors and reviewers
  • Javier Valderrama — @Jaxolotl
    Author, JavaScript exercise contributor and reviewer

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Javier Valderrama
Javier Valderrama

Written by Javier Valderrama

Engineering manager, Lead Software engineer, passionate educator and community evangelist.

No responses yet

Write a response