Anupam Dagar

@siriusdagar

Building a React Todo App with Hasura GraphQL Engine

October 3rd 2018
Hasura and React

If you are reading this then it means that you’re probably on your way to know about Hasura and React. Well if that’s the case then you just landed at the perfect location. You might be having all sorts of questions like, “What’s graphql?”, “What’s Hasura?” or more importantly, “Why are we using it?”. Well, fear not everything will be cleared by the time you complete reading this blog. So let’s get started!

This tutorial assumes that you have basic knowledge of React framework. If you are total new to React, I would suggest going through the hello world app of React first before continuing further.
The code samples given in as you follow are for main relevant part only, if you intend to copy the code then make sure to import relevant libraries and components also and export the Component created. Otherwise you can take a look at the code repository for this blog.

What is Hasura?

Hasura is a PaaS with BaaS components. 
PaaS stands for platform as a service. It allows developers, IT professionals, and business leaders to develop, test, and deploy the next generation of applications in the cloud in a secure, cost-effective manner that speeds time to market and increases competitive advantage.

BaaS stands for Backend as a service. It is a model for providing web app and mobile app developers with a way to link their applications to backend cloud storage and APIs exposed by back end applications while also providing features such as user management, push notifications, and integration with social networking services.

GraphQL, what is all the fuss about it?

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.

Hasura’s GraphQL Engine

The Hasura GraphQL Engine is an extremely lightweight, high performance product that gives you instant realtime GraphQL APIs on a Postgres database. This can be used to quickly build new applications on Postgres or fast-track the move to GraphQL for existing applications on Postgres.
It comes with a UI that lets you create and view tables on your database and make GraphQL queries using the embedded GraphiQL interface.

What we will be building

We will be creating a simple todo app which lets a user sign up or login and then manage todos by creating them, marking them as complete or deleting them if neccessary. User will also be able to see his all todos. Visit https://reacthasuratodo.herokuapp.com/ to see a demo of what we will be building.

Setting up developer environment

  1. Hasura GraphQL server
  2. node
  3. npm or yarn
  4. create-react-app
  5. Deploy your Hasura GraphQL engine to a server which will be used as an endpoint to make queries. Setting up a Hasura GraphQL takes atmost 1 minute. It can be easily deployed to Heroku via its one click deploy to heroku method. Click here to deploy your Hasura GraphQL Engine to a heroku server. Give your heroku app a name and click on deploy app.
    Your Hasura GraphQL UI will be live at appname.herokuapp.com
Hasura One Click Deploy to Heroku

To secure your Hasura graphql server, add an environment variable HASURA_GRAPHQL_ACCESS_KEY on Heroku and keep its value to something you can remember. This access key will be asked whenever you try to login on the Hasura Graphql server.

2. Install node and npm in your system.

  • On a ubuntu based OS:
curl-sL https://deb.nodesource.com/setup_8.x | sudo bash -
sudo apt install nodejs

The above command installs both node and npm in your system.

  • On Windows:
    Download the relevant package from here and install it.

3. Installing create-react-app (I’ll be using yarn instead of npm)

  • create-react-app is a script developed by Facebook to setup a react app with all the neccessary directory structure and node_modules.
  • Install create-react-app using the following command.
yarn global add create-react-app

This installs create-react-app globally on your system.

Creating a react app

Create a new react app using create-react-app reacthasuratodo 
On successful completion of the command, you will see a similar output as in the image. Now open your code editor in the react app directory just created.

Setting up a React app

Change your terminal present working directory to react app directory and run yarn start. Server will start and you should be able to see a welcome to react screen on http://localhost:3000. This means your react app is running fine.

Live React app

I’ll be using react-bootstrap package for the styling so install the package using yarn add react-bootstrap. Make sure to add the stylesheet in /public/index.html. Complete documentation for react-bootstrap package can be found here.

Using auth0 as authentication for the todo app.

auth0 is a universal authentication & authorization platform.

Including auth0 in your react app includes the following steps:
1. Sign up on https://auth0.com and create a new application.
2. Adding a callback url in auth0 console.
3. Creating an Auth class.
4. Creating history.js
5. Creating a Callback component
6. Creating routes
7. Changing App.js to include auth urls
8. Rendering routes instead of App js.

Sign up on https://auth0.com and create a new application for your react app. Provide a relevant name to your auth0 application and headover to settings tab to configure it with your react app.
In settings tab under Allowed Callback Urls add http://localhost:3000/callback as it will be the callback url on dev environment after authentication completes.

Now install auth0 in your react app by executing yarn add auth0-js.
auth0 has a great react quick start documentation written on their website to include auth0 in your react app.

Create a new file in src/Auth/as Auth.js. We’ll be creating an Auth class which will handle the authentication.

Copy your auth0 clientID from your auth0 application and paste it in Auth.js. If you are following from auth0 docs then make sure to add localStorage.setItem('sub', authResult.idTokenPayload.sub) in setSession() function and localStorage.removeItem('sub', authResult.idTokenPayload.sub) in logout() function. This will store the user id in local storage.

history.js

Create a file history.js and make its content as in image. Also change App.js to include login, logout and home buttons.

Auth.js and App.js

Create a callback.js component which will be shown to user when authorisation is completed.
Create a routes.js to include different routes on which different components will be shown and a route on which authorisation will take place.
The content for all the files can be found on auth0 react quick start documentation.

Writing queries in GraphQL

There are 3 different types of queries in graphql, query, mutation and subscription. GET queries are completed by query while insert, delete and update queries are completed by mutation. Subscription listens to any change in event happening, for instance if a new entry is added to table then through subscription it can be notified. This prevents using a GET query all over again.

Create a new table on Hasura API Explorer named todos. It will have the following fields:
1. todo_id: Integer (auto increment)
2. todo_text: Text
3. todo_mark: Boolean
4. todo_user: Text

  • todo_id will be the todo number which will automatically increment on every new creation.
  • todo_text will store the text of todo.
  • todo_mark is a field which will be true if the todo has been completed and false in case it hasn’t been completed.
  • todo_user will store the user id of the user logged in.
Creating a table on Hasura

Add table permissions so that every user can access only its data.

  1. Create a new role user.
  2. For insert chose with custom checks
    Select todo_user as the field, make it _eq to X-HASURA-USER-ID
  3. For select chose with same checks as ---- and select all columns for access.
  4. For update chose with same checks as ---- and give access only to todo_mark column.
  5. For delete chose with same checks as ----.

Writing a GET query

Writing queries in graphql is easy, specify the table name then the fields you want to be in the response. If you want to do selective search then where and order_by can be provided after the table name specification.

A sample query to get all the values in todos table is as follow:

query {
todos{
todo_id
todo_text
todo_mark
todo_user
}
}

general format for a query is:

query query_name {
table_name (where, orderby or pagination expression)]{
table fields in response
}
}

Writing a mutation

Mutation consists of Insert, Update and Deletions.
General format for writing a mutation query is

mutation mutation-name {
mutation-type_table-name (
expressions to identify row and changing data
)
affected_rows
}

A simple insert query for todos table will look like this:

mutation {
insert_todos(
objects: [
{
todo_text: "Complete react app",
todo_user: "auth0|20390123821398"
}
]
){
affected_rows
}
}

A simple update query for todos table will look like this:

mutation {
update_todos(
where: {todo_id: {_eq: 1}}
_set: {todo_mark: true}
){
affected_rows
}
}

A simple delete query for todos table will look like this:

mutation {
delete_todos(
where: {todo_id: {_eq:1}}
){
affected_rows
}
}

Now we are ready to create the frontend using react and query the db to create and utilise todos.

Coding the frontend using React

We’ll be using React Apollo Client to make interact with graphql server and make queries in React. Install apollo client using npm install apollo-boost react-apollo graphql --save or yarn add apollo-boost react-apollo graphql.

There will be the following main components:
1. One parent component wrapping all the components in apollo provider component.
2. GetTodos component to display all the pending todos to the user.
3. AddTodos component to add a todo.
4. MarkTodo component to mark a todo as completed.
5. DeleteTodo component to delete a todo.
6. GetAllTodos component to fetch all the todos created till now for a user.

  1. Home.js The parent component.
    This component will act as a parent component for all other components, we’ll wrap the child component in an ApolloProvider which will enable us to use apollo client to make graphql queries in the complete app. ApolloProvider requires a client prop with a ApolloClient object. This allows us to make authorised requests. Import ApolloClient from apollo-boost and ApolloProvider from react-apollo. Create a ApolloClient object as follows
    To use user authentication, pass the user access token in the headers as Authorization. This will let the Hasura know which user is sending a request to the graphql server. A separate authentication webhook needs to be deployed to allow token authentication. Deploy the webhook to heroku or any other service. It’s easy to deploy using heroku one click deploy. After that configure the HASURA_GRAPHQL_AUTH_HOOK environment variable in your Hasura Server to your deployed webhook url. Use /auth0/webhookfor auth0 authentication.
Home.js

2. GetTodos will fetch all the incomplete todos from the database and display them to the user. This component requires the use of React Apollo’s Query component. We first need to write a graphql query to fetch all the incomplete todos from todos table. The method to write a query remains the same as explained above. In react, you need to enclose that query in gql``. gql is imported from graphql-tag which let the apollo client know that the text enclosed within this text is a graphql query. To keep the code clean, we’ll create a queries.js and write all the graphql queries in it.

get incomplete todos query

We’ll use this query to fetch all the incomplete todos. In GetTodos component, we’ll be using Apollo’s Query Tag. Create a Apollo Query and pass the graphql query in it as a query prop. A function inside the Query component will check for the query’s current state (loading), error if present and the data on completion. The data will have all the todos in it, we’ll just iterate over the data and display the relevant content to the user. There should be an option to mark the todo as completed or delete the todo, so we’ll create those components and render along side the data recevied. Finally after all the todos are rendered we’ll give the user an option to add a new todo, we’ll create an AddTodo component for the same and render it next to the Todos shown to the user.

GetTodos component

3. AddTodo component will be used to send an insert request to the hasura graphql server to add a new todo entry in the database. This component will require the use of graphql’s mutation request and Apollo’s Mutation Component.

Query to insert a new todo

Here we will be using variables in the mutation query which will be received from Apollo’s Mutation component. This component will consist of a form which will take the todo_text input from the user and send that to the mutation query as a variable. Create a Mutation component and pass the name of graphql query in mutation prop. Inside a mutation is a function with 2 arguments, first one being the type of mutation and second being an optional data. Insert type of mutation requires todo_text and todo_user as a variable. Any extra data to be sent along the query is included in a dictionary. All the variables are included in a dictionary with variable name as key and its value as dictionary. This variable dictionary is assigned to a variables key in the extra data dictionary. Mutation changes the state of the database, this means if we add a new todo to the database then it should be shown to the user in the list of incomplete todos. This is achieved by refetchQueries. refetchQueries is a list of dictionaries with each dictionary containing the name of query to execute on mutation completion. We’ll refetch all the todos whenever a new todo is added to the database.

AddTodos Component

4. MarkTodo component will be used to send an update request to the database for a particular todo to change its todo_mark value from false to true.

Mutation Query for marking a todo as completed

In the MarkTodo component, Create a Mutation component and pass the name of graphql query in mutation prop. MarkTodo component is similar to AddTodos except that AddTodo inserts a new entry while MarkTodo updates an exisiting entry in the database.

Pass the id of todo as a variable to update mutation so that the todo_mark value can be changed in the database. Refetch all the todos on mutation completion.

MarkTodo Component

5. In the same way as MarkTodo, we’ll create a DeleteTodo component. This will allow a user to delete the todo completely from the database. Everything will be same as in MarkTodo except that we’ll use delete_todos as type of mutation.

Query to delete a todo
DeleteTodo Component

6. Finally we’ll create a GetAllTodos component to show users all the todos he has created till now. It will consist of both completed and non completed todos. This component will use a GET query on the todos table and we’ll order the todos by most recently created non completed todos first. Using conditional rendering in react we can style the incomplete todos and completed todos differently.

GetAllTodos Component and Query

Run the server using yarn start. Head over to http://localhost:3000 to test your app.

And that’s it, it’s that easy to create a React Todo App with Hasura Graphql Engine. You can extend it to include more features and a better look and feel. Deploy your react app to Heroku or any other hosting service so that everyone over the internet can use it.

You can find the source code for this blog here.

Keep Coding!!!

Useful Resources used while creating the todo app:
1. Hasura GraphQL Engine Documentation
2. React Apollo GraphQL Documentation
3. Auth0 React Quickstart
4. Official GraphQL Documentation

About Me

My name is Anupam Dagar. I am an undergraduate student at the Indian Institute of Information Technology, Allahabad (A Centre of Excellence in Information Technology established by Ministry of HRD, Govt. of India), pursuing my B.Tech degree in Information Technology.

I love creating and learning new things when I don’t have an overhead of college assignments. I love to code in Python and JavaScript. I am an opensource contributor and currently a GitHub Campus Expert in India.

You can follow me on LinkedIn, Twitter and GitHub.

More by Anupam Dagar

More Related Stories