Pets GraphQL Walkthrough Queries

Pets GraphQL Walkthrough Queries

Creating the Schema

The schema is going to hold the instructions for how we interact with our data. We start by defining the types of objects that we will be returning and then the RootQuery. The RootQuery is the entry point for a query request and will hold the directions for how to resolve the request.

Start by making the schema file.

touch lib/schema/schema.js

Next require the graphql package at the top of our file, so that we can use it to define our object types that we will be using.

const graphql = require('graphql');

Let’s start by defining the PetType.

const PetType = new GraphQLObjectType({
  name: 'Pet',
  fields: () => ({
    id: {type: GraphQLID},
    name: {type: GraphQLString},
    animal_type: {type: GraphQLString},
    breed: {type: GraphQLString},
    age: {type: GraphQLInt},
    favorite_treat: {type: GraphQLString}
  })
});

We will need to require the GraphQL datatypes from graphql, so let’s update our schema file. It should now look like this:

const graphql = require('graphql');
const {
  GraphQLObjectType,
  GraphQLString,
  GraphQLID,
  GraphQLInt
} = graphql;

const PetType = new GraphQLObjectType({
  name: 'Pet',
  //It is important that the fields is a function when we add our relationship later.
  fields: () => ({
    id: {type: GraphQLID},
    name: {type: GraphQLString},
    animal_type: {type: GraphQLString},
    breed: {type: GraphQLString},
    age: {type: GraphQLInt},
    favorite_treat: {type: GraphQLString}
  })
});

We’ve defined the PetType which is telling our user what type of information that they can ask for, but we have yet to give them a way to ask for it. Let’s do that next. We will write a query to return all our pets.

const RootQuery = new GraphQLObjectType({
  name: 'RootQueryType',
  fields:{
    pets: {
      type: new GraphQLList(PetType),
      resolve(parent, args){
        return database('pets').select()
      }
    },
  }
})

We are using another GraphQL datatype so we will want to add it to our list at the top of the page. GraphQLList will return for us a list of graphql objects. Also, since we are using our database to get back information we will also need to add that connection too. Our schema file should now look like this:

const environment = process.env.NODE_ENV || 'development';
const configuration = require('../../knexfile')[environment];
const database = require('knex')(configuration);

const graphql = require('graphql');
const {
  GraphQLObjectType,
  GraphQLString,
  GraphQLID,
  GraphQLInt,
  GraphQLList
} = graphql;

const PetType = new GraphQLObjectType({
  name: 'Pet',
  //It is important that the fields is a function when we add our relationship later.
  fields: () => ({
    id: {type: GraphQLID},
    name: {type: GraphQLString},
    animal_type: {type: GraphQLString},
    breed: {type: GraphQLString},
    age: {type: GraphQLInt},
    favorite_treat: {type: GraphQLString}
  })
});

const RootQuery = new GraphQLObjectType({
  name: 'RootQueryType',
  fields:{
    pets: {
      type: new GraphQLList(PetType),
      resolve(parent, args){
        return database('pets').select()
      }
    },
  }
});

Alright we are almost ready to check out our query, but first we need to export our schema so that our index.js file can access it. We will also need to add one last thing to our GraphQL datatypes list, GraphQLSchema.

module.exports = new GraphQLSchema({
  query: RootQuery
})

Double check that your file looks like this:

const environment = process.env.NODE_ENV || 'development';
const configuration = require('../../knexfile')[environment];
const database = require('knex')(configuration);

const graphql = require('graphql');
const {
  GraphQLObjectType,
  GraphQLString,
  GraphQLID,
  GraphQLInt,
  GraphQLList,
  GraphQLSchema
} = graphql;

const PetType = new GraphQLObjectType({
  name: 'Pet',
  //It is important that the fields is a function when we add our relationship later.
  fields: () => ({
    id: {type: GraphQLID},
    name: {type: GraphQLString},
    animal_type: {type: GraphQLString},
    breed: {type: GraphQLString},
    age: {type: GraphQLInt},
    favorite_treat: {type: GraphQLString}
  })
});

const RootQuery = new GraphQLObjectType({
  name: 'RootQueryType',
  fields:{
    pets: {
      type: new GraphQLList(PetType),
      resolve(parent, args){
        return database('pets').select()
      }
    },
  }
});

module.exports = new GraphQLSchema({
  query: RootQuery
})

Update index.js

We will need to require our schema in our file and update the object passed to graphqlHTTP(). The index.js file should now look like this:

const express = require('express');
const app = express();
// Allows express to understand graphql and interact with graphql API
// It is used as middleware for a single route
const graphqlHTTP = require('express-graphql')
const schema = require('./lib/schema/schema')


app.use('/graphql-pets', graphqlHTTP({
  schema: schema,
  //graphiql allows us to query from our browser
  graphiql: true
}))


app.listen(3001, ()=> {
  console.log("Listening for requests on port 3001")
});

Pets Query

Now spin up your server and visit localhost:3001/graphql-pets. Our browser should now allow us to send queries and when hit play to see the response from our server. The only data we can query at the moment is a list of pets. Create an object with pets at the root and then include the fields that you want to see in your response.

//query format
{
  pets{
    id
    name
    animal_type
    breed
    age
    favorite_treat
  }
}

Expected Response

{
  "data": {
    "pets": [
      {
        "id": "1",
        "name": "Fluffy",
        "animal_type": "cat",
        "breed": "long-hair",
        "age": 7,
        "favorite_treat": "catnip"
      },
      {
        "id": "2",
        "name": "Bubbles",
        "animal_type": "dog",
        "breed": "Boston Terrier",
        "age": 3,
        "favorite_treat": "blueberries"
      },
      {
        "id": "3",
        "name": "Fiona",
        "animal_type": "dog",
        "breed": "Mini Australian Shepherd",
        "age": 1,
        "favorite_treat": "pepperoni"
      },
      {
        "id": "4",
        "name": "Scooby",
        "animal_type": "dog",
        "breed": "Great Dane",
        "age": 4,
        "favorite_treat": "peanut butter"
      },
      {
        "id": "5",
        "name": "Wiley",
        "animal_type": "guinea pig",
        "breed": "Teddy",
        "age": 1,
        "favorite_treat": "oranges"
      }
    ]
  }
}

Hooray! we can query for pets.

Add query for single pet

Now we are going to add to the RootQuery so that we can retrieve a single pet.

const RootQuery = new GraphQLObjectType({
  name: 'RootQueryType',
  fields:{
    pet: {
      type: PetType,
      args: {id: {type: GraphQLID}},
      resolve(parent, args){
        return database('pets').where(id: args.id).first()
      }
    },
    pets: {
      type: new GraphQLList(PetType),
      resolve(parent, args){
        return database('pets').select()
      }
    },
  }
});

Notice that we include args here because we need our user to specify which pet they want with their query. We then pass the args to our resolver to find the specific pet.

Pet Query

When you are in graphql you now need to pass pet the argument of id like so.

{
  pet(id: 1){
    id
    name
    animal_type
    breed
    age
    favorite_treat
  }
}

Including Owners for pets

  • Define Owner type first
const OwnerType = new GraphQLObjectType({
  name: 'Owner',
  fields: () => ({
    id: {type: GraphQLID},
    name: {type: GraphQLString},
    age: {type: GraphQLInt},
    }
  })
});
  • Adjust the PetType
const PetType = new GraphQLObjectType({
  name: 'Pet',
  //It is important that the fields is a function when we add our relationship later.
  fields: () => ({
    id: {type: GraphQLID},
    name: {type: GraphQLString},
    animal_type: {type: GraphQLString},
    breed: {type: GraphQLString},
    age: {type: GraphQLInt},
    favorite_treat: {type: GraphQLString}
    owner: {
      type: OwnerType,
      resolve(parent, args){
        return database('pets')
          .join('owners', {'pets.owner_id': 'owners.id'})
          .where('owner.id', parent.owner_id)
          .first()
      }
    }
  })
});

We can now include the owner when querying for a pet.

Query for Pet’s Owner

{
  pet(id: 1){
    id
    name
    animal_type
    breed
    age
    favorite_treat
    owner{
      name
    }
  }
}

Practice

  • Add owners as a field to the RootQuery to return a list of all owners

  • Add owner as a field to the RootQuery to return a single owner based on the id

  • Adjust OwnerType so that it includes a field of pets that will return a list of pets for that owner

Bonus

  • Try to refactor the database queries to a Pet and Owner model

Completed Example here Completed Example refactored here

Lesson Search Results

Showing top 10 results