Since this is a frontend track, we’re not going to spend any time implementing the backend. Instead, we’ll use the server from the Node tutorial.
Once our React application is created, we’ll pull in the required code for the backend.
Note: The final project for this tutorial can be found on GitHub. You can always use it as a reference whenever you get lost throughout the course of the following chapters. Also note that each code block is annotated with a filename. These annotations directly link to the corresponding file on GitHub so you can clearly see where to put the code and what the end result will look like.
The first step is to create a React project! As mentioned in the beginning,
we’ll use create-react-app
for that.
Note: This tutorial uses yarn for dependency management. Find instructions for how you can install it here. If you prefer using
npm
, you can just run the equivalent commands.
This will create a new directory called hackernews-react-apollo
that has all
the basic configuration setup.
Make sure everything works by navigating into the directory and starting the app:
cd hackernews-react-apollo
yarn start
This will open a browser and navigate to http://localhost:3000
where the app
is running. If everything went well, we’ll see the following:
import React from 'react';
import ReactDOM from 'react-dom';
import './styles/index.css';
import App from './components/App';
import reportWebVitals from './reportWebVitals';
import logo from './../logo.svg';
import './../styles/App.css';
The project structure should now look as follows:
.
├── README.md
├── node_modules
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
│ └── logo192.png
│ └── logo512.png
│ └── robot.txt
├── src
│ ├── components
│ │ └── App.js
│ │ └── App.test.js
│ ├── index.js
│ ├── logo.svg
│ ├── reportWebVitals.js
│ ├── setupTests.js
│ └── styles
│ ├── App.css
│ └── index.css
└── yarn.lock
This tutorial is about the concepts of GraphQL and how we can use it from within a React application, so we want to spend as little time as possible on styling. To reduce the usage of CSS in this project, we’ll use the Tachyons library which provides a number of CSS classes.
Since we still want to have a bit more custom styling, we also prepared some styles that need to be included in the project.
Here’s an overview of the packages we installed:
@apollo/client
contains
all the pieces needed to wire up the GraphQL client for our app. It exposes
the ApolloClient
, a provider to wrap around the React app called
ApolloProvider
, custom hooks such as useQuery
, and much more.graphql
contains Facebook’s
reference implementation of GraphQL - Apollo Client uses some of its
functionality within.That’s it, we’re ready to write some code! 🚀
ApolloClient
Apollo abstracts away all lower-level networking logic and provides a nice
interface to the GraphQL server. In contrast to working with REST APIs, we don’t
have to deal with constructing our own HTTP requests any more - instead we can
simply write queries and mutations and send them using an ApolloClient
instance.
The first thing we have to do when using Apollo is configure our ApolloClient
instance. It needs to know the endpoint of our GraphQL API so it can deal with
the network connections.
Let’s take a look at what’s going on in the code snippet above:
@apollo/client
.httpLink
that will connect our ApolloClient
instance with
the GraphQL API. The GraphQL server will be running on
http://localhost:4000
.ApolloClient
by passing in the httpLink
and a new instance
of an InMemoryCache
.App
is wrapped
with the higher-order component ApolloProvider
that gets passed the
client
as a prop.That’s it, we’re all set to start for loading some data into our app! 😎
As mentioned above, for the backend in this tutorial we’ll simply use the final project from the Node tutorial.
Note: If you are on Windows, you may want to install Git CLI to avoid potential problems with commands such as
curl
.
We now have a new directory called server
inside our project that contains all
the code needed for our backend.
Before we start the server, let’s quickly understand the main components:
prisma
: This directory holds all the files that relate to our
Prisma setup. Prisma Client is used to access the
database in our GraphQL resolvers (similar to an ORM).
schema.prisma
defines our data model for the project. It uses the
Prisma Schema Language
to define the shape of our databases tables and the relations between them.dev.db
is a SQLite database that will be used to store and retrieve data
for this tutorialsrc
: This directory holds the source files for our GraphQL server.
schema.graphql
contains our application schema. The application schema
defines the GraphQL operations we can send from the frontend. We’ll take a
closer look at this file in just a bit.resolvers
contains the
resolver functions
for the operations defined in the application schema.index.js
is the entry point for our GraphQL server.From the mentioned files, only the application schema defined in
server/src/schema.graphql
is relevant for you as a frontend developer. This
file contains the
GraphQL schema
which defines all the operations (queries, mutations and subscriptions) we can
send from your frontend app.
Here is what it looks like:
type Query {
info: String!
feed(filter: String, skip: Int, take: Int, orderBy: LinkOrderByInput): Feed!
}
type Feed {
id: ID!
links: [Link!]!
count: Int!
}
type Mutation {
post(url: String!, description: String!): Link!
signup(email: String!, password: String!, name: String!): AuthPayload
login(email: String!, password: String!): AuthPayload
vote(linkId: ID!): Vote
}
type Subscription {
newLink: Link
newVote: Vote
}
type AuthPayload {
token: String
user: User
}
type User {
id: ID!
name: String!
email: String!
links: [Link!]!
}
type Link {
id: ID!
description: String!
url: String!
postedBy: User
votes: [Vote!]!
createdAt: DateTime!
}
type Vote {
id: ID!
link: Link!
user: User!
}
input LinkOrderByInput {
description: Sort
url: Sort
createdAt: Sort
}
enum Sort {
asc
desc
}
scalar DateTime
This schema allows for the following operations:
Queries:
feed
: Retrieves all links from the backend, note that this query also
allows for filter, sorting and pagination argumentsMutations:
post
: Allows authenticated users to create a new linksignup
: Create an account for a new userlogin
: Login an existing uservote
: Allows authenticated users to vote for an existing linkSubscriptions:
newLink
: Receive realtime updates when a new link is creatednewVote
: Receive realtime updates when a vote was submittedFor example, we can send the following feed
query to retrieve the first 10
links from the server:
{
feed(skip: 0, take: 10) {
links {
description
url
postedBy {
name
}
}
}
}
Or the signup
mutation to create a new user:
mutation {
signup(name: "Sarah", email: "sarah@prisma.io", password: "graphql") {
token
user {
id
}
}
}
There is one thing left to do before we can start our server and begin sending queries and mutations to it. We need a database and a generated Prisma Client so that we can actually store and retrieve data.
Prisma supports several relational databases, including Postgres, MySQL, and SQLite.
For this tutorial, we’ll keep things simple and use SQLite. It’s a filesystem database that is very easy to get started with. It should be noted, however, that SQLite may not be suitable for production purposes.
There is a file called dev.db
located in the server/prisma
directory. This
file is our SQLite database.
Note: You are free to use Postgres or MySQL for this tutorial if you prefer. All aspects of the tutorial will still work with those databases.
Next, let’s run database migrations and generate Prisma Client.