Building scalable Flutter apps using GraphQL, Hasura and event-driven serverless, Part 1 - Setting up Hasura
Tags: flutter, serverless, graphql, firebase
Published: 2019-12-17 10:25:52

---
title: Building scalable Flutter apps using GraphQL, Hasura and event-driven serverless, Part 1 - Setting up Hasura
published: true
date: 2019-09-04 14:55:42 UTC
tags: flutter, serverless, graphql, firebase
canonical_url: https://blog.hasura.io/build-flutter-app-graphql-hasura-serverless-part1/
---

![](https://blog.hasura.io/content/images/2019/09/hasura-flutter-wo-border-9.png)

_This tutorial was written by_ [_Can Taşpınar_](https://twitter.com/cntaspinar) _and published as part of the [Hasura Technical Writer Program](https://blog.hasura.io/the-hasura-technical-writer-program/) - an initiative that supports authors who write guides and tutorials for the open source Hasura GraphQL Engine._

## Introduction

In this blog post we are going to make a quiz app with Flutter powered by Hasura and Firebase. We are going to see how Hasura can work with Firebase services such as Authentication and Cloud Functions to handle user authentication and business logic. Combining these services together will provide us a flexible and scalable architecture.

This will be a 3-part series. In this first part, we are going to deploy Hasura and we will see how to model the relational data with permissions.

> **[Part 2](https://blog.hasura.io/build-flutter-app-hasura-firebase-part2/)** will cover how to setup Auth with Firebase and Hasura. **[Part 3](https://blog.hasura.io/build-flutter-app-hasura-firebase-part3/)** will cover how to make the flutter frontend.

## Hasura Deployment on Heroku

Deploy Hasura less than a minute by using the Heroku button below.

[![Hasura on Heroku](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/hasura/graphql-engine-heroku)

When it is done, you can access the Hasura Console by opening your Heroku app URL.

![](https://lh4.googleusercontent.com/v-3Vr6HW_RFoWDQ28BBEwAw6p_ogVDSlmX_VYZDtLNZwBkWdKOtPaK1SNuv2zl4EHeZH3WJRY0Rg_ZF22P3K6RI65jSk6RnyyyArlinuFNl72Gvz1nAhA7LS-qAuNIRMBnHmuHmt_T6DCpjQqA)

## Modelling Data

Let’s start with modelling our data first. We are going to define columns, relationships and permissions. Hasura makes it easy to create relationships by tracking foreign keys in tables and suggesting possible relationships. By setting permissions you can restrict access for rows and columns for users by their role.

Head to the **Data \> Add Table**

**HINT:** You can use the “Frequently used columns” for these frequently used types:

![](https://lh6.googleusercontent.com/FJf8sgAO4IR0lMcafhL30XZacWFAmtWIORxQSWaepZsuxMyuZIbk1-iOq7eLzCPoL2NskIi8ynt3gAE2EY2sXIIej4eGOKXKJk54VyDfD8m3h6KwtREqyNvt0-5KkpduCuyny7EWWyP3uYOcfA)

### Table: users

`id`, `email`, `name` columns will be filled by the data coming from Firebase. Notice that `id` here is type of `Text` **.** We are going to talk more about that later on. `score` column will be incremented if the user submits the correct answer. `created_at` will be set to now when a new user is inserted to the table. Let’s set `id` as the primary key.

![](https://lh5.googleusercontent.com/FD7xc7jhD0iaN9aWqxSqh42OcI1JEMGPWzHoYJXEODcct80l4A-7XZ-jveITt2PKMpXsF3oRRTjoE_Sf5NRr4PLm3LhQt4s9itN5xoDjOfO4fbimFMzTjo9Rskmb5al8QKghP0PsPdFUoWOufw)

After creating table head to the **Permissions** tab. For now, there is only one role which is admin and it has full access on every operation below. Enter a new role called “user”. For users table we are only going to give select permissions. A user should be able to see other’s name and score. We are mostly going to deal with following rules when we are adjusting select permissions.

- **Row select permissions** to restrict access to rows.
- **Column select permissions** to restrict access for certain columns

We don’t need a custom check for **Row select permissions.** For the **Column select permissions,** check only name and score columns. This way we ensure that users can only see these fields.

![](https://lh5.googleusercontent.com/tPoUpEBQ21lfGtGwl9lh9NCwXVSUlei26wk5Dw7jnq-u_aM58VsYTCYn0z6UuRbFupcCXag7CXpy4UQlMYN4tjGc_GQNthBMTTmYCdPCOOYQlrKl2XLo6CuQhGENqUv80p9hR-Nq4kinnpGDxw)

**Table: questions**

`id` is a field with type UUID and the primary key. Default function `gen_random_uuid()` will generate a unique UUID whenever a new object is inserted to the table. **question** is the question title and `created_at` will be used for ordering questions later.

![](https://lh6.googleusercontent.com/QnD-yJINYpNKbZbZvLdIAW8kkGQWq_DFuBZ1jL39FowBVmdVirTRuQTeHTXl8bbyBA4OxaTtP8H_lvCYtvEA6K6IiP_baonef2OcQ26WGUnWi8TNoLgC69vEN-iTumHBnK73eZ3M4n096KkvXw)

For permissions, every user can make a query to get the questions, so we have the following permission for the questions table.

![](https://lh3.googleusercontent.com/sCZq4JIavAe3GkjcGrGc2Eo4lc1UjmBRzts6L6RB9P_klBuWEZtL3Zf41Ap1V83R93-AI5QpAJ4In5ttdgC5eaSgZ3lHQPSTeVGdmyCnNbjcEXgrWkUyiLeMUHTV65Fss7jELm5lyDIFT49FuA)

**Table: question\_answers**

`id` is again type of UUID and the primary key for the table. `answer` is the question answer. Since we are going to give multiple answer options for a question, we need to know which answer is the correct one. To do that we have the `is_correct` column with a type of Boolean.

![](https://lh6.googleusercontent.com/xO1inQ80rKx0tfxt56AW6ONxAOISs42YL8m9PeLiS5L9GITgFWy5hH8CXF53diVZGUoWLKAYcaCTsalruYabqzr6kvNpyCgYk_K31V_jHE7ABl5aui6-jfgIFv99xFkomin6X9TEU4BkLriQ_Q)

`question_id` is here to point out which question this answer belongs to. So, it will be a foreign key.

![](https://lh5.googleusercontent.com/1NNa8LecWsOkHXV516uUH8CU02uKlLlZyItgkGi6XD-1sSHiPR1l2tN2PVlp8v0rt4KbCqAgPQzCM3pH-TasDmW79UyzvyW8GdXHtWOGOZKEaBbYcm-sQTs0OQor5BD3IPq1899bEbPVgkIe0A)

Users should be able to make a query to get the possible answers of a question. Permissions for this table is as below.

![](https://lh6.googleusercontent.com/KLzZvPOcCWOuGGDpQaLtrmlUP1SApyerBDiY2NjeIo-VeNFShRE6En_f7QwJ4EPJdjsgw09s_wZm7q-aj95EKb0iARpThMNhmzCJthM63qzcjgainDF7z9P6BTm9aPOBnbFU42cytVMOTnaCww)

**Table: user\_answers**

`id` is type of UUID and primary key. `user_id`, `question_id` and `answer_id` are foreign keys to point out to other tables. Notice that `user_id` column is type of Text instead of UUID. This is because we defined the `id` field in `users` table as Text. This is because it will be filled by the value coming from Firebase Authentication and Firebase user id is a string.  

![](https://lh5.googleusercontent.com/26T4TJJN3ngAQdiAXvP0HEF0wNIFQYUCdlBTbEsA1f4jBFbXdDG1HKXlHEeScp02IAgbH7-2gcupp5eu5CwNlN2hdT3dT-1l7AXX8mFvXVMi0d93aCBM_MIUkTZhLYNj5hdPf10XOXOM1xJt9w)

![](https://lh3.googleusercontent.com/xVDmaq3S29rdU2s1MPva1Wm81Y1yPX6GrW2ENvHelDAk_wpFZlbPV4ufMOOTb4_AZ6-Kgp-uFjR9-YCbZm2YyWpzYaBa4G_kmcIPA5KE4fPk0kGngDTcbSWSQQYN5VY8pY-4V0KXqUKvRpg3jA)

For the permission part, we are going to allow users to insert answers, but we need to make sure a user can only insert an answer if the request is coming from the same user. In other words, a user can’t insert a new record on behalf of someone else. This is where **Sessions Variables** comes in. Hit with **custom check** box and give the following rule.

![](https://lh5.googleusercontent.com/62bwGMdzCAxGGxDpYluGb54pFt0O_AuPofuRwItj3jF5Dxw_P6ozY6PYwa2cdp5Q6DYQMudQTwggRS6ZBK7-hEwDgb6d4ZyYO2dRiY8Ua_W12QFCnePS9zYQI_aSuDcI81aPXYrQElW_wfvKKw)

Every request from user that comes to the GraphQL API, will include a `X-Hasura-User-Id` header. We are going to talk more on that in Authentication part. Last thing we need to do is to set to the `user_id` field automatically from the `X-Hasura-User-Id` header. For that we are going to make use of **Column presets.** This allow a column to be filled by a static value or a session variable in our case.

![](https://lh3.googleusercontent.com/hh0vLoHMI8Xg4lez0EQJd4YHyo2jAhIKSxD7vGTswg9532M1xDZCxRDYxn2hx6_pyDjAidGwdyYYxwQ52zkrFmA-S2i-zhOwxIOzxioXs9KD12wsC9zpzHXiVeMi093-iswljL-D7aXomaXc1w)

At the end insert permissions for user\_answers table should look like below.

![](https://lh5.googleusercontent.com/KbtNVXx75bcIanGGwcV1ua7h1moeIH997QgB8m_RQHW04BeIC5nPreSZiauemkRE4N6QYPbeNXpNGle22uZ6KCEwvy0_eSt3l6uWlIjY9Qp9jHa_fUJTouZG12W-O66rPs4gidc-5G7SkQcMHA)

Now that we defined our tables, it is time to create relationships for GraphQL API. Head to the **Data** tab. Hasura tells you about the Untracked foreign-key relations. Hit **Track All** to expose these relations over GraphQL API.

![](https://lh5.googleusercontent.com/nSm2v-FI8ItmvOqCaY6N5JZf0knFzMhXHRSlpRPKGUtjdheajlJNvQrEoq7m2QBU9E_PnZ7AGCCht1QzNKxx1d3bbL5Sp-Kmfo3PyP2GabJ6yo8BDZbc4DO23FLisKc8vFUp1mgfttlqZ0fcpg)

To sum things up, we defined the tables, gave permissions and tracked relationships. Hasura already prepared our API for us at this point. You can head to the **GRAPHIQL** tab and explore the API. There is one last thing to do before we move on. We need a way to query the questions that hasn’t been answered by the user. To do that, we can create a PostgreSQL function with an argument. Hasura will again magically track this function and expose it over GraphQL API. Head to **Data** \> **SQL.** In here, you can write raw SQL. It can be for creating triggers, views or a function in our case. Write the following code and don’t forget to check **Track this** box. This box will tell Hasura to track this function and expose it over GraphQL API.

```
CREATE
OR REPLACE FUNCTION public.unanswered_questions(userid text) RETURNS SETOF questions LANGUAGE sql STABLE AS $ function $
SELECT
  *
FROM
  questions
WHERE
  id NOT IN (
    SELECT
      question_id
    FROM
      user_answers
    WHERE
      user_id = userID
  ) $ function $
```

After you click Run, the function will take its place below the tables on the sidebar.

![](https://lh4.googleusercontent.com/1jC1t-j7CZJxrwO5-NptuYZ18l3geb4Dgz9zqgkTjRxyKaNVi476eTneG7LscDSO5W8NnjcigtnDCfaa8r5CYr86hoQykX6RHfM2c5tF550ZaUNvxTnfnV4VZkmjsiSBORIlRM2Ub5H75nG-SQ)

Now that we have deployed Hasura and modeled the data & relationships, we have can move on to the next step. In **[Part 2](https://blog.hasura.io/build-flutter-app-hasura-firebase-part2/)** we are going to prepare Auth and Business Logic by integrating Firebase services. **[Part 3](https://blog.hasura.io/build-flutter-app-hasura-firebase-part3/)** will cover how to to make the Flutter frontend.

## About the Author

[Can Taşpınar](https://twitter.com/cntaspinar) is passionate and enthusiastic developer whose journey started with the question “How to make a video game?”Moving on with mobile application development and Full Stack Web development. Enjoys working with modern and open source technologies.