Using GraphQL

Overview

GraphQL is a query language for APIs. It enables declarative data fetching and thus ties in perfectly with React/React Native as a declarative framework for building user interfaces. GraphQL can either complement or entirely replace the usage of REST APIs.

The main difference between REST and GraphQL is that RESTful APIs have multiple endpoints that return fixed data structures whereas a GraphQL server only exposes a single endpoint and returns flexible data structures. This works because a client that needs data from the server also submits its precise data requirements in each request which allows the server to tailor the response exactly according to the client’s needs.

You can learn more about the differences between GraphQL and REST here. To get a high-level overview and understand more about the architectural use cases of GraphQL, take a look at this article.

GraphQL has a rapidly growing community. To stay up-to-date about everything that’s happening in the GraphQL ecosystem, check out these resources:

Prisma blog: Technical deep dives and tutorials all around GraphQL development

For an in-depth learning experience, visit the How to GraphQL fullstack tutorial website.

Communicating with a GraphQL API

In this section, we’ll explain the core concepts you need to know when working with a GraphQL API.

Fetching data with GraphQL queries

When an application needs to retrieve data from a GraphQL API, it has to send a query to the server in which it specifies the data requirements. Most GraphQL servers accept only HTTP POST requests where the query is put into the body of the request. Note however that GraphQL itself is actually transport layer agnostic, meaning that the client-server communication could also happen using other networking protocols than HTTP.

Here’s an example query that a client might send in an Instagram-like application:

query{
feed {
id
imageUrl
description
}}

The keyword query in the beginning expresses the operation type. Besides query, there are two more operation types called mutation and subscription. Note that the default operation type of a request is in fact query, so you might as well remove it from the above request. feed is the root field of the query and everything that follows is called the selection set of the query.

When a server receives the above query, it will resolve it, i.e. collect the required data, and package up the response in the same format of the query. Here’s what a potential response could look like:

The root of the returned JSON object is a field called data as defined in the official GraphQL specification. The rest of the JSON object then contains exactly the information that the client asked for in the query. If the client for example hadn’t included the imageUrl in the query’s selection set, the server wouldn’t have included it in its response either.

In case the GraphQL request fails for some reason, e.g. because the query was malformed, the server will not return the data field but instead return an array called errors with information about the failure. Notice that it can happen that the server returns both, dataanderrors . This can occur when the server can only partially resolve a query, e.g. because the user requesting the data only had the access rights for specific parts of the query's payload.

Creating, updating and deleting data with GraphQL mutations

Most of the time when working with an API, you’ll also want to make changes to the data that’s currently stored in the backend. In GraphQL, this is done using so-called mutations. A mutation follows the exact same syntactical structure as a query. In fact, it actually also is a query in that it combines a write operation with a directly following read operation. Essentially, the idea of a mutation corresponds to the PUT, POST and DELETE calls that you would run against a REST API but additionally allows you to fetch data in a single request.

Let’s consider an example mutation to create a new post in our sample Instagram app:

Instead of the query operation type, this time we’re using mutation. Then follows the root field, which in this case is called createPost. Notice that all fields can also take arguments, here we provide the post’s description and imageUrl so the server knows what it should write into the database. In the payload of the mutation we simply specify the id of the new post that will be generated on the server-side.

After the server created the new post in the database, it will return the following sample response to the client:

{"data":{"createPost":{"id":"1"}}}

The GraphQL schema

In this section, we'll discuss the backbone of every GraphQL server: The GraphQL schema.

For a technical deep dive all around the GraphQL schema, be sure to check out this article.

The Schema Definition Language (SDL)

GraphQL has a type system that’s used to define the capabilities of an API. These capabilities are written down in the GraphQL schema using the syntax of the GraphQL Schema Definition Language (SDL). Here’s what the Post type from our previous examples looks like:

type Post {id: ID!description: String!imageUrl: String!}

The syntax is pretty straightforward. We’re defining a type called Post that has three properties, in GraphQL terminology these properties are called fields. Each field has a name and a type. The exclamation point following a type means that this field cannot be null.

Root types are the entry points for the API

Each schema has so-called root types that define the entry points into the API. These are the root types that you can define in your schema:

Query: Specifies all the queries a GraphQL server accepts

Mutation: Specifies all the mutations a GraphQL server accepts

Subscription: Specifies all the subscriptions a GraphQL server accepts (subscriptions are used for realtime functionality, learn more here)

To enable the feed query and createPost mutation that we saw in the previous examples, you’d have to write the root types as follows:

Getting started with GraphQL

The first thing you need when getting started with GraphQL is of course a GraphQL server. As GraphQL itself is only a specification, you can either implement your own server using one of the available reference implementations or take a shortcut by using a tool like Apollo Launchpad.

The best way to get started with GraphQL in production is to use graphql-yoga, a flexible GraphQL server based on Express.js. graphql-yoga has a number of compelling features, such as support for GraphQL Playground and built-in GraphQL subscriptions for realtime functionality.

A great way to add a database to your GraphQL server is by using Prisma. Prisma is an open-source GraphQL query engine that turns your database into a GraphQL API. Thanks to Prisma bindings, it integrates nicely with your graphql-yoga server.

To learn how to build a GraphQL server, check out this tutorial or watch this 4-min demo video.

Since GraphQL servers are commonly implemented with HTTP, you can simply use fetch to get started and send queries and mutations to interact with the server. However, when working with GraphQL on the frontend, you’ll usually want to use a GraphQL client library. GraphQL clients generally provide handy abstractions and allow you to directly send queries and mutations without having to worry about lower-level networking details.

Creating your own GraphQL server

The fastest way to get started with GraphQL is by using a GraphQL boilerplate project for the technology of your choice. GraphQL boilerplates provide the ideal starter kits for your GraphQL-based projects - no matter if backend-only or fullstack.

To get started, you can use the graphql create command (which is similar to create-react-native-app).

This will prompt you a list of the available boilerplates. Each technology has a minimal, a basic and an advanced version.

Choose minimal to learn what the most minimal version of a GraphQL server looks like. basic boilerplates come with an integrated database (based on Prisma). Finally, the advanced boilerplates additionally come with built-in authentication functionality for your users as well as support for realtime subscriptions.

To skip the interactive prompt, you can also pass the --boilerplate (short: -b) flag to the graphql create command and specify which starter kit you'd like to use. For example:

Running a practical example with React, Apollo & GraphQL

If you want to get your hands dirty and learn how to get started with a practical example, check out the basic boilerplate for a fullstack React application.

Note There are currently no boilerplate projects for React Native. However, all the code that's used to interact with the GraphQL API from within the React app can be applied in a React Native application in an identical manner!

Run graphql create and specify react-fullstack-basic as your target boilerplate:

graphql create myapp --boilerplate react-fullstack-basic

The GraphQL CLI will now fetch the code from the corresponding GitHub repository and run an install script to configure everything that's required.

After having downloaded the code from the repo, the CLI will prompt you to choose where you want to deploy your Prisma database service. To get started quickly, select one of the development clusters (prisma-eu1 or prisma-us1). If you have Docker installed, you can also deploy locally.

The install script will use the generated endpoint for the Prisma service and connect the GraphQL server with it by insterting it into src/server/index.js.

Once the command has finished, you first need to start the server and second start the React app:

cd myapp/server
yarn start
# the server is now running on http://localhost:4000;
# to continue, open a new tab in your terminal
# and navigate back to the root directory
cd ..
yarn start