GraphQL Basics - Part 5: GraphQL Queries in Apollo Client

doylecodes

Ryan Doyle

Posted on April 30, 2019

GraphQL Basics - Part 5: GraphQL Queries in Apollo Client

GraphQL Queries

To get started with GraphQL queries we are going to first take a look at what a GraphQL query looks like, then we are going to see what writing a query looks like in Apollo on the front end.

If you've been following along with this tutorial, we have the following data model so far:

type User {
  id: ID! @unique
  name: String!
}

type Item {
  itemId: ID! @unique
  name: String!
  cost: Int!
  shortDescription: String
  longDescription: String
}
Enter fullscreen mode Exit fullscreen mode

Using GraphQL we can write a query for a specific user the following way:

{
  query GET_USER_QUERY {
    user {
      id
      name
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Here what each level has going on:

  • query GET_USER: This establishes we are writing a query, and we give it the name GET_USER_QUERY. I just like to add 'query' or 'mutation' in the names for clarity sake.
  • user: This is the specific query. It's also what our Apollo Server is going to look for in the Resolvers. Basically, we are telling the graphQL server to run the "user" resolver, which is similar to making a request from website.com/user in a REST API.
  • id, name: Finally, inside of user, we state what we want to be returned, which is both the id and the name of the user. (Although, we could just ask for one of them if we wanted)

REST API and GraphQL Compared

If you are coming from the land of a REST API, this is a little different. Basically, with a REST API, you end up hitting a certain URL endpoint, such as somesite.com/user and passing a query or params to the URL. You could use an express server to take those query params and use them in whatever logic to talk to the database and return data to you. (Super brief explanation obviously, I'm assuming you have some familiarity)

In a REST API, you have endpoints that you hit for certain requests/posts. An example would be website.com/users to get a list of users or going to website.com/posts for a full list of posts. You need an endpoint for all the different requests.

With GraphQL your server is set up to accept all requests the same way, but similar to how a REST API has different endpoints where the logic for the requests goes, a GraphQL server has different RESOLVERS that tell each GraphQL how to be handled.

Mind Blown

Writing the GraphQL Query from Frontend

Again, if you've been following along in the series, when we set up our graphQL server initially we were able to run queries against the sandbox endpoint (localhost:4000 on our project). That's great but, we need to be able to run the queries from our application, here's how we could do that!

  • Adding Users to Prisma DB
    First thing's first, we need to add a few users to our database in order to have something to query. We could do this programmatically, but I think that queries are easier to start within GraphQL, Prisma, and Apollo so what I did was just go into my Prisma DB, and add some users directly from the Prisma Admin.
    Prisma Admin Console
    Go to your Users in the admin console, and there is a + button (I highlighted it in yellow in the photo above) where you can just click to add users directly.

  • Add graphql-tag
    We need to add the package graphql-tag to our project. This lets us use template literals to parse the GraphQL language into out Apollo Queries. Simply npm i graphql-tag!

  • Make a Users Component
    Ok! So to write a query, we first need a component. We first need to create a file named Users.js in our projects frontend/components directory. Inside we need to require a few things (in addition to the normal react stuff dependencies).

    • graphql-tag: For wrapping out GraphQL queries.
    • Query: The Query render prop from the react-apollo library. We should have a basic start like below:
  import React, { Component } from 'react';
  import gql from 'graphql-tag';
  import { Query } from 'react-apollo';


  class Users extends Component {
    render() {
      return (
        <p>I'm the user component.</p>
      );
    }
  }

  export default Users;
Enter fullscreen mode Exit fullscreen mode
  • Add GraphQL Query to the User Component Next, we need to add the actual query. To get a better idea of the flow of writing a query from scratch, we are going to be making a query to get ALL users. To do this we use the gql tag and create a variable that holds the query in the gql tag.
const GET_USERS_QUERY = gql`
  query GET_USERS_QUERY {
    users {
      id
      name
    }
  }
`;
Enter fullscreen mode Exit fullscreen mode
  • Using the Query Component in Apollo Client To run our query, we use the Query component from Apollo Client. This is essentially a render prop that accepts our query as a prop, and behind the science runs the query against the database and returns data for us to work with!

To start off making sure everything is working, within the class we can put our component, passing the query as a prop, and within that, we have a single function that returns "data".

class Users extends Component {
  render() {
    return (
      <Query query={GET_USERS_QUERY}>
        {(data) => {
          console.log(data)
          return <p>check log</p>
        }}
      </Query>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

You can see how our function accepts data that get returned from the query, and currenlty we are simply returning a paragraph tag that say "check log" because we are logging the data to the console.

  • Make a User Page To see anything we need to make a new page that we can navigate to in our application. In the frontend/pages directory, I made a new file named users.js and put the following:
import React from 'react';
import Users from '../components/User';

const users = () => {
  return (
    <Users />
  );
};

export default users;
Enter fullscreen mode Exit fullscreen mode

Because we are using Next.js, making a new component in the /pages directory will create the users route and that's where we put out Users component.

Now we should be able to go to localhost:3000/users, and see our data in the logs!

  • OOPS. Fixing Errors Ok, if you have been following along 100% you now see errors. Full disclosure, I didn't plan this all out ahead of time and one problem I realized along the way is when setting up our servers, there are some CORS problems due to our frontend and backend being from different locations.

This can all be fixed by changing our backend/index.js to look like this:

const express = require('express');
const { Prisma } = require('prisma-binding');
const { ApolloServer } = require('apollo-server-express');
const { importSchema } = require('graphql-import');
const cors = require('cors');

const typeDefs = importSchema('./src/schema.graphql');
const Query = require('./src/Query');
const Mutation = require('./src/Mutation');

const db = new Prisma({
  typeDefs: './generated/prisma.graphql',
  endpoint: 'https://us1.prisma.sh/prisma-tutorial/prisma-graphql-tutorial/dev',
  secret: 'currentlyDrinkingPhilzCoffee'
});

const server = new ApolloServer({
  typeDefs,
  resolvers: {
    Mutation,
    Query
  },
  context: ({ req }) => ({
    ...req,
    db
  })
})

const app = express();

var corsOptions = {
  origin: 'http://localhost:3000',
  credentials: true // includes headers for the requests to backend
}

app.use(cors(corsOptions));

server.applyMiddleware({
  app,
  path: '/',
  cors: false // disbles default apollo-server cors and uses the express middleware cors in-lieu. 
})

app.listen({ port: 4000}, () => 
  console.log(`🚀 Server ready at localhost:4000`)
);
Enter fullscreen mode Exit fullscreen mode

This is pretty similar to what we had before with one major adjustment. (Hopefully, the reasoning will be another post later on...) Apollo Server actually handles CORS by default, and this becomes a problem if your frontend and backend are hosted in different places. Essentially what I've done here is this:

  • Changed const { ApolloServer } = require('apollo-server') to require('apollo-server-express')
  • Created an express app
  • Added the cors middleware and passed it more specific options for out application, including the origin for frontend requests.
  • Applied the express middlewares to our express server, and set the Apollo Server cors to FALSE, meaning that the Apollo cors is disabled, and we are going to be using the cors middleware.

If all goes well, there should be NO http-header errors anymore! But we still don't get any data returned, why is that? Well, we created a query for users but we didn't give our Apollo server any resolvers to deal with the query. So far we only have a single query for an individual user. The final step should be making a resolver for actually fetching all users.

  • Users Resolver This is pretty simple actually. First, go to backend/src/schema.graphql and add a users query to our graphql schema. The Query type should look like this after adding the users:
type Query {
  user(id: ID!): User
  users: [User]
}
Enter fullscreen mode Exit fullscreen mode

So, we added a users query, and that's going to return an array of User objects.

Next, we need to write the logic for the Query, so we head to backend/src/Query.js and create a users query after the user query we already had.

const Query = {
  user(parent, args, context, info) {
    if (!context.request.userId) {
      return null;
    }
    return context.db.query.user({
      where: { id: context.request.userId }
    }, info);
  },
  users(parent, args, context, info) {
    return context.db.query.users();
  }
};
Enter fullscreen mode Exit fullscreen mode

This is a pretty straightforward query due to the fact we are asking for ALL users. We are just accessing the Prisma users() method, made available to us because we passed it into the context object way back when the server was made. So we are accessing the context, then out Prisma database (db), then we are accessing the prisma queries, and calling users() with no additional options. (You can pass users() more options, but we just want all users).

Query Done!

At this point, (errors fixed and all) you should be able to go to localhost:3000/users and see logged to the console a data object with all of the users somewhere. I have what I see below.
Output
You can see in the object that's returned, we actually have the users nested under data.users.

We have the data! But we can clean it up a little.

<Query query={GET_USERS_QUERY}>
        {({data: {users} }) => {
          return (
            users.map(user => {
              return <p key={user.id}>{user.name}</p>
            })
          )
        }}
      </Query>
Enter fullscreen mode Exit fullscreen mode

Because we know that data we want is within "data" in the object, we can restructure that, and then further destructure the users within data. This lets us just access the array of users using "users." Within the return of the Query component, we can map through the array of users, returning a

tag with a "key" set to their id (React want's unique keys) and return the users name within the tag. So, if you had 4 users, you would just get a list of them all output to the DOM. Yay!

Recap

To recap, making a a query involves the following core steps:

  1. Writing the query.
  2. Adding the query to your GraphQL schema.
  3. Creating a resolver to handle the query coming from the client.

Hopefully, this is a good intro to basic queries in Apollo and implementing them with our Prisma methods in the resolvers. Next step, mutations!

💖 💪 🙅 🚩
doylecodes
Ryan Doyle

Posted on April 30, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related