DEV Community

Cover image for A Comprehensive Guide to Writing Your First GraphQL Query
The ERIN
The ERIN

Posted on • Edited on

A Comprehensive Guide to Writing Your First GraphQL Query

Introduction

APIs (Application Programming Interfaces) have become essential to modern web apps in today's software development world. APIs allow developers to access and interact with data from different sources, making building apps that rely on data from multiple services easier. GraphQL has gained significant popularity as a powerful and flexible query language. It is an open-source query language developed by Meta that provides a more efficient approach to querying APIs.

If you are new to GraphQL and wondering how to write your first Query, you have come to the right place.

This guide covers the following:

  • An overview of GraphQL and its differences from traditional REST(Representational State Transfer) APIs
  • Introduction to writing your first GraphQL Query
  • Understanding the syntax of GraphQL queries
  • How to consume a GraphQL API in a React.js web app
  • Exploring everyday use cases for querying APIs with GraphQL

Upon completing this guide, you must have learned how to write a GraphQL query and be ready to build powerful web apps with GraphQL-powered APIs. So, let us get started!

 

Prerequisites

  • Basic knowledge of JavaScript
  • Basic knowledge of Node.js and its syntax
  • Any code editor you are comfortable using

 

What is GraphQL?

GraphQL is a query language that describes an API request. It is unrelated to databases. Query Languages are not specific to databases. They are programming languages used to get data from a database or an API. GraphQL is not a technology, library, or database; it is a query language that exists as a layer between an app’s front and backend. GraphQL acts as a middle-man layer between the front and backend, so either can not communicate directly. GraphQL is an alternative to REST APIs. With a REST API, we have to make individual requests with different HTTP methods to a database to retrieve data, but with GraphQL, all of the requests must be made to a single endpoint.

 

Differences between GraphQL and REST APIs

GraphQL and REST APIs are two popular methods of retrieving data from an API or a database. While REST APIs have existed longer, GraphQL has recently gained significant popularity. Both technologies have strengths and weaknesses, and knowing which one to use for specific use cases is essential. Let us go over some of their differences:

  • Endpoints: With a standard REST API, we must make individual requests with different methods to get the appropriate data. With GraphQL, we only have to request a single endpoint without worrying about making requests to different endpoints.

     

  • Data Fetching: GraphQL allows the frontend to specify what data they need, and the server returns only that data. It helps to reduce network usage and make data fetching faster. With REST APIs, the server sends back all the data associated with an endpoint requested from the frontend, sometimes including irrelevant data and slow network optimization.

     

  • Error Handling: With REST APIs, errors are returned as HTTP status codes, which must be parsed and handled correctly in the frontend. Unlike GraphQL, errors are returned as part of the response data, making it easier for the frontend to handle errors correctly and provide clearer and more concise error messages.

     

  • Documentation: One distinct difference between GraphQL and REST APIs is their approach to documentation. REST APIs often rely on external documentation to explain each endpoint and its associated parameters. On the other hand, GraphQL is self-documented as its available types and fields are already defined, making it easier to understand how to query the API without the need for external documentation.

It is advisable to choose either of the two methods for a specific use case, as both are popular methods of fetching data with a large community, making them easier to use.

 

GraphQL Terminologies: Types, Schema, Queries, Mutation, and Resolvers

It is important to understand the basic terminologies of GraphQL, as it helps to simplify the complex concepts surrounding the language. By the end of this section, we expect to have a clear understanding of the concepts. These concepts lay the foundation for using a GraphQL API.

 

Types

One of the fundamental concepts in GraphQL is types. Types in GraphQL refer to the structure of data that can be queried from an API. Like strictly-typed languages, we must always define data types. By using types in GraphQL, our API provides a more structured and consistent way of querying data. In GraphQL, there are three main types:

  • scalar types
  • object types
  • enumeration types

 

Scalar Types

Scalar types are primitive data types used to represent values. These types are namely: IDs, strings, integers, floats, and booleans They are not types composed of fields or sub-fields.

 

Object Types

Object types in GraphQL are a set of fields, each with its scalar type. They represent complex data types that can have subfields and child types, each with its scalar type.

Example of an Object Types

 type User {
      id: ID!
      name: String!
      email: String!
      age: Int
    }
Enter fullscreen mode Exit fullscreen mode

In this example, we have an object type called: User. The User type represents a certain user in our app and has fields for their id, name, email, and age

If we notice, there is an exclamation mark (!) after some data types. It indicates the fields are required and cannot be null. GraphQL accepts either a value or null.

 

Enumeration Types

Enumeration types in GraphQL are also referred to as enums. They define a finite set of constant values used as a type for a field, ensuring only valid values are accepted for that field. Once an enum has been defined, the values cannot be changed, ensuring they remain constant.

Example of Enums

 enum Country {
      CANADA
      FRANCE
      SPAIN
      ENGLAND
    }
Enter fullscreen mode Exit fullscreen mode

In the example, we have defined an enum called Country with four values: CANADA, FRANCE, SPAIN, and ENGLAND. This enum can be included as a type for an object field such as:

 type User {
      id: ID!
      country: Country!
    }
Enter fullscreen mode Exit fullscreen mode

In the User object, we have specified a type with a country field of type Color. Using an enum type like the one we defined ensures only valid country values are accepted for the country field, making the API more consistent and accurate.

In addition to scalar, object, and enumeration types, GraphQL also supports unions and interfaces. Unions and interfaces enable the creation of abstract types representing multiple object types.

 

Schema

A schema in GraphQL is unrelated to a database schema. It is a schema that defines all of the data inside the API. Every GraphQL schema have a root object type called Query. This root type contains all the queries we want to make from the frontend to request data from the API. Every GraphQL API must have a schema. A schema also defines the relationships between objects and any available queries or mutations.

Here is an example of a schema in GraphQL, using an example from the Countries GraphQL API:

 type Query {
      country(code: ID!): Country
      language(code: ID!): Language
    }

  type Country {
      code: ID!
      continent: Continent!
      currency: String
      name: String!
      native: String!
      phone: String!
    }

   type Language {
      code: ID!
      name: String!
      native: String!
      rtl: Boolean!
    }
Enter fullscreen mode Exit fullscreen mode

 

In this example, we defined a schema with two object types, Country and Language, and two query fields, country, and language.

The country query takes an argument code of type ID and returns a single Country object with fields code, continent, currency, name, native, and phone.

The language query takes an argument code of type ID and returns a single Language object with fields code, name, native, and rtl.

By defining these object types and queries, the frontend can query the API for specific countries or languages and receive a standard response, including the specified fields.

 

Queries and Mutations

In GraphQL, there are two types of operations: queries and mutations. They are the primary way to request data from an API, whether for querying or changing the data. With GraphQL, we do not need to specify what HTTP method request we are making from the frontend; we need to specify if we are trying to make a query or a mutation.

 

Queries

A query is a request for data that specifies exactly what data the frontend wants and how it must be structured. All the data the frontend needs from the API or database is written inside the query.

Queries in GraphQL consist of one or more fields, each with its name and set of arguments that specify how the field must be queried. Fields can be scalar types, such as strings, integers, or object types, with subfields and child types.

The GET method in REST API is synonymous with a Query operation in GraphQL.

Example of a query

 query {
      country(code: "US") {
        code
        name
        phone
      }
    }
Enter fullscreen mode Exit fullscreen mode

 

In this example, we request data for a GraphQL Country API country with the US code. We specified the country's code, name, and phone fields to be returned from the API. By specifying the fields we want in the Query, we can reduce the amount of data the API returns, resulting in more efficient network usage.

 

Mutation

Mutation is the second type of operation in GraphQL. A mutation is a type of operation used to mutate, alter, or change the data on the server side. Mutations can create, update, or delete data and are defined in the schema, object types, and queries.

While queries are used to retrieve data, mutations are used to make changes to that data.
The REST API's CREATE, UPDATE, and DELETE method is synonymous with a Mutation operation in GraphQL.

For example, a mutation can create a new user account or update an existing one. Mutations typically take input arguments that define the changes to be made and return values that indicate the success or failure of the mutation.

Example of a mutation operation that creates a user

 mutation {
      createUser(input: {
        name: "John Doe",
        email: "john.doe@example.com",
        password: "secret123456"
      }) {
        id
        name
        email
      }
    }
Enter fullscreen mode Exit fullscreen mode

 

In this example, the createUser mutation takes a single argument called input, an object type containing the new user's name, email, and password fields. The mutation returns the newly created user's id, name, and emailfields.

Example of a mutation operation that updates a user

 mutation {
      updateUser(id: 111, name: "John Doe") {
        id
        name
        email
      }
    }
Enter fullscreen mode Exit fullscreen mode

 

In this example, the updateUser mutation takes two arguments: id, which identifies the user to be updated, and name, which is the new name for the user. The mutation returns the user's updated id, name, and email fields.

Example of a mutation operation that deletes a user

  mutation {
      deleteUser(id: 123) {
        id
        name
        email
      }
    }
Enter fullscreen mode Exit fullscreen mode

In this example, the deleteUser mutation takes a single argument called id, which is the identifier of the user to be deleted. The mutation returns the deleted user's id, name, and email fields.

 

Resolvers

A resolver is a function that retrieves data for a particular field in a query or mutation. It triggers the request sent from the frontend and fetches data from the API based on the type of operation specified.

Each field in a GraphQL schema must have a corresponding resolver that returns the data for that field. Resolvers can fetch data from a database, call an API, or perform any other operation needed to retrieve the data. Resolvers are responsible for resolving the entire query,

Example of a Resolver in GraphQL

 const resolvers = {
      Query: {
        user: (_, { id }) => {
          return users.find(user => user.id === id);
        }
      },
      User: {
        name: (user) => user.name
      }
    };
Enter fullscreen mode Exit fullscreen mode

In this example, the user resolver function takes an id argument and returns the user object from the users array, which matches the given ID. The User resolver object defines a resolver for the name field, which returns the value of the name property on the user object.

 

How to write and run a GraphQL query using the GraphQL Playground

To use GraphQL to fetch data from an API, the API must support the GraphQL fetching operation. It has to be a REST API that communicates with the GraphQL layer or a GraphQL API built using GraphQL.

GraphQL Playground is a tool for testing GraphQL APIs. It provides an interactive environment for executing queries, exploring the schema, and debugging errors. To test a GraphQL API in the Playground, we must provide the endpoint URL and write queries in the left-hand panel.

Other GraphQL clients offer similar functionality for testing and interacting with a GraphQL API, but this article places greater emphasis on using GraphQL Playground. To test our queries, we will work with the StarWars API.

To start, Open the GraphQL Playground by navigating to the Star Wars GraphQL Playground URL here.

 

Explore the API Schema:

Once the playground is loaded, you can find the API schema on the bottom left-hand side of the screen. Click the schema icon to explore the available types, queries, and mutations to use with the API.

 

Writing our Query:

We must implement our Queries operation knowledge to request the Star Wars API. From the schema defined, in the root query, there are different queries we can make requests to. Let us request the allPeople query.

  query {
        allPeople {
          people {
            name
            birthYear
            species {
              name
            }
          }
        }
      }
Enter fullscreen mode Exit fullscreen mode

This GraphQL Query fetches a list of people and their details, including name, birth year, and species they belong to. The Query requests for all people and uses the allPeople field to retrieve an object containing a list of people. The people field then returns an array of objects containing each person's name, birthYear, and species details. The species field within the people field is a nested query retrieving the species names for each person.

In this example, we use the allPeople field to fetch a list of people and their details. The people field then returns an array of objects containing each person's name, birthYear, and species details.
After writing our Query, we must click the "Play" button to execute our Query.

 

Viewing the response:

After executing the query, the results are shown in the "Response" section of the screen. The response to the data is in this format:

 {
      "data": {
        "allPeople": {
          "people": [
            {
              "name": "Luke Skywalker",
              "birthYear": "19BBY",
              "species": null
            },
            {
              "name": "C-3PO",
              "birthYear": "112BBY",
              "species": {
                "name": "Droid"
              }
            },
            {
              "name": "R2-D2",
              "birthYear": "33BBY",
              "species": {
                "name": "Droid"
              }
            },
            {
              "name": "Darth Vader",
              "birthYear": "41.9BBY",
              "species": null
            },
            {
              "name": "Leia Organa",
              "birthYear": "19BBY",
              "species": null
            },
            {
              "name": "Owen Lars",
              "birthYear": "52BBY",
              "species": null
            },
            {
              "name": "Beru Whitesun lars",
              "birthYear": "47BBY",
              "species": null
            },
            }
          ]
        }
      }
    }
Enter fullscreen mode Exit fullscreen mode

The response data also provides us with an option to view any errors or warnings which may have occurred during the execution of our Query.

 

How to fetch a GraphQL API in a React.Js app

React.js is a popular frontend JavaScript library for building scalable and efficient user interfaces. It lets us create reusable UI components and declaratively define how they may behave in response to user interactions or data changes.

React.js is useful for building apps that let us consume data from a GraphQL API because it easily renders data from the API to components. React components can send queries to a GraphQL server using GraphQL client libraries like Apollo Client.

Apollo Client is a comprehensive JavaScript state-management library enabling us to consume and interact with GraphQL APIs in our app easily.

It provides a range of useful features, such as caching, fetching, and modifying real-time data, and lets us easily integrate our GraphQL API with our frontend app.

 

Setting up our development environment

Our first step is to set up a development environment where we can start building our web app.

Run the following command via the terminal. I am using npm as my package manager, but you can use your preferred package manager's commands instead:

 npx create-react-app rick-morty-app
Enter fullscreen mode Exit fullscreen mode

This command creates a React.js app in our folder directory.

Once all of the dependencies have been installed, navigate to the rick-morty-app directory by running

 cd rick-morty-app
Enter fullscreen mode Exit fullscreen mode

To start the development server run

 npm start or yarn start
Enter fullscreen mode Exit fullscreen mode

To view the app, go to http://localhost:3000.
We must install the apollo-client library and set up some basic configurations to write our queries to the GraphQL API in our React app.

Open up the terminal, and run the following command:

 npm install @apollo/client
Enter fullscreen mode Exit fullscreen mode

When we run the specified command, it installs the apollo-client library, which enables our React.js app to establish a connection with the Rick and Morty API. This connection allows us to consume the data contained within the Rick and Morty API.

In your App.js file, write the following code. I'll then go over each line of the code to explain its purpose.

    import { ApolloClient, InMemoryCache, ApolloProvider } from "@apollo/client";
    Import PeopleData from './PeopleData'
    function App() {
      const client = new ApolloClient({
        cache: new InMemoryCache(),
        uri: "https://rickandmortyapi.com/graphql",
      });
      return (
        <ApolloProvider client={client}>
          <div className="App">
            <PeopleData />
          </div>
        </ApolloProvider>
      );
    }
    export default App;
Enter fullscreen mode Exit fullscreen mode

The code sets up our React app with the Apollo Client, which lets us communicate with the Rick and Morty API server. It imports the necessary classes from the @apollo/client library, including the ApolloClient, InMemoryCache, and ApolloProvider.

The Apollo Client library has good state management, allowing us to cache data in our browser called the InMemoryCache. The InMemoryCache is configured with the ApolloClient, which stores the results of queries made to the GraphQL server.

Finally, the App component returns a div containing the PeopleData component, making GraphQL queries to the server using the ApolloClient. This code enables the React app to communicate with a GraphQL API via the Apollo Client.

Let us create a file called PeopleData.js. This file involves making a query operation to the Rick and Morty API via the Apollo client library, then displaying the retrieved data.

Go ahead and write the following code:

    import React from "react";
    import { useQuery, gql } from "@apollo/client";
    const GET_CHARACTERS = gql`
      query GetCharacters {
        characters {
          results {
            id
            name
            image
          }
        }
      }
    `;
    function PeopleData() {
      const { loading, data } = useQuery(GET_CHARACTERS);
      if (loading) {
        return <h1> Loading...</h1>;
      }
      return (
        <div>
          {data.characters.results.map((character) => (
            <div key={character.id}>
              <h2>{character.name}</h2>
              <img src={character.image} alt={character.name} />
            </div>
          ))}
        </div>
      );
    }
    export default PeopleData;
Enter fullscreen mode Exit fullscreen mode

 

In the PeopleData.js file, we imported the useQuery hook and gql function from the @apollo/client library. The useQuery hook is an important part of the apollo client library because this hook lets us make queries to the Rick and Morty API. The gql function lets us write GraphQL syntax in our React components.

The GET_CHARACTERS constant is a GraphQL query retrieving the id, name, and image fields for all characters in the API. The useQuery hook lets us retrieve data, handle errors, and set loading features in our components by destructuring the data, error, and loading variables from the hook.

To display the data retrieved from the API, we need to use the JavaScript map() function to iterate over the data. For each character in the array, our component displays the character's name and image.

If we go over to http://localhost:3000 in the browser, our fetched data is displayed in the order specified in our component.

We can also handle errors in our code, as the useQuery hook provides an error variable.

 

Conclusion

GraphQL is a flexible and powerful query language that has been increasingly popular in recent years thanks to its flexibility, efficiency, and ease of use. In this guide, we have covered the basics of GraphQL, including its key features, syntax, and concepts, as well as how to write your first GraphQL query. By following the steps outlined in this guide, you now have a solid understanding of how to use GraphQL to retrieve and manipulate data from your API and display it on the frontend, as well as the tools and resources you need to get started. Whether you are a seasoned developer or just starting, GraphQL is a valuable tool to help build better, more responsive, and more scalable apps.

 

Resources and References

If you liked my article and found it useful, please leave a tip. Your contribution would enable me to continue producing high-quality articles for you.

Image description

Thank you for your continued support, and I look forward to providing you with more useful content in the future.

Top comments (1)

Collapse
 
fruntend profile image
fruntend

Сongratulations 🥳! Your article hit the top posts for the week - dev.to/fruntend/top-10-posts-for-f...
Keep it up 👍