How to Use GraphQL Mutations and Queries

In this lesson, we'll look to mimic the listings retrieval and manipulation we had in our Express RESTful API but with GraphQL instead.

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

Querying and mutating listings data with GraphQL

📝 This lesson's quiz can be found - here.
🗒️ Solutions for This lesson's quiz can be found - here.

We've created a simple GraphQL Schema with which our root level query and mutation object types each have a single hello field that returns a string message when queried. We'll now look to mimic the listings retrieval and manipulation we had in our REST API with GraphQL.

Listing Object Type

The first thing we'll do is create a custom Listing object type. The Listing object type is to reference the listing type that is to be returned from our soon to be query and mutation. We'll use the GraphQLObjectType class to construct this type in the src/graphql.ts file.

The Listing type is to contain a series of fields that represent a listing.

const Listing = new GraphQLObjectType({
  name: "Listing",
  fields: {
    id: {},
    title: {},
    image: {},
    address: {},
    price: {},
    numOfGuests: {},
    numOfBeds: {},
    numOfBaths: {},
    rating: {}
  }
});

We'll need to define the types of each of the fields within Listing.

GraphQLID

GraphQL provides a unique scalar type for ID's, GraphQLID. The GraphQLID scalar type is to represent a unique identifier however it behaves and gets serialized as a String. Its main purpose is to convey that a field is to be a unique identifying field. We'll import the GraphQLID type and use it as the type of the id field.

import {
  // ...
  GraphQLID
} from "graphql";

const Listing = new GraphQLObjectType({
  name: "Listing",
  fields: {
    id: { type: GraphQLID }
    // ...
  }
});

GraphQLString

The title, image, and address fields of Listing are expected to be strings so we'll define their types with the already imported GraphQLString scalar type.

import {
  // ...
  GraphQLString
} from "graphql";

const Listing = new GraphQLObjectType({
  name: "Listing",
  fields: {
    // ...
    title: { type: GraphQLString },
    image: { type: GraphQLString },
    address: { type: GraphQLString }
    // ...
  }
});

GraphQLInt

The price, numOfGuests, numOfBeds, numOfBaths, and rating fields of Listing are expected to be integers so we'll define their types with the GraphQLInt type.

import {
  // ...
  GraphQLInt
} from "graphql";

const Listing = new GraphQLObjectType({
  name: "Listing",
  fields: {
    // ...
    numOfGuests: { type: GraphQLInt },
    numOfBeds: { type: GraphQLInt },
    numOfBaths: { type: GraphQLInt },
    rating: { type: GraphQLInt }
  }
});

For floating-point numbers (i.e. numbers with decimals), GraphQL provides the GraphQLFloat scalar type.

Our Listing object will now look like the following:

const Listing = new GraphQLObjectType({
  name: "Listing",
  fields: {
    id: { type: GraphQLID },
    title: { type: GraphQLString },
    image: { type: GraphQLString },
    address: { type: GraphQLString },
    price: { type: GraphQLInt },
    numOfGuests: { type: GraphQLInt },
    numOfBeds: { type: GraphQLInt },
    numOfBaths: { type: GraphQLInt },
    rating: { type: GraphQLFloat }
  }
});

It might be apparent that the types we specify here mimic the Listings TypeScript interface created in the src/listings.ts file.

As a reminder, TypeScript is the extension we're using to type check and reinforce our development code.

GraphQL is a typed query language for APIs so we have to define the types of the fields in our schema. There are open-source tools (e.g. GraphQL Code Generator) that help in generating TypeScript types from GraphQL schemas, but they add a layer of complexity so we won't be using them for our server code. We'll investigate how we can generate TypeScript types from a GraphQL schema when we work on the client portion of our app.

GraphQLNonNull

We'll take the type definitions for the fields in the Listing object type another step. We want all our fields in the Listing type to never be null and to always be defined. We can achieve this by using the GraphQLNonNull wrapper.

GraphQLNonNull is a type marker that enforces values are never null and will ensure an error is thrown if this ever occurs. Let's import the GraphQLNonNull wrapper in our src/graphql.ts file.

import {
  // ...
  GraphQLNonNull
} from "graphql";

We'll wrap every field type in Listing with the GraphQLNonNull wrapper which will make our Listing object type appear as follows:

server/src/graphql.ts
const Listing = new GraphQLObjectType({
  name: "Listing",
  fields: {
    id: { type: GraphQLNonNull(GraphQLID) },
    title: { type: GraphQLNonNull(GraphQLString) },
    image: { type: GraphQLNonNull(GraphQLString) },
    address: { type: GraphQLNonNull(GraphQLString) },
    price: { type: GraphQLNonNull(GraphQLInt) },
    numOfGuests: { type: GraphQLNonNull(GraphQLInt) },
    numOfBeds: { type: GraphQLNonNull(GraphQLInt) },
    numOfBaths: { type: GraphQLNonNull(GraphQLInt) },
    rating: { type: GraphQLNonNull(GraphQLFloat) }
  }
});

Root query and GraphQLList

We'll now modify our root Query object to have a field that will allow us to return an array of listing objects from the mock listings array we have in our app. We'll rename the hello field in our query object to a listings field responsible in returning a list of listings.

const query = new GraphQLObjectType({
  name: "Query",
  fields: {
    listings: {}
  }
});

The listings query field is expected to be a list of Listing items. Since we expect this field to be a list, we'll need to use the GraphQLList definition.

GraphQLList is a type wrapper that indicates a list is to be created for a particular type. Let's import the GraphQLList type.

This lesson preview is part of the The newline Guide to Building Your First GraphQL Server with Node and TypeScript course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to The newline Guide to Building Your First GraphQL Server with Node and TypeScript, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

Thumbnail for the \newline course The newline Guide to Building Your First GraphQL Server with Node and TypeScript
  • [00:00 - 00:17] We have a simple GraphQL schema in which our query and mutation root object types have a single hello field that returns a simple string message when quer ied. Let's mimic the listings retrieval and manipulation we had in our REST API into this GraphQL schema.

    [00:18 - 00:29] The first thing we'll look to do is create a custom listing object type. This object type is to reference the listing type that is to be returned from our soon-to-be query and mutation.

    [00:30 - 00:42] We'll use the GraphQL object type class to construct this type. The listing type is to contain a series of fields that represent the listing.

    [00:43 - 00:59] The ID field, title, image, address, price, number of guests, number of beds, number of baths, and the rating. We're going to need to define the types of each of the fields here.

    [01:00 - 01:12] GraphQL provides a unique scalar type for IDs, GraphQL ID. We'll import the GraphQL ID type and use it as the type of the ID field.

    [01:13 - 01:22] This ID scalar type is to be used to represent a unique identifier. However, it actually behaves and gets serialized as a string.

    [01:23 - 01:33] Its main purpose is to convey that this field is to be a unique identifying field. Title, image, and address are expected to be strings.

    [01:34 - 01:51] So we'll define their types with the already imported GraphQL string scalar type. Price, number of guests, number of beds, number of baths, and rating are to be whole numbers, or in other words, integers.

    [01:52 - 02:06] We'll define their types with the GraphQL integer scalar type that we'll import . An interesting point to make, GraphQL actually provides another type for floating point numbers, or numbers with decimals.

    [02:07 - 02:23] And that is the GraphQL float scalar type, though we won't use that here. Now you may be realizing that the types we're defining here actually mimic the listings TypeScript interface we've set up in the listings file.

    [02:24 - 02:37] As a reminder, TypeScript is the extension we're using to type check and reinforce our development code. GraphQL is also a type language, and it's a type language for APIs.

    [02:38 - 02:53] So we have to define the types of the fields we create in our GraphQL schema. Now there are open source tools that help in generating TypeScript types from GraphQL schemas, but they add a layer of complexity, so we won't talk about them just yet.

    [02:54 - 03:13] We want to take the type definitions for the fields in this listing object type , another step. We want all our fields in the listing type to never be null, and to always be defined as the type specified in the fields here.

    [03:14 - 03:41] With the GraphQL library, we can do this by importing the GraphQL none null marker, and wrapping each type with the marker. This tells our schema that these fields must enforce these types, and if not, an error will be thrown.

    [03:42 - 03:59] Now let's modify our query root object to have a field that will allow us to return an array of listing objects from the mock listings array we have in our app. We will rename the hello field in our query to be the listings field responsible for this.

    [04:00 - 04:21] Since we expect this field to be a list, we'll need to import and use the Graph QL list definition. The GraphQL list definition expects an argument of the item we expect in the list, so we'll place the custom listing object type within.

    [04:22 - 04:48] We also want the type of element being iterated in the list to never be null, so we'll wrap it with the GraphQL none null wrapper. We also don't want the list listings type itself ever being null, so we'll wrap the whole type with the GraphQL none null wrapper as well.

    [04:49 - 05:05] A little verbose, but it does what we intended to do. For this field to return a defined list that has a defined set of listing items , we are expected to use the wrapper twice.

    [05:06 - 05:23] We'll now import the listings of mock array from the listings file, and have it simply be returned in our listings field resolve function. The listings field when queried will now return the list of listings.

    [05:24 - 05:43] We'll now modify our mutation objects to have a delete listing field, where a listing can be deleted and the deleted listing object is expected to be returned. On that note, we'll say the type of the new delete listing field is listing, and it can't be null.

    [05:44 - 05:57] We'll also remove the prior return of the resolve function for now. For our delete listing mutation, we expect to receive the ID of a listing that is to be deleted.

    [05:58 - 06:16] As a result, we'll introduce a new field option here labeled "args", "arguments ", that dictates the fields that is to be passed in as arguments. We'll declare an ID argument, and specify its type as "graphqlid".

    [06:17 - 06:30] In addition, we'll say that this argument can't be null, so we'll wrap it with the "graphql-none-null" type. As we've discussed before, resolvers have access to up to four arguments.

    [06:31 - 06:42] With this field resolver, we're only interested in accessing the arguments this field will receive. So we'll define the first two arguments of this resolver function.

    [06:43 - 06:54] We'll label the first object argument as "root" to convey that it's the "root object passed to our root object type". And we'll prefix it with underscore since it's to be unused.

    [06:55 - 07:15] We'll then destruct the ID value from the arguments payload. Our resolver function would now do the same as we've had before in our RESTful API, and I'll simply look to remove the appropriate listing from the listings collection while returning the removed listing.

    [07:16 - 07:32] We'll use a for loop, and we'll use the splice method to help remove the appropriate listing. One difference here is that we're not using the response.send function any longer, and we either simply return the splice listing or we throw an error.

    [07:33 - 07:43] The other difference is in this particular case, we're interested in returning a listing object. The splice function returns an array of the spliced items.

    [07:44 - 07:55] So in this case, we're being a little bit more particular, and saying since we have an array of a single item, we want to return the first item of the data array, which is essentially a symbol of the list. And we'll also use the list item that has been deleted.

    [07:56 - 08:10] Note that the root and ID arguments don't have appropriate types right now. We'll discuss this in the next lesson as we change how we're creating our Graph QL schema, but we'll stop here for now.

    [08:11 - 08:19] Our schema is appropriately set up with the express application, so there's nothing else we'll need to do. We'll head to the terminal and start our server.

    [08:20 - 08:38] We'll then head over to the GraphQL Playground at localhost9000/api, refresh it if we have it open, and then we'll look through the Playground documentation. We can see the newly added fields in our query and mutation object types.

    [08:39 - 08:52] And when we look at the listing type that is to be returned, we can see all the fields and the expected types of each field within the listing type. Notice how a description isn't being shown for the custom listing type?

    [08:53 - 09:05] We can introduce a definition by simply declaring a description option in our GraphQL object type constructor. Now, let's look to query the listings field.

    [09:06 - 09:20] At first, we'll simply query just the ID and title fields within the listing. After pressing play, we'll see a list of IDs and titles from the listings data in our listings mock array.

    [09:21 - 09:32] How about if we change our query and introduce more fields, like the price and address? By pressing play again, we get the updated fields we're trying to query.

    [09:33 - 09:47] This is one of the main powers of GraphQL. We're now able to query whatever fields we want to perform our API. We'll now try to delete a listing with a delete listing mutation.

    [09:48 - 10:01] We'll change the keyword that we have on the left-hand side to mutation, and we 'll specify the delete listing mutation field. We'll then pass in an ID argument and provide a value of one of the IDs of our mock listings array.

    [10:02 - 10:11] We'll say 001. Here, we can then return what information we'd want of the deleted listing. We 'll say ID and title.

    [10:12 - 10:24] After pressing play, we'll get the deleted listing back returned to us. If we attempt to query the listings again, we'll see that the first listing object is now officially gone.

    [10:25 - 10:37] Amazing. This shows one of the powers of GraphQL. We're not interacting with two end points that act as separate resources, like a restful route.

    [10:38 - 10:52] Instead, we're making the query and mutation from the same API endpoint. In this lesson, we learned how to create a GraphQL schema by manually creating custom object types using the constructors provided by the GraphQL library.

    [10:53 - 11:07] However, you may have noticed how defining the schema this way started to become quite verbose very quickly. And as our schema inevitably grows bigger when we move on to our production app , our schema will become harder to understand and debug.

    [11:08 - 11:25] Well, there is a different way to define a GraphQL schema, and we can see this when we actually click the schema documentation tab in our GraphQL playground. Here, this is known as the GraphQL schema language, which is a syntax easier to understand when creating and reading schemas.

    [11:26 - 11:31] In the next lesson, we'll see how we can recreate the schema we have with this syntax. Thanks.

    [11:32 - 11:38] 10-1-2-7-1-2-3-4.