Developers' Blog

GraphQL 101, Part 3 — Efficient data mutation and Aliases

post-thumb

Welcome to the third part in this series on using GraphQL with the Skedulo Pulse Platform! We’ve covered accessing data and using filters, so now it’s time to cover mutation and aliases.

So, what on earth do we mean by mutation and aliases?

Mutation is simply changing (or mutating) data using GraphQL. That means we use mutation queries to create, update, and delete records in the Skedulo Pulse Platform.

What about aliases? Well, aliases allow us to perform multiple actions in one call. We give each mutation an alias (e.g job0, job1, etc) and the Pulse Platform will perform them and return the result for each one. Using aliases improves efficiency versus doing each action in a separate call. They also allow us to insert multiple related records in a single call.

For example, if we want to create both a Job and Job Allocation, we’d normally need to insert the Job first, get its UID, and then use that to insert the Job Allocation. With aliases we can do this in a single call.

We’ll talk more about aliases later. For now, let’s begin with some mutations!

Creating Records

Creating records is one of the most common mutations you will perform on the Pulse Platform, and it is very straightforward.

Here is an example of how to create a Job record:

    mutation createJob {
      schema {
        insertJobs(input: {
          RegionId: "0003ef0d-2e08-4e37-8b91-c35ccc36ad84"
          Start: "2023-01-01T08:00:00+00:00"
          End: "2023-01-01T09:30:00+00:00"
          Duration: 90
          Address: "1 Small Street, Bristol"
          Description: "New Job"
          Type: "Maintenance"
          Urgency: "Normal"
        })
      }
    }

As you can see, we use the insertJobs operation with an input containing the fields and values we want to set.

You’ll also note that we’ve called this mutation createJob. This name can be set to anything you’d like, so choose something that makes sense for what you’re doing.

Each object type has its own ‘insert’ operation, for example insertAccounts for Accounts, insertContacts for Contacts, and so on.

We can use introspection queries to get these operations, or, if you’re using an API client like insomnia, it can do this for you. We will be covering introspection in more detail in a future post, but I also touched on it in my earlier [post on GraphQL basics](https://developerblog.skedulo.com/post/220913-quick-and-easy-graphql-exploration-in-skedulo/.

In this mutation, you can see we have various fields with various data types (more on data types in part two of this series). You’ll notice a new one though: UID. This stands for ‘unique identifier’ and is simply the ID of a record.

RegionId is a Relationship (aka Lookup) field, so we need to provide a UID of a ’Region’ record in order to insert this Job. We could get this by performing a query first.

When we perform this mutation, we get the following result back:

    {
      "data": {
        "schema": {
          "insertJobs": "00145503-d82e-458a-b6df-0dd93bb08c10"
        }
      }
    }

We are provided with the UID of the record we just created, so we could use this in subsequent calls within our application.

You might be thinking to yourself, well that is great but what if I want to create two related records at the same time, for example Job and Job Allocation? Well fear not, we will be covering just that in the section on aliases and Related Records.

You can also use aliases to create multiple records in the same call!

Now that we know how to create records, let’s move on to updating!

Updating Records

Updating records is another very important and very common use case for mutations, and it is very similar to creating.

Following on from our job example above, let’s say we want to change the Job’s type and Urgency:

    mutation updateJob {
      schema {
        updateJobs(input: {
          UID: "00145503-d82e-458a-b6df-0dd93bb08c10"
          Type: "Installation"
          Urgency: "Urgent"
        })
      }
    }

The main difference this time, is we are specifying the UID of the Job and using the updateJobs operation rather than insertJobs.

We even get a similar response back from the Pulse Platform, but note that it tells us it was an update operation rather than an insert.

    {
      "data": {
        "schema": {
          "updateJobs": "00145503-d82e-458a-b6df-0dd93bb08c10"
        }
      }
    }

Now that we can create and update single records, let’s talk about how to get rid of them!

Deleting Records

What if we don’t need the Job we’ve just created and updated? Well, as you can probably guess by now we use the deleteJobs operation.

Here is an example of deleting a Job.

    mutation deleteJob {
      schema {
        deleteJobs(UID: "00145503-d82e-458a-b6df-0dd93bb08c10")
      }
    }

You will notice it differs from the previous operations, where instead of an input containing all of the fields we wish to update, we simply provide a UID.

Again we get back a similar response, including the UID of the record we just deleted. Of course this UID is now no longer valid, but it allows us to validate that the record we requested to be deleted was actually deleted.

    {
      "data": {
        "schema": {
          "deleteJobs": "00145503-d82e-458a-b6df-0dd93bb08c10"
        }
      }
    }

We’ve now covered all of the basics: creating, updating, and deleting single records. So let’s move on to how to use aliases to perform mutations on multiple records in a single call.

Using Aliases

In all of the previous examples, we were performing a mutation on a single record. This is useful if you are building a simple form or similar, where you may only need to handle one record at a time.

But what if you’re building something more complex? Of course, you could make multiple calls, but this isn’t very efficient.

Luckily, GraphQL has you covered with aliases. We can use these to perform multiple mutations in a single call.

Let’s take a look at how this works.

    mutation updateMultipleJobs {
      schema {
        job0: updateJobs(input: {
          UID: "00146e2f-c8db-4593-adc2-084abc866785"
          Duration: 60
        })
        job1: updateJobs(input: {
          UID: "0014586b-3fa3-4f74-a5b1-a47f22a4b3a2"
          Duration: 60
        })
        job2: updateJobs(input: {
          UID: "001419d8-ea58-40d8-8fc9-7e5e114af0e0"
          Duration: 60
        })
      }
    }

This mutation looks quite similar to the previous updateJobs example, but notice how under the schema key, we have now got multiple updateJobs operations, each one with its own key (e.g job0, job1).

These keys are aliases, and they allow us to perform multiple actions in a single mutation. We have to provide the keys to the GraphQL API, and they must be unique to that transaction. They will be returned by the Pulse Platform when making the API call.

For example, we’d get this response for the above mutation:

   {
     "data": {
       "schema": {
         "job0": "00146e2f-c8db-4593-adc2-084abc866785",
         "job1": "0014586b-3fa3-4f74-a5b1-a47f22a4b3a2",
         "job2": "001419d8-ea58-40d8-8fc9-7e5e114af0e0"
       }
     }
   }

As you can see, we get a map of our provided alias to the record’s UID. Just like in the single calls we covered earlier, we can use these returned UID’s to perform further actions.

The cool thing about aliases is that we can perform different actions in a single call. Taking a look at the below example, we are inserting a job, updating two jobs, and deleting one.

    mutation createUpdateDeleteJobs {
      schema {
        job0: updateJobs(input: {
          UID: "00146638-4614-41e5-8312-e241d1871bea"
          Description: "updated from a single call"
        })
        job1: updateJobs(input: {
          UID: "00149d62-2ce9-40ff-a705-0db466225f92"
          Description: "me too!"
        })
          job2: insertJobs(input: {
          RegionId: "0003ef0d-2e08-4e37-8b91-c35ccc36ad84"
          Start: "2023-01-01T08:00:00+00:00"
          End: "2023-01-01T09:30:00+00:00"
          Duration: 90
          Address: "1 Small Street, Bristol"
          Description: "i was also created!"
          Type: "Maintenance"
          Urgency: "Normal"
        })
         job3: deleteJobs(UID: "00146a22-c4c2-4d1b-b70a-31cdb7949ba3")
      }
    }

When we make this call, we get the following response back from the Pulse Platform:

    {
      "data": {
        "schema": {
          "job0": "00146638-4614-41e5-8312-e241d1871bea",
          "job1": "00149d62-2ce9-40ff-a705-0db466225f92",
          "job2": "001451bc-454d-41ab-ae24-2b3a75c628ff",
          "job3": "00146a22-c4c2-4d1b-b70a-31cdb7949ba3"
        }
      }
    }

This tells us that we successfully performed three different operations on four records. Neat, huh?

This leads us to the obvious question: “What if I want to create multiple related records in a single call? Well, GraphQL has got your back! We can use aliases and idAlias to do just that.

Now that we’ve got all the pieces to insert, create, or delete records, and perform multiple operations in one call, let’s link it all together (pun intended) to create multiple related records.

The final piece of the puzzle is idAlias. This is a value we pass to the operation (e.g insertJobs) giving GraphQL a way to reference the record we intend to create before it is created.

We then use that within the same mutation to tell the related records which of the newly created records they should be related to.

Looking at the example below:

    mutation createJobsWithAllocations {
      schema {
        job0: insertJobs(input: {
          RegionId: "0003ef0d-2e08-4e37-8b91-c35ccc36ad84"
          Start: "2023-01-01T08:00:00+00:00"
          End: "2023-01-01T09:30:00+00:00"
          Duration: 90
          Address: "1 Small St, Bristol"
          Description: "fun with idAlias"
        } idAlias: "NEW_JOB_ID0")
       ja0: insertJobAllocations(input: {
          ResourceId: "0005f801-7a9c-40fe-8933-7886e0441e84"
          JobId: "NEW_JOB_ID0"
          Status: "Pending Dispatch"
        })
      }
    }

This looks a lot like what we did in the previous section, but with one very important difference.

We provide both an input and idAlias to the operation. As you can see, we’ve specified idAliasas “NEW_JOB_ID0” in ourinsertJobsoperation. Then, in our insertJobAllocations` operation, rather than providing a UID in the “JobID” field (like we’re doing for “ResourceId”), we’re providing that exact same idAlias.

This tells GraphQL how to link up the records we’re creating, allowing us to insert both of them in a single call. It really is that simple!

We get the following back from the Pulse Platform, telling us that both our Job and Job Allocation records have been successfully created:

    {
      "data": {
        "schema": {
          "job0": "001433c3-0729-437f-998c-9384a5c6ecd3",
          "ja0": "0018972f-ac70-4598-ad40-2fca8b88ba09"
        }
      }
    }

Just like with aliases, we need to generate our own idAlias values, and they must be unique within a transaction.

Conclusion

We’ve now covered how to perform data mutations, and make them as efficient as possible by using aliases and even being able to insert multiple related records in a single call. In part four, we will cover working at scale using batch processing!

As always, we’d love to hear about what you’re building on the Skedulo Pulse Platform so please reach out to us on Twitter @SkeduloDevs or LinkedIn!

References

comments powered by Disqus