This video is available to students only

Querying and mutating listings data with GraphQL

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

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.

import {
  // ...
  GraphQLList
} from "graphql";
No discussions yet