How to use GraphQL Queries

In this tutorial we’re going to learn how to use basic GraphQL queries. This is a post in a larger series. To get caught up, grab the existing code here: https://github.com/truthseekers/graphql-prisma-series and pull down the start-graphql-queries branch. (and run npm install)

Ok, let’s begin!

So GraphQL obviously needs a data source, otherwise we would have no app. You can fetch data from a MongoDB database, SQL, a JSON file, or even just hardcode data into the files. Let’s start with hard coding.

Open up the index.js file, and after all the import/require statements, add an array of users:

let users = [
  {
    id: "123",
    firstName: "Cindy",
    email: "cindy@cindy.com",
  },
  {
    id: "456",
    firstName: "Todd",
    email: "todd@todd.com",
  },
];

If we’re going to add Users to our GraphQL server, we need to tell GraphQL about the User type. We do that in the typeDefs. Alter your typeDefs constant (in index.js) to have the following code:

const typeDefs = `
type Query {
  helloWorld: String!
  users: [User!]!
}

type User {
    id: ID!
    firstName: String!
    email: String!
}
`;

The above code describes the Query “root type”. Inside it are the queries that are available to the server. There are also “Mutation” and “Subscription” root types which we’ll get to later.

In addition to the “root types” we also have to define the types of data that are available. We want to add a new type of User, so we need to define how a user object looks. In our case a user has an ID, firstName, and email with the primitive types of String. (ID is basically a string)

! behind the primitive types mean the field is required.

The typeDefs tells GraphQL that the User type exists, but it doesn’t say anything about where the data is or how to get it. That’s what the resolvers are for. Edit the resolvers constant to look like the following:

const resolvers = {
  Query: {
    helloWorld: () => `Hello World! What a day!`,
    // users: () => users, // We could do this since it's such a simple query
    users: (parent, args, context, info) => {
      return users;
    },
  },
  User: {
    id: (parent) => parent.id,
    firstName: (parent) => {
      console.log("What is parent: ", parent);
      return parent.firstName;
    },
    // firstName: (parent) => parent.firstName, // simple version. above to illustrate
    email: (parent) => parent.email,
  },
};

Because we’re trying to retrieve data from the database, the function belongs in the Query root type. To make the query we define a function that takes 4 parameters: parent, args, context, info. Then the function has to go find the users. In this case all we have to do is return the users array.

The return value of the function “users” MUST match exactly what the typeDefs expects. Look at the Query.users value in typeDefs. Notice that it says [User!]! which means an array of User objects. What does a User object look like? Look at the definition! It says type User has an id, firstName, and email field… So if the resolver returns anything other than an array of User objects it will fail.

We’ll cover the User object in the resolvers in just a moment. First, save the file and run the following query in your GraphQL Playground: make sure you stop and restart the server with CTRL+C

query {
  users {
    firstName
    email
  }
}

You should get something that looks like this:

The Query we just ran basically says “Hey GraphQL, run a query that fetches me an array of User objects. I’m only interested in the firstName and email fields. And so that’s what we get back!

When the Query runs, it fetches all the User objects. Then you can see we’re only asking for the “firstName”, and “email” of the User object. Well… How does GraphQL know where to get the firstName or email field?

That’s where the User resolver comes in. From within the Query.users, we have to get the User.firstName and a User.email for each User object returned. Because User.firstName is ran from within the Query.users, then Query.users is the parent of User.firstName.

If you don’t need “email”, don’t include it in your query. Try swapping out the firstName with id to see the console.log statement is no longer executed.

Queries with Arguments:

Let’s grab individual users from our database. Create a “user” query that accepts a userId as an argument. Alter your “typeDefs” so it has the “user” query like this:

const typeDefs = `
type Query {
  helloWorld: String!
  users: [User!]!
  user(userId: ID!): User
}
// ....

You’ll see the “user” query takes a “userId” argument with the type of ID (which is actually a string). Note the ! means it’s required. If you were to omit the “!” then it would be an optional parameter. (good for things like search)

the “user” query returns a SINGLE User object. Note there is no “!” because there might not be a user that matches the userId argument.

Now we need another query resolver to tell GraphQL how to find this individual user. Let’s use Javascripts Array.find() method to search the users array by userId. In the “resolvers” constant, create the “user” query like below:

const resolvers = {
  Query: {
    helloWorld: () => `Hello World! What a day!`,
    // users: () => users, // We could do this since it's such a simple query
    users: (parent, args, context, info) => {
      return users;
    },
    user: (parent, args, context, info) => {
      return users.find((user) => {
        if (user.id == args.userId) {
          return user;
        }
      });
    },
  },
//...

This is essentially us creating our own “SQL Statement” because our server is currently too dumb to figure it out. Prisma will do a lot of this heavy lifting for us soon.

Notice this time we’re using the args parameter. The args parameter is the “userId” value that is passed into our query. Let’s try it out in our GraphQL playground after you restart the server. Enter the code below into the GraphQL Playground and hit the play button:

query {
  user(userId: "456") {
    firstName
    email
  }
}

Cool beans right? Now let’s try getting familiar with the Query variables at the bottom of graphql playground. When running in a live application you’ll need to pass in arguments via the code, so the below query will be identical to what you would have in your actual code. Paste the following into your GraphQL playground:

query getUser($userId: ID!){
  user(userId: $userId) {
    firstName
    email
  }
}

Before you hit Play, you have to populate the userId variable. You can do that by clicking the “query variables” tab at the bottom of the screen, and entering the following information:

{
  "userId": "123"
}

When you enter the information and hit play, you should get only the user that has the matching userId.

What you’re seeing above is “named” queries, which are used on the client to help with caching. (We’ll cover that later). In the above code we’re just declaring a variable $userId with the type of ID! Then we pass the $userId variable to the user() query as userId, which is then used by the “args” parameter in our resolvers, where we find the user with the corresponding ID.

That’s it for now on Queries. We’ll touch on it a bit more once we get into Prisma.

The final code is here at the done-graphql-queries branch

That’s it for now on Queries. We’ll get back to it a bit later when we cover relationships between data like one to many and many to many.

Want More Tutorials?

Get our best crash courses and tutorials

(Source Code Provided)

Leave a Comment

Your email address will not be published. Required fields are marked *

want more details?

Fill in your details and we'll be in touch

%d bloggers like this: