GraphQL Mutation Basics

Learn the basics of writing mutations using GraphQL

GraphQL mutations take on all the same benefits and efficiencies as queries mentioned in the GraphQL query basics.

Let's look at some of the basics of constructing a mutation in GraphQL. We'll connect to both Fauna and SendGrid as examples.

Getting Set Up

The Fauna GraphQL API is a serverless web-native GraphQL API providing an easily accessible way to explore many of GraphQL's transactional features.

Setup Fauna Database

Go to Fauna.com and click Sign Up. You will be taken to the Fauna dashboard.

01-fauna-dashboard

Create Database

Create a new database in Fauna named stepzen-fauna. Use the "Classic" region group and be sure to check the "Use demo data" option.

02-create-database

Once the database is created, open the GraphQL menu option within the Fauna Dashboard. You'll need the HTTP authorization header at the bottom of the Playground to use in your config.yaml file.

04-http-headers

On your local machine, create a working directory for your StepZen project and place a config.yaml file in the folder with the following contents (replacing Basic MY_FAUNA_KEY with the information you just copied from the GraphQL Playground in the Fauna dashboard.

configurationset:
  - configuration:
      name: fauna_config
      Authorization: Basic MY_FAUNA_KEY

Next, we need to create our GraphQL schema code that builds our API within StepZen.

Types, inputs and queries

Next, create a file named fauna.graphql within the local working directory containing your config.yaml.

types represent the objects we expect to get in response to the query. For instance, the sample data that Fauna provides has a store that has an address, these are represented by the Store and Address types below. The properties of each match the data that we'll retrieve when querying these types in our Fauna backend.

inputs are the arguments passed into the mutations to specify what to send to Fauna. For example, the StoreInput will be passed to a mutation and contains the name and address properties of a Store that we want to add or update. The Query type will contain our queries to retrieve data from the backend.

type Store {
  _id: ID!
  name: String!
  address: Address
}

type StorePage {
  data: [Store]!
  after: String
  before: String
}

type Address {
  street: String
  city: String
  state: String
  zipCode: String
}

input AddressInput {
  street: String
  city: String
  state: String
  zipCode: String
}

input StoreInput {
  name: String!
  address: AddressInput
}

type Query {
  findStoreByID(
    id: ID!
  ): Store
    @graphql(
      endpoint: "https://graphql.fauna.com/graphql"
      configuration: "fauna_config"
    )

  allStores: StorePage!
    @graphql(
      endpoint: "https://graphql.fauna.com/graphql"
      configuration: "fauna_config"
    )
}

Add this code to your fauna.graphql.

Mutation Type

Within GraphQL, the Mutation type is specifically designed for any transactions that will modify data. Let's create a type Mutation with the following mutations: createStore, updateStore, and deleteStore.

type Mutation {
  createStore(data: StoreInput!): Store!
  updateStore(id: ID!, data: StoreInput!): Store
  deleteStore(id: ID!): Store
}

At this point, our mutations won't do anything since they are not connected to a backend. Let's fix that.

Each mutation will need an endpoint. Since we're connecting with the Fauna backend via its GraphQL API, we'll specify https://graphql.fauna.com/graphql. The configuration referes to the configuration we created earlier within our config.yaml file that we named fauna_config. This passes in the authorization that we need to work with the Fauna API.

type Mutation {
  createStore(
    data: StoreInput!
  ): Store!
    @graphql(
      endpoint: "https://graphql.fauna.com/graphql"
      configuration: "fauna_config"
    )

  updateStore(
    id: ID!
    data: StoreInput!
  ): Store
    @graphql(
      endpoint: "https://graphql.fauna.com/graphql"
      configuration: "fauna_config"
    )

  deleteStore(
    id: ID!
  ): Store
    @graphql(
      endpoint: "https://graphql.fauna.com/graphql"
      configuration: "fauna_config"
    )
}

Add these mutations to the end of our fauna.graphql file. The last thing we need is to create an index.graphql file within the same working directory with the following contents that tells StepZen how to assemble our schema. We only have one schema file at the moment.

schema @sdl(files: ["fauna.graphql"]) {
  query: Query
}

To upload and deploy this schema to your StepZen account, open a command prompt and run stepzen start. You'll need to have the StepZen CLI installed and configured. See the documentation for installing and configuring the CLI if you do not already have it installed.

Create a store with CREATE_STORE

Now we're ready to test our mutations. Running stepzen start should have opened a GraphiQL editor in your browser. Enter the following mutation into the query editor.

mutation CREATE_STORE {
  createStore(data: {
    name: "Fake Store",
    address: {
      street: "123 Fake Street",
      city: "Washington",
      state: "DC",
      zipCode: "12345"
    }
  }) {
    name
    _id
    address {
      city
      state
      street
      zipCode
    }
  }
}

The response will return the store data, including the ID, for the store we just inserted.

{
  "data": {
    "createStore": {
      "_id": "305411426543992901",
      "address": {
        "city": "Washington",
        "state": "DC",
        "street": "123 Fake Street",
        "zipCode": "12345"
      },
      "name": "Fake Store"
    }
  }
}

Search for a store with FIND_STORE_BY_ID

Let's use the ID to query the information about the store we just created. Copy the id of the new store and paste it between the quotes in id: "NEW_STORE_ID".

query FIND_STORE_BY_ID {
  findStoreByID(id: "NEW_STORE_ID") {
    _id
    name
    address {
      street
      city
      state
      zipCode
    }
  }
}

Update the name of the store with UPDATE_STORE_NAME

Next, let's use the same store id, pasting it between the quotes in id: "NEW_STORE_ID", to update the store's data in Fauna.

mutation UPDATE_STORE_NAME {
  updateStore(
    id: "NEW_STORE_ID"
    data: {
      name: "Updated Fake Store"
    }
  ) {
    name
    _id
  }
}

We will get the updated store's name and ID in the response.

Delete the store with DELETE_STORE

Finally, let's use the same store id, pasting it between the quotes in id: "NEW_STORE_ID", to delete the store we just created and edited.

mutation DELETE_STORE {
  deleteStore(id: "NEW_STORE_ID") {
    _id
    name
  }
}

We will get the ID and name of the store we just deleted in the response.

Sendgrid Example

Now that we've covered the basics of how mutations work and how to set them up in StepZen, let's look at another example. The Sendgrid Email Rest API can be written into a GraphQL schema with mutations using StepZen.

Setup Sendgrid Account

Go to SendGrid.com and click Start for Free. You will be taken to the SendGrid dashboard.

Create Sendgrid Api Key and Template

Go to Settings > API Keys and select Create API Key.

sendgrid_create_key

Create a local working directory for your StepZen schema code. Copy the API Key and add it to a config.yaml file as below.

sendgrid_api_key

configurationset:
  - configuration:
      name: sendgrid_config
      Authorization: Bearer xxxx

Go to Email API > Dynamic Templates and Create a Dynamic Template

sendgrid_create_template

Note the ID of the template (see "Template ID" in the image above). You'll need this later.

Types and queries

Create a sendgrid.graphql file in your working directory. Within that file, we'll define the types and queries that we'll be interacting with on the SendGrid API.

type Email @mock {
  message: String
}

type Template {
  id: String!
  name: String!
  generation: String
  updated_at: String
}

type Query {
  template(id: ID!): Template
    @rest (
      endpoint: "https://api.sendgrid.com/v3/templates/$id"
      configuration: "sendgrid_config"
    )
}

Note the @mock directive on the Email type. This returns mock data. The SendGrid API does not return any body in the response when using it to send an email. GraphQL mutations always include some sort of response. We've added mock data so that the response doesn't come back null.

Finally, create an index.graphql file in the working directory with the following contents:

schema @sdl(files: ["sendgrid.graphql"]) {
  query: Query
}

Run stepzen start and add the unique id from the template you created in SendGrid to the following query.

query MyQuery {
  template(id: "d-771bf0b7b67f4396a35da33a340acbb6") {
    generation
    id
    name
    updated_at
  }
}

You should get a response similar to the following. Now you know the SendGrid API is successfully querying the template.

{
  "data": {
    "template": {
      "generation": "dynamic",
      "id": "d-771bf0b7b67f4396a35da33a340acbb6",
      "name": "Welcome Email",
      "updated_at": "2021-06-29 22:16:21"
    }
  }
}

Mutation Type

Next, let's add a mutation that will send an email via SendGrid's API.

type Mutation {
	sendTemplatedEmail(to: String!, from: String!, template_id: String!): Email
}

The mutation method is POST to the endpoint, https://api.sendgrid.com/v3/mail/send. We need to send the body through the postbody field that follows the template email example in the SendGrid docs. The configuration is set to the sendgrid_config that we defined in our config.yaml to securely send the API key.

The postbody can seem overwhelming, but we are url encoding the three arguments, to, from, and template_id into the fields expected by the REST API by using a \"{{.Get \"from\"}}\" structure to properly add the quotes around the values.

type Mutation {
	sendTemplatedEmail(to: String!, from: String!, template_id: String!): Email
		@rest(
		method: POST
        endpoint: "https://api.sendgrid.com/v3/mail/send"
		postbody: "{\"personalizations\": [{\"to\": [{\"email\": \"{{.Get \"to\"}}\"}]}],\"from\": {\"email\": \"{{.Get \"from\"}}\"},\"subject\":\"demo\",\"content\": [{\"type\": \"text/html\",\"value\": \"Heya!\"}], \"template_id\" : \"{{.Get \"template_id\"}}\"}"
		configuration: "sendgrid_config"
		)
}

Send an Email using sendTemplatedEmail

Now that our mutation is written, let's test it out within the GraphiQL editor that launched when we ran stepzen start.

mutation MyMutation {
  sendTemplatedEmail(
    from: "example@stepzen.com"
    template_id: "d-6d5704f9a5c9424d9c67a226c8fa2b43"
    to: "example@stepzen.com"
  ) {
    message
  }
}

As we noted earlier, you can see in the response below that SendGrid does not send a success message in response, so for now we're just returning mock data. If you want to set up response data, you'll set up a webhook on SendGrid.

{
  "data": {
    "sendTemplatedEmail": {
      "message": "Vestibulum lacinia arcu eget nulla"
    }
  }
}

Even though we are getting mock in the response, we'll still see the email in the recipients inbox that was sent to the to field in the mutation!

email_in_inbox

Where To Go Next

If you are looking for more details, we recommend the following resources:

This site uses cookies: By using this website, you consent to our use of cookies in accordance with our Website Terms of Use and Cookie Policy.