<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Amolo</title>
    <description>The latest articles on Forem by Amolo (@amolo).</description>
    <link>https://forem.com/amolo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F156464%2F5e8edfcc-801e-4c79-94bc-83106097b26b.jpeg</url>
      <title>Forem: Amolo</title>
      <link>https://forem.com/amolo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/amolo"/>
    <language>en</language>
    <item>
      <title>Build a Realtime Serverless Trivia app using Fauna Streaming And React.js On Netlify</title>
      <dc:creator>Amolo</dc:creator>
      <pubDate>Fri, 10 Dec 2021 07:08:11 +0000</pubDate>
      <link>https://forem.com/amolo/build-a-serverless-realtime-trivia-app-using-fauna-streaming-and-reactjs-on-netlify-8md</link>
      <guid>https://forem.com/amolo/build-a-serverless-realtime-trivia-app-using-fauna-streaming-and-reactjs-on-netlify-8md</guid>
      <description>&lt;h3&gt;
  
  
  INTRODUCTION
&lt;/h3&gt;

&lt;p&gt;As a developer, building applications that users can interact with in real-time has become a norm for most of the developers. Most of the applications we see and interact with have at least a single real-time feature included. Real-time messaging, notifications are just two of commonly used real-time features used in applications.&lt;br&gt;
While building applications it is not always clear how to achieve real time functionality, there exists a number due to many available technologies and platforms, complexity of setting up, provision of resources, scaling etc.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://fauna.com/?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=WritewithFauna_Trvia_BAmolo"&gt;FAUNA&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://fauna.com/features?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=WritewithFauna_Trvia_BAmolo"&gt;Fauna’s&lt;/a&gt; database is well optimized for the JamStack through its API first approach while offering powerful and useful  query features through its own query language (FQL).&lt;br&gt;
Fauna provides a variety of features including Streams. Using Streams, client code can subscribe to a document stored in a Fauna database and any changes to that document are immediately streamed to the client as event notifications. &lt;br&gt;
With this, you can immediately interact with your users and maintain a consistent and high-level user experience, as well as keep your information and data constantly updated.&lt;br&gt;
In this tutorial we will use React, Fauna and Netlify &amp;amp; Netlify Functions to build out a realtime serverless application.&lt;/p&gt;
&lt;h3&gt;
  
  
  TUTORIAL APPLICATION
&lt;/h3&gt;

&lt;p&gt;As stated in our title, our application will simply allow you to post questions, following this, a user will be able to answer these questions. We will also maintain a real time leaderboard just to see how well one is stacking up against other players.&lt;/p&gt;

&lt;p&gt;This application will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Allow users to answer questions &lt;/li&gt;
&lt;li&gt;Get their scores in real time&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Project Setup
&lt;/h3&gt;

&lt;p&gt;The recommended way to initialize a blank React app is by using create-react-app which sets up everything automatically for you. &lt;/p&gt;

&lt;p&gt;You will be required to either have yarn or npm installed.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;yarn create react-app trivia&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once this is complete,cd into the folder. &lt;br&gt;
&lt;code&gt;cd trivia&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To quickly build out our UI, we will take advantage of Chakra UI  which is a simple, modular and accessible component library that gives you the building blocks you need to quickly build your React applications.&lt;/p&gt;

&lt;p&gt;To install Chakra UI simply use yarn or npm to do that.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;yarn add @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^4&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Basic Application Structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── package.json
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
├── README.md
├── src
│   ├── App.css
│   ├── App.js
│   ├── App.test.js
│   ├── index.css
│   ├── index.js
│   ├── reportWebVitals.js
│   └── setupTests.js
└── yarn.lock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Installing Fauna
&lt;/h4&gt;

&lt;p&gt;Install the faunadb npm package to allow our application to interact with our Fauna Instance.&lt;br&gt;
&lt;code&gt;yarn add faunadb&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Setup your Fauna database.
&lt;/h4&gt;

&lt;p&gt;To hold all our application’s data, we will first need to create a database. &lt;br&gt;
Fortunately, this is just a single command or line of code, as shown below. &lt;br&gt;
Don’t forget to create a Fauna account before continuing.&lt;br&gt;
Fauna Shell&lt;br&gt;
Fauna's API has various interfaces/clients, such as drivers in Javascript, Golang, Python, Java and more, a cloud console, local and cloud shells, and even a VS Code extension! For this article, we’ll start with the local Fauna Shell, which is almost 100% interchangeable with the other interfaces.&lt;/p&gt;

&lt;p&gt;You will first be required to install the Fauna shell on your machine with the following command.&lt;br&gt;
&lt;code&gt;npm install -g fauna-shell&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After installing the Fauna Shell with yarn, log in with your Fauna credentials using the fauna cloud-login command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ fauna cloud-login
For email login, enter your email below, and then your password.
For login with 3rd-party identity providers like Github or Netlify, please acquire a key from 
Dashboard &amp;gt; Security and enter it below instead.

Email: email@example.com
Password: **********
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are able to create our database.&lt;br&gt;
&lt;code&gt;fauna create-database trivia&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Create Collections and Indexes.
&lt;/h3&gt;

&lt;p&gt;To start a shell with your new database, run:&lt;br&gt;
fauna shell trivia&lt;/p&gt;

&lt;p&gt;We can now operate our database from this shell.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ fauna shell trivia
Starting shell for database trivia
Connected to https://db.fauna.com
Type Ctrl+D or .exit to exit the shell
trivia&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the case of our application, we will have two collections.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Questions - This will hold information about the questions.&lt;/li&gt;
&lt;li&gt;Answers - The responses provided by the users. We will also use this collection to grade the responses.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  DATA SCHEMA
&lt;/h4&gt;

&lt;h3&gt;
  
  
  Questions Collection
&lt;/h3&gt;

&lt;p&gt;Each question will have the following fields &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;question_text - A questions eg. “Does Next.js support SSR or SSG?”&lt;/li&gt;
&lt;li&gt;correct_answer - The correct answer to the question asked in (1)  eg. “Both”&lt;/li&gt;
&lt;li&gt;options - Distractors to the correct answer eg. [“SSR”, “SSG”]&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Answers Collection
&lt;/h3&gt;

&lt;p&gt;Each question response (answer) will have the following fields &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;question_id - a  reference to the question in the questions collection. &lt;/li&gt;
&lt;li&gt;user_id - A unique identifier for the respondent.(This value will be automatically generated and stored in the browser.)&lt;/li&gt;
&lt;li&gt;response - The user’s response from a list of possible options.&lt;/li&gt;
&lt;li&gt;isCorrect - A Boolean value to indicate it the answer provided is their correct (true) or incorrect (false) &lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Creating collections
&lt;/h3&gt;

&lt;p&gt;To create our questions collection, run the following command in the shell to create the collection with the default configuration.&lt;br&gt;
&lt;code&gt;trivia&amp;gt; CreateCollection({ name: "questions" })&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next, let’s do the same for the answers’ collections.&lt;br&gt;
&lt;code&gt;trivia&amp;gt; CreateCollection({ name: "answers" })&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Lastly, let’s do the same for the scores’ collections.&lt;br&gt;
&lt;code&gt;trivia&amp;gt; CreateCollection({ name: "scores" })&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;INDEXING OUR DATA.&lt;/p&gt;

&lt;p&gt;Fauna highly recommends indexing your data for the purposes of searching, sorting and combining results from multiple collections.&lt;/p&gt;

&lt;p&gt;In this application, a user will be allowed to attempt and respond to a question only once. We can enforce this constraint in our answers collection by creating an index as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;qna&amp;gt; CreateIndex({
name: "unique_question_user",
   unique: true,
   serialized: true,
   source: Collection("answers"),
   terms: [
     {
       field: ["data", "user_id"]
     },
     {
       field: ["data", "question_id"]
     }
   ]
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  SAMPLE RESPONSE
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#SAMPLE RESPONSE…...
{
  ref: Index("unique_question_user"),
  ts: 1610301037970000,
  active: true,
  serialized: true,
  name: 'unique_question_user',
  unique: true,
  source: Collection("answers"),
  terms: [
    { field: [ 'data', 'user_id' ] },
    { field: [ 'data', 'question_id' ] }
  ],
  partitions: 1
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our second index is to enable us to quickly fetch a question based on the id.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CreateIndex({
  name: "question_by_id",
  source: Collection("questions"),
  terms: [
    {
      field: ["data", "id"]
    }
  ]
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly we will index our scores collection based on the user_id in order to allow faster retrieval and reads to this collection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CreateIndex({
  name: "score_by_user",
  source: Collection("scores"),
  terms: [
    {
      field: ["data", "user_id"]
    }
  ]
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SERVERLESS FUNCTIONS.&lt;/p&gt;

&lt;p&gt;We will create two Netlify functions,&lt;br&gt;
To create questions&lt;br&gt;
To retrieve question data and metadata from the database.&lt;br&gt;
To respond to the questions being asked and update the user’s scores.&lt;/p&gt;

&lt;p&gt;Now let’s create our first Netlify function. To make the functions, first, we need to install Netlify CLI globally.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;yarn global add netlify-cli -g&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now that the CLI is installed. We can create a key to allow our application to interact with Fauna.&lt;/p&gt;
&lt;h3&gt;
  
  
  CREATE A FAUNA KEY
&lt;/h3&gt;

&lt;p&gt;In order for our application to send and receive data to Fauna we will need to create a key and provide its secret when performing queries.&lt;br&gt;
For this application, a key with a Server Role is sufficient to create, read and delete data.&lt;br&gt;
Head over to your database’s Fauna Shell and create a key using the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CreateKey({
      name: "trivia-app",
      role: "server"
   })
# Example result.
# NOTE: Make sure you copy and store the secret!
# {
#   ref: Ref(Keys(), "280185139463529993"),
#     ts: 1603464278974000,
#     role: 'server',
#     secret: '&amp;lt;FaunaDB secret key&amp;gt;’',
#     hashed_secret: ...
# }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;let’s create a .env file on our project root with the following fields.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;netlify env:set FAUNADB_SERVER_SECRET “&amp;lt;FaunaDB secret key&amp;gt;”&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next, Let’s see how we can start with creating Netlify functions. For this, we will need to create a directory in our project root called functions and a file called netlify.toml, which will be responsible for maintaining configurations for our Netlify project. This file defines our function’s directory, build directory, and commands to execute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[build]
command = "npm run build"
functions = "functions/"
publish = "build"

[[redirects]]
  from = "/api/*"
  to = "/.netlify/functions/:splat"
  status = 200
  force = true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will do some additional configuration for the Netlify configuration file, like in the redirection section in this example. Notice that we are changing the default path of the Netlify function of /.netlify/** to /api/. This configuration is mainly for the improvement of the look and field of the API URL. So to trigger or call our function, we can use the path:&lt;/p&gt;

&lt;p&gt;First, let’s make a connection file for Fauna called lib/fauna.js, returning a Fauna connection object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const faunadb = require('faunadb');
const q = faunadb.query

const client = new faunadb.Client({
  secret: process.env.FAUNADB_SERVER_SECRET,
});

module.exports = { client, q };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We would &lt;/p&gt;

&lt;p&gt;For our first function, we create a file: functions/createQuestion.js  and add the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { client, q } = require("../src/lib/fauna");

exports.handler = async (event, context) =&amp;gt; {
  try {
    let { question, answer, options } = JSON.parse(event.body);
    let results = await client.query(
      q.Create(q.Collection("questions"), {data: { question, answer, options },}),
    );
    return {statusCode: 200, body: JSON.stringify({ id: results.ref.id, data: results.data }),};
  } catch (err) {
    return { statusCode: 500, body: JSON.stringify({ error: err.toString() }) };
  }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For our second function, we create a file: functions/getQuestion.js  and add the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { client, q } = require("../src/lib/fauna");

exports.handler = async (event, context) =&amp;gt; {
  try {
    let {id} = event.queryStringParameters
    let results = await client.query(q.Get(q.Ref(q.Collection("questions"), id )));
    return { statusCode: 200, body: JSON.stringify({ id: results.ref.id, data: results.data }),};
  } catch (err) {
    return { statusCode: 500, body: JSON.stringify({ error: err.toString() }) };
  }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For our last function create a functions/provideAnswer.js  and add the following to the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Docs on event and context https://www.netlify.com/docs/functions/#the-handler-method
const { client, q } = require("../src/lib/fauna");

exports.handler = async (event, context) =&amp;gt; {
  try {
    let { question_id, answer, user_id } = JSON.parse(event.body);

    // ensure no missing values
    if (!(question_id &amp;amp;&amp;amp; answer &amp;amp;&amp;amp; user_id)) {
      return {
        statusCode: 500,
        body: JSON.stringify({
          error: "Fields question_id &amp;amp; answer &amp;amp; user_id required ",
        }),
      };
    }

    let results = await client.query(
      q.Get(q.Ref(q.Collection("questions"), question_id)),
    );
    let question = results.data;
    let isCorrect = false;
    if (question.answer === answer) isCorrect = true;
    try {
      let query = await client.query(
        q.Create(q.Collection("answers"), {
          data: {
            question_id,
            user_id,
            isCorrect: isCorrect,
            response: answer,
          },
        }),
      );
      query.data.correct = question.correct_answer;
      if (isCorrect) {
        // update the user's score if correct
        try {
          let score = await client.query(
            q.Get(q.Ref(q.Collection("scores"), process.env.LEADERBOARD_ID)),
          );
          console.log("S", score,)
          let req = await client.query(
            q.Update(q.Ref(q.Collection("scores"), process.env.LEADERBOARD_ID), {
              data: { [user_id]: ( (user_id in score.data) ? (score.data[user_id] + 10) : 10) },
            }),
          );
        } catch (error) {
            console.log(error)
            return {
                statusCode: 500, body: JSON.stringify({ error: error.toString() }),};
        }
      }
      return {
        statusCode: 200,
        body: JSON.stringify({ ref: query.ref.id, data: query.data }),
      };
    } catch (error) {
      if (error.message === "instance not unique") {
        return {
          statusCode: 500,
          body: JSON.stringify({ error: "Question is already answered" }),
        };
      }
      return {
        statusCode: 500,
        body: JSON.stringify({ error: error.toString() }),
      };
    }
  } catch (err) {
    return { statusCode: 500, body: JSON.stringify({ error: err.toString() }) };
  }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  UI
&lt;/h3&gt;

&lt;p&gt;Now that we have all our function endpoints working. We can now work on the UI for this application.&lt;/p&gt;

&lt;h3&gt;
  
  
  REALTIME LEADERBOARD.
&lt;/h3&gt;

&lt;p&gt;For our real time leaderboard we will utilize Fauna Streaming which &lt;/p&gt;

&lt;p&gt;Create a server-only key to be able to  interact between the frontend&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {Box, Stack, useMediaQuery} from '@chakra-ui/react'
import {useEffect, useState} from 'react'
import {query as q, Client} from 'faunadb'
import rw from 'random-words'


function App() {

  let [isMobile] = useMediaQuery("(max-width:600px)");
  let [leaderboard, setLeaderboard] = useState(null)
  let client = new Client({
    secret: process.env.REACT_APP_FAUNA_CLIENT_SECRET
  })
  let stream
  const startStream = () =&amp;gt; {
    stream = client.stream.document(q.Ref(q.Collection('scores'), process.env.REACT_APP_LEADERBOARD_ID))
    .on('snapshot', snapshot =&amp;gt; {
      console.log("S", snapshot)
      setLeaderboard(snapshot.data)
    })
    .on('version', version =&amp;gt; {
      console.log("V", version)
      setLeaderboard(version.document.data)
    })
    .on('error', error =&amp;gt; {
      console.log('Error:', error)
      stream.close()
      setTimeout(startStream, 1000)
    })
    .start()
  }

  useEffect(()=&amp;gt;{

    if(! window.localStorage.getItem("user_id")){
      window.localStorage.setItem("user_id", `${rw()}_${Math.floor((Math.random() * 999) + 900)}` )
    }
    startStream()

  }, [])

  return (
    &amp;lt;div className=""&amp;gt;
      &amp;lt;Stack direction={isMobile ? "column" : "column"} p="64"&amp;gt;
        &amp;lt;h3&amp;gt;Leaderboard&amp;lt;/h3&amp;gt;
        {leaderboard &amp;amp;&amp;amp; Object.keys(leaderboard).map((k)=&amp;gt;{
          console.log(k,)
          return &amp;lt;&amp;gt;&amp;lt;h4&amp;gt;{`${k} ------------ ${leaderboard[k]}`}&amp;lt;/h4&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;/&amp;gt;
        })} 
      &amp;lt;/Stack&amp;gt;

    &amp;lt;/div&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  DEPLOYING TO NETLIFY.
&lt;/h3&gt;

&lt;p&gt;When deploying your site, you can easily set your environment variables with the Netlify CLI using the netlify env:set command..&lt;/p&gt;

&lt;p&gt;Deploying to Netlify is relatively easy, all you need to do is to create a git repository. &lt;br&gt;
This is a good practice as you are able to easily version control your entire application.&lt;br&gt;
Next, commit your changes and push to the repository you created.&lt;br&gt;
On the Netlify GUI, go to [New Site from Git]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kZXHmWpF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t527t0vyqi0go1rr0nem.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kZXHmWpF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t527t0vyqi0go1rr0nem.png" alt="Deploy to Netlify" width="880" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then select your desired project and Netlify will take care of the building, provisioning and deploying.&lt;br&gt;
Once it's done, you will be provided with a URL to access your application. &lt;br&gt;
Wasn’t that easy?&lt;/p&gt;

</description>
      <category>fauna</category>
      <category>netlify</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to develop a fullstack Q&amp;A app with Fauna and Next.js</title>
      <dc:creator>Amolo</dc:creator>
      <pubDate>Thu, 21 Jan 2021 17:38:56 +0000</pubDate>
      <link>https://forem.com/amolo/how-to-develop-a-fullstack-q-a-app-with-fauna-and-next-js-335j</link>
      <guid>https://forem.com/amolo/how-to-develop-a-fullstack-q-a-app-with-fauna-and-next-js-335j</guid>
      <description>&lt;h4&gt;
  
  
  INTRODUCTION
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://nextjs.org" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; is a powerful open source React framework. It enables features such as server-side rendering, API routes that  you can use to build REST API endpoints within your Next.js app and consume it within the same app or any other app. This way, the frontend and backend can also be unified into a single codebase.&lt;br&gt;
&lt;a href="https://fauna.com/features" rel="noopener noreferrer"&gt;Fauna&lt;/a&gt;’s database is well optimized for the JamStack through its API first approach while offering powerful and useful  query features through its own query language (FQL).&lt;br&gt;
In this tutorial we will use Next.js and Fauna to build out a  full stack Q&amp;amp;A application.&lt;br&gt;
This application will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Allow users to answer questions &lt;/li&gt;
&lt;li&gt;Get their scores in real time&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;
  
  
  Project Setup.
&lt;/h4&gt;

&lt;p&gt;The recommended way to initialize a Next.js app is by using create-next-app which sets up everything automatically for you. &lt;/p&gt;

&lt;p&gt;You will be required to either have yarn or npm installed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn create next-app qna
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you prefer to use npx you can run the below equivalent command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-next-app qna
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once this is complete,&lt;code&gt;cd&lt;/code&gt; into the folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd qna
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Basic Application Structure
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── package.json
├── pages
│   ├── api
│   ├── _app.js
│   └── index.js
├── public
│   ├── favicon.ico
│   └── vercel.svg
├── README.md
├── styles
│   ├── globals.css
│   └── Home.module.css
└── yarn.lock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the &lt;code&gt;faunadb&lt;/code&gt; npm package to allow our application to interact with our Fauna Instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add faunadb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Setup your Fauna database.
&lt;/h4&gt;

&lt;p&gt;To store all our application’s data, we will first need to create a database. &lt;br&gt;
Fortunately, this is just a single command or line of code, as shown below. &lt;br&gt;
Don’t forget to create a &lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=WritewithFauna_Q&amp;amp;A_BAmolo" rel="noopener noreferrer"&gt;Fauna&lt;/a&gt; account before continuing.&lt;/p&gt;
&lt;h4&gt;
  
  
  Fauna Shell
&lt;/h4&gt;

&lt;p&gt;Fauna's API has various interfaces/clients, such as drivers in Javascript, Golang, Python, Java and more, a cloud console, local and cloud shells, and even a VS Code extension! For this article, we’ll start with the local Fauna Shell, which is almost 100% interchangeable with the other interfaces.&lt;/p&gt;

&lt;p&gt;You will first be required to install the Fauna shell on your machine with the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g fauna-shell
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installing the &lt;a href="https://docs.fauna.com/fauna/current/integrations/shell/index.html" rel="noopener noreferrer"&gt;Fauna Shell&lt;/a&gt; with npm or yarn, log in with your Fauna credentials using the &lt;code&gt;fauna cloud-login&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ fauna cloud-login
For email login, enter your email below, and then your password.
For login with 3rd-party identity providers like Github or Netlify, please acquire a key from 
Dashboard &amp;gt; Security and enter it below instead.

Email: email@example.com
Password: **********
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are able to create our database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fauna create-database qna
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Create Collections and Indexes.
&lt;/h4&gt;

&lt;p&gt;To start a shell with your new database, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fauna shell qna
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now operate our database from this shell.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ fauna shell qna
Starting shell for database qna
Connected to https://db.fauna.com
Type Ctrl+D or .exit to exit the shell
qna&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the case of our application, we will have two collections.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Questions - This will hold information about the questions.&lt;/li&gt;
&lt;li&gt;Answers - The responses provided by the users. We will also use this collection to grade the responses.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Creating collections
&lt;/h4&gt;

&lt;p&gt;To create our questions collection, run the following command in the shell to create the collection with the default configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;qna&amp;gt; CreateCollection({ name: "questions" })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, let’s do the same for the answers collections.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;qna&amp;gt; CreateCollection({ name: "answers" })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected Output&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ff0l9fi3qlnnm6k4lfj2t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ff0l9fi3qlnnm6k4lfj2t.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  DATA SCHEMA
&lt;/h4&gt;

&lt;h4&gt;
  
  
  Questions Collection
&lt;/h4&gt;

&lt;p&gt;Each question will have the following fields &lt;br&gt;
question_text - A questions eg. “Does Next.js support SSR or SSG?”&lt;br&gt;
correct_answer - The correct answer to the question asked in (1)  eg. “Both”&lt;br&gt;
options - Distractors to the correct answer eg. [“SSR”, “SSG”]&lt;/p&gt;
&lt;h4&gt;
  
  
  Answers Collection
&lt;/h4&gt;

&lt;p&gt;Each question response (answer) will have the following fields &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;question_id - a  reference to the question in the questions collection. &lt;/li&gt;
&lt;li&gt;user_id - A unique identifier for the respondent.(This value will be automatically generated and stored in the browser.)&lt;/li&gt;
&lt;li&gt;response - The user’s response from a list of possible options.&lt;/li&gt;
&lt;li&gt;isCorrect - A Boolean value to indicate it the answer provided is their correct (true) or incorrect (false) &lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  INDEXING YOUR DATA.
&lt;/h4&gt;

&lt;p&gt;Fauna highly recommends &lt;a href="https://docs.fauna.com/fauna/current/api/fql/indexes?lang=javascript" rel="noopener noreferrer"&gt;indexing your data for the purposes of searching, sorting and combining results from multiple collections&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this Q&amp;amp;A app, a user will be allowed to attempt and respond to a question only once. We can enforce this constraint in our answers collection by creating an index as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;qna&amp;gt; CreateIndex({
...   name: "unique_question_user",
...   unique: true,
...   serialized: true,
...   source: Collection("answers"),
...   terms: [
...     {
.....       field: ["data", "user_id"]
.....     },
...     {
.....       field: ["data", "question_id"]
.....     }
...   ]
... })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the index was created successfully, you should get a similar response.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#SAMPLE RESPONSE…...
{
  ref: Index("unique_question_user"),
  ts: 1610301037970000,
  active: true,
  serialized: true,
  name: 'unique_question_user',
  unique: true,
  source: Collection("answers"),
  terms: [
    { field: [ 'data', 'user_id' ] },
    { field: [ 'data', 'question_id' ] }
  ],
  partitions: 1
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second index we will create is to enable us get all answers by a particular user&lt;/p&gt;

&lt;h4&gt;
  
  
  READING AND SAVING DATA
&lt;/h4&gt;

&lt;p&gt;Next.js supports multiple ways or obtaining  data from the remote source eg. API or a database.&lt;br&gt;
Use of &lt;code&gt;getServersideProps&lt;/code&gt;. This props can thereafter be passed to the exported component &lt;br&gt;
Using API Routes - API routes provide a straightforward solution to build your API with Next.js.Any file inside the folder &lt;code&gt;pages/api&lt;/code&gt; is mapped to &lt;code&gt;/api/*&lt;/code&gt; and will be treated as an API endpoint instead of a page. They are server-side only bundles and won't increase your client-side bundle size.&lt;/p&gt;

&lt;p&gt;Now that we know about API Routes, let's create an HTTP endpoint to allow us to create a question with a simple POST request.&lt;/p&gt;

&lt;p&gt;In the root of our application directory, in the &lt;code&gt;pages/api&lt;/code&gt;  folder, lets create a file named &lt;code&gt;createQuestion.js&lt;/code&gt;  and add the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import faunadb, {query as q} from 'faunadb';
const client = new faunadb.Client({secret: process.env.FAUNA_SECRET })

export default async (req, res) =&amp;gt; {
   if(req.method == 'POST'){
       let {question_text, correct_answer, options } = req.body
       let results = await client.query(
           q.Create(q.Collection('questions'),
           { data : {question_text, correct_answer, options}})
       )
       console.log(results)
       res.json({ id: results.ref.id, data: results.data })
   }
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  CREATE A FAUNA KEY
&lt;/h4&gt;

&lt;p&gt;In order for our application to send and receive data to Fauna we will need to create a key and provide its secret when performing queries.&lt;br&gt;
For this application, a key with a Server Role is sufficient to create, read and delete data.&lt;br&gt;
Head over to your database’s Fauna Shell and create a key using the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CreateKey({
      name: "qna-app",
      role: "server"
   })
# Example result.
# NOTE: Make sure you copy and store the secret!
# {
#   ref: Ref(Keys(), "280185139463529993"),
#     ts: 1603464278974000,
#     role: 'server',
#     secret: 'fnAD62i0bTBCDRjYjkcttAsY3wVyfsvynwUSqxYG',
#     hashed_secret: ...
# }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This next step is critical. Copy the secret generated and set it on your project environment by running the command below. Note that secrets are only shown once after creating keys; you’ll have to create a new key if you lose the original secret.&lt;br&gt;
Create a &lt;code&gt;.env.local&lt;/code&gt; file in the application root, and here we will place this key&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .env.local 
FAUNA_SECRET=fn……………………………….
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you are done we can start our development server by running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ yarn dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  SEED INITIAL QUESTIONS
&lt;/h4&gt;

&lt;p&gt;Now that we have an API running at &lt;a href="http://127.0.0.1:3000/api/createQuestion" rel="noopener noreferrer"&gt;http://127.0.0.1:3000/api/createQuestion&lt;/a&gt; we can seed some initial questions to our database by using simple curl commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl --location --request POST 'http://127.0.0.1:3000/api/createQuestion' \
--header 'Content-Type: application/json' \
--data-raw '{
    "question_text":"How many items in a dozen?",
    "correct_answer": "12",
    "options": ["6", "10"]
}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl --location --request POST 'http://127.0.0.1:3000/api/createQuestion' \
--header 'Content-Type: application/json' \
--data-raw '{
    "question_text":"How many bits in a byte?",
    "correct_answer": "8",
    "options": ["6", "10", "12", "16" ]
}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s also create an API endpoint that can be used to evaluate question response.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;pages/api&lt;/code&gt;  folder, let's create a file named &lt;code&gt;evaluateResponse.js&lt;/code&gt;  and add the following code.&lt;br&gt;
This API endpoint will be available at &lt;a href="http://127.0.0.1:3000/api/evaluateResponse" rel="noopener noreferrer"&gt;http://127.0.0.1:3000/api/evaluateResponse&lt;/a&gt; and shall be invoked whenever a users response needs to be evaluated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import faunadb, {query as q} from 'faunadb';
const client = new faunadb.Client({secret: process.env.FAUNA_SECRET })

export default async (req, res) =&amp;gt; {
   if(req.method == 'POST'){
       let {question_id, user_id, answer } = req.body
       if (!(question_id &amp;amp;&amp;amp; answer &amp;amp;&amp;amp; user_id)){
           res.json({ error: "Fields question_id &amp;amp; answer &amp;amp; user_id should be provided." })
       }
       else {
           let results = await client.query(
               q.Get( q.Ref(q.Collection('questions'), question_id)))
           let question = results.data
           let isCorrect = false
           if ( question.correct_answer === answer ){ isCorrect = true }
           try{
               let query = await client.query(
                   q.Create(q.Collection('answers'),
                       { data : { question_id, user_id, isCorrect: isCorrect, response: answer }})
               )
               query.data.correct = question.correct_answer
               res.json({ ref: query.ref.id, data: query.data }) 
           }catch(error){
               if(error.message === 'instance not unique'){
                   res.json({error: 'Question is already answered'})
               }
           }                   
   }
 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now start working on the UI.&lt;/p&gt;

&lt;p&gt;To create a UI quickly, we will use the react-bootstrap library and use some ready made UI components.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ yarn add react-bootstrap bootstrap
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, add the change the default style in the pages/_app.js file to bootstrap as shown.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// pages/_app.js

import 'bootstrap/dist/css/bootstrap.min.css'

function MyApp({ Component, pageProps }) {
 return &amp;lt;Component {...pageProps} /&amp;gt;
}

export default MyApp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  USERS
&lt;/h4&gt;

&lt;p&gt;As noted above, we will be required to uniquely identify users sowe will generate random user ids that will be saved in the cookies.&lt;br&gt;
We will use nookies to easily create and read cookie data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add nookies
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  getServerSideProps
&lt;/h4&gt;

&lt;p&gt;Our cookies will be generated and set in the &lt;code&gt;serverSideProps&lt;/code&gt; of our &lt;code&gt;index.js&lt;/code&gt;.&lt;br&gt;
If the cookies are available, they will be used to save user responses and also identify already attempted questions to prevent them from being loaded to the user again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// pages/index.js
let cookies = parseCookies(context)
 if(!cookies.user_id){
   setCookie(context, 'user_id', `${rw()}${Math.floor((Math.random() * 999) + 900)}`, {
     maxAge: 7 * 24 * 60 * 60, path: '/', })
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the same function, we will also retrieve a not attempted question from our questions collection in Fauna using the &lt;a href="https://docs.fauna.com/fauna/current/api/fql/functions/difference" rel="noopener noreferrer"&gt;FQL Difference&lt;/a&gt; function&lt;br&gt;
This will enable us to compare the entire collections of questions  that are missing from a list of questions that have already been attempted by the user.&lt;br&gt;
This will enable us to select the next question for the user.&lt;/p&gt;

&lt;p&gt;We will use the following  FQL query.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// pages/index.js
let query = await db.query(
   q.Difference(
     //Get All questions
     q.Select('data', q.Map(
       q.Paginate(q.Documents(q.Collection('questions'))), q.Lambda('ref', q.Var('ref')))),
     //Get  Attempted Questions
     q.Select('data', q.Map(
       q.Paginate( q.Match(q.Index('questions_attempted_by_user'), cookies.user_id)),
       q.Lambda('question_id', q.Ref(q.Collection('questions'), q.Var('question_id')))
     ))
   )
 )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, update the pages/index.js file to be as below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Head from 'next/head'
import React, { useState, useEffect } from 'react'

import { parseCookies, setCookie, destroyCookie } from 'nookies'

import faunadb, {query as q} from 'faunadb';
const db = new faunadb.Client({secret: process.env.FAUNA_SECRET })
import rw from 'random-words'

//Bootstrap Components
import Card from 'react-bootstrap/Card'
//Import Custom Components
import Question from '../components/Question'

export default function Home( { question, auth } ) {

 let [questionId, setQuestionId] = useState(null)
 let [userId, setUserId] = useState(null)
 let cookies = parseCookies()

 return (
   &amp;lt;div className="container"&amp;gt;
     &amp;lt;h5 style={{paddingTop:"3em"}}&amp;gt;🤔 Questions need answers&amp;lt;/h5&amp;gt;
     &amp;lt;hr/&amp;gt;
     &amp;lt;Card&amp;gt;
       &amp;lt;Card.Header&amp;gt;
         &amp;lt;h5 style={{float:'right'}}&amp;gt;Hello {cookies.user_id}&amp;lt;/h5&amp;gt;
       &amp;lt;/Card.Header&amp;gt;

           &amp;lt;Question question={ question } /&amp;gt;

       &amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;
     &amp;lt;/Card&amp;gt;
     &amp;lt;Card.Footer&amp;gt;
     &amp;lt;/Card.Footer&amp;gt;
   &amp;lt;/div&amp;gt;
 )
}

export async function getServerSideProps(context) {
 //Check for cookies and setCookie if none
 let cookies = parseCookies(context)
 if(!cookies.user_id){
   setCookie(context, 'user_id', `${rw()}${Math.floor((Math.random() * 999) + 900)}`, {
     maxAge: 7 * 24 * 60 * 60, path: '/', })
 }

 // Fetch questions
 let query = await db.query(
   q.Difference(
     //All questions
     q.Select('data', q.Map(
       q.Paginate(q.Documents(q.Collection('questions'))), q.Lambda('ref', q.Var('ref')))),
     // Attempted Questions
     q.Select('data', q.Map(
       q.Paginate( q.Match(q.Index('questions_attempted_by_user'), cookies.user_id)),
       q.Lambda('question_id', q.Ref(q.Collection('questions'), q.Var('question_id')))
     ))
   )
 )

 let question = null
 if(query.length &amp;gt; 0){
   let result = await db.query(q.Get(query[0]))
   question = result.data
   question.id = result.ref.id
 }

 return {
   props: {
     question,
   }, // will be passed to the page component as props
 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create a components folder and in the &lt;code&gt;./components/Question.jsx&lt;/code&gt; add the following code for our question’s component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, {useState} from 'react'
import Card from 'react-bootstrap/Card'
import Form from 'react-bootstrap/Form'
import Button from 'react-bootstrap/Button'
import { parseCookies } from 'nookies'
import {useRouter} from 'next/router'
import Alert from 'react-bootstrap/Alert'

export default function Question({ question }){

   let [answer, setAnswer ] = useState(null)
   let [evaluated, setEvaluated] = useState(null)

   let router = useRouter()
   let cookies = parseCookies()
   let user_id = cookies.user_id

   let submitResponse = async () =&amp;gt; {
       let request = await fetch('/api/evaluateResponse', {
           headers:{ 'Content-Type': 'application/json'},
           body: JSON.stringify({ question_id: question.id, user_id: user_id, answer: answer}),
           method: "POST",
       })
       let response = await request.json()
       setEvaluated(response.data)
       setTimeout(function(){
           setEvaluated(null)
           router.push('/')}, 2500)
   }

   return(
       &amp;lt;&amp;gt;
       {evaluated ? &amp;lt;Alert variant="info"&amp;gt;You answer was {evaluated.isCorrect ?
           "correct": `wrong. Correct answer is ${evaluated.correct}`}&amp;lt;/Alert&amp;gt; : &amp;lt;&amp;gt;&amp;lt;/&amp;gt;}
       {question ? &amp;lt;Card.Body&amp;gt;
           &amp;lt;h4&amp;gt;{question.question_text}&amp;lt;/h4&amp;gt;
           &amp;lt;hr/&amp;gt;
           {(question.options.concat(question.correct_answer)).map((answer, idx)=&amp;gt;{
               return ( &amp;lt;h4 key={idx}&amp;gt;
                           &amp;lt;Form.Check type="radio"
                               onChange={e =&amp;gt; {setAnswer(e.target.value)}}  value={answer} name="options" label={answer} /&amp;gt;
                        &amp;lt;/h4&amp;gt; )
           })}
           &amp;lt;div className="container"&amp;gt;
               {   answer ?
                   &amp;lt;Button className="col-sm-12 col-lg-12 col-md-12" variant="warning" onClick={submitResponse}&amp;gt;Answer&amp;lt;/Button&amp;gt; :
                   &amp;lt;Button className="col-sm-12 col-lg-12 col-md-12" variant="warning" disabled&amp;gt;Answer&amp;lt;/Button&amp;gt;
               }
           &amp;lt;/div&amp;gt;
       &amp;lt;/Card.Body&amp;gt; : &amp;lt;h4&amp;gt;You have answered all available questions.&amp;lt;/h4&amp;gt;
       }
       &amp;lt;/&amp;gt;
   )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we run the dev server&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you visit &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; you will be greeted with the questions page as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpttm8dzwfcf5i31yhb3m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpttm8dzwfcf5i31yhb3m.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy to Vercel
&lt;/h3&gt;

&lt;p&gt;To deploy our app to &lt;a href="https://vercel.com" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt;, we first need to install the &lt;a href="https://vercel.com/docs/cli" rel="noopener noreferrer"&gt;Vercel CLI&lt;/a&gt; by running the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i -g vercel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensure you have a Vercel account, or head over to &lt;a href="https://vercel.com" rel="noopener noreferrer"&gt;vercel.com&lt;/a&gt; to create one.&lt;br&gt;
Once registered, run the following command to login to the CLI with your account.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vercel login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the prompts to confirm your email.&lt;br&gt;
Once you successfully login, run the following command to setup and deploy the app to Vercel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vercel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ vercel
Vercel CLI 20.1.1
? Set up and deploy “~/x/qna”? [Y/n] y
? Which scope do you want to deploy to? Bryan
? Link to existing project? [y/N] n
? What’s your project’s name? qna
? In which directory is your code located? ./
Auto-detected Project Settings (Next.js):
- Build Command: `npm run build` or `next build`
- Output Directory: Next.js default
- Development Command: next dev --port $PORT
? Want to override the settings? [y/N] n

🔍  Inspect: https://vercel.com/amolo/qna/ikxz9cpa2 [5s]
✅  Preview: https://qna.amolo.vercel.app [copied to clipboard] [48s]
📝  To deploy to production, run `vercel --prod`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we will need to add the FAUNA_SECRET environment variable to allow our app interact with Fauna.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vercel env add
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the prompts as shown below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ vercel env add
Vercel CLI 20.1.1
? What’s the name of the variable? FAUNA_SECRET
? What’s the value of FAUNA_SECRET? [hidden]
? Add FAUNA_SECRET to which Environments (select multiple)? Production, Preview,
 Development
✅  Added Environment Variable FAUNA_SECRET to Project qna [2s]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally we can deploy our app with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vercel  --prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ vercel --prod
Vercel CLI 20.1.1
🔍  Inspect: https://vercel.com/amolo/qna/co2hv7ces [2s]
✅  Production: https://qna-seven.vercel.app [copied to clipboard] [35s]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your app is now live.&lt;br&gt;
You can visit the demo on &lt;a href="https://qna-seven.vercel.app" rel="noopener noreferrer"&gt;https://qna-seven.vercel.app&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Conclusion
&lt;/h4&gt;

&lt;p&gt;For this tutorial, we are able to see how fast it can be to develop a full stack application with Fauna and Next.js.&lt;br&gt;
Next.js provides a highly productive, powerful and fast framework that we can use to develop both backend and frontend components of our full stack app. &lt;br&gt;
Secondly, we can see how Fauna is indeed a powerful database; with a powerful FQL, which supports complex querying and integration with the serverless and JAMStack ecosystem through its API first approach. This enables developers to simplify code and ship faster.&lt;/p&gt;

&lt;p&gt;I hope you find Fauna to be exciting, like I do, and that you enjoyed this article. Feel free to follow me on Twitter &lt;a href="https://twitter.com/theAmolo" rel="noopener noreferrer"&gt;@theAmolo&lt;/a&gt; if you enjoyed this!&lt;/p&gt;

&lt;p&gt;All code written for this tutorial can be found in the following &lt;a href="https://github.com/brianraila/qna" rel="noopener noreferrer"&gt;Github Repo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>fauna</category>
      <category>nextjs</category>
      <category>react</category>
    </item>
    <item>
      <title>How to create a job board with Fauna and Redwood.js</title>
      <dc:creator>Amolo</dc:creator>
      <pubDate>Thu, 03 Dec 2020 14:57:41 +0000</pubDate>
      <link>https://forem.com/amolo/develop-a-job-board-with-fauna-and-redwood-js-1cl3</link>
      <guid>https://forem.com/amolo/develop-a-job-board-with-fauna-and-redwood-js-1cl3</guid>
      <description>&lt;h4&gt;
  
  
  INTRODUCTION
&lt;/h4&gt;

&lt;h4&gt;
  
  
  Redwood.js &amp;amp; Full Stack
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://redwoodjs.com" rel="noopener noreferrer"&gt;Redwood&lt;/a&gt; is an opinionated, full-stack, serverless web application framework that enables developers to build and deploy Jamstack applications with ease.&lt;br&gt;
One of the main Redwood’s philosophies is power in standards, so it makes decisions about which technologies to use, organizing your code into files, and naming conventions.&lt;/p&gt;
&lt;h4&gt;
  
  
  Fauna
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=WritewithFauna_MircroServicesPythonFlaskFauna_BAmolo" rel="noopener noreferrer"&gt;Fauna&lt;/a&gt; is a powerful and fully featured serverless database. With a web-native GraphQL interface that supports custom business logic, consistent data and total freedom from database operations since its fully managed. &lt;/p&gt;

&lt;p&gt;By using &lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=WritewithFauna_MircroServicesPythonFlaskFauna_BAmolo" rel="noopener noreferrer"&gt;Fauna&lt;/a&gt; in this application’s architecture, we are able to simplify code, reduce costs and ship faster.&lt;/p&gt;
&lt;h4&gt;
  
  
  The Application.
&lt;/h4&gt;

&lt;p&gt;In this tutorial, we will be developing a simple job board. &lt;/p&gt;
&lt;h4&gt;
  
  
  Getting started.
&lt;/h4&gt;

&lt;p&gt;We'll use yarn (&lt;a href="https://yarnpkg.com/en/docs/install" rel="noopener noreferrer"&gt;yarn&lt;/a&gt; is a requirement) to create the basic structure of our app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn create redwood-app ./job-board
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll have a new directory “job-board” containing several directories and files. Change to that directory.&lt;/p&gt;

&lt;h4&gt;
  
  
  Redwood File Structure
&lt;/h4&gt;

&lt;p&gt;Let's take a look at the files and directories that were created for us (config files have been excluded for now):&lt;/p&gt;

&lt;p&gt;In the web folder.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzdss0v4tg4xbyk6waigd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzdss0v4tg4xbyk6waigd.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the api folder.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fds8wt9kpatx3hdb3cvxt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fds8wt9kpatx3hdb3cvxt.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the above structure, it's clear how Redwood makes decisions for you about which technologies to use, how to organize your code into files, and how to name things.&lt;br&gt;
It can be a little overwhelming to look at everything that’s already been generated for us. The first thing to pay attention to is that Redwood apps are separated into two directories:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;web directory for the application frontend.&lt;/li&gt;
&lt;li&gt;api for the backend&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;
  
  
  Setting Up Fauna.
&lt;/h4&gt;

&lt;p&gt;Create Fauna Account&lt;br&gt;
To hold all our application’s data, we will first need to create a database. Fortunately, this is just a single command or line of code, as shown below. Don’t forget to create a Fauna account before continuing!&lt;/p&gt;

&lt;p&gt;NOTE:&lt;br&gt;
&lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=WritewithFauna_MircroServicesPythonFlaskFauna_BAmolo" rel="noopener noreferrer"&gt;Fauna&lt;/a&gt; offers a generous free tier for you not only to test your app but you can also use this to build your small hobby apps. &lt;/p&gt;
&lt;h4&gt;
  
  
  Fauna Shell
&lt;/h4&gt;

&lt;p&gt;Fauna’s API has many interfaces/clients, such as drivers in JS, GO, Java and more, a cloud console, local and cloud shells, and even a VS Code extension! For this article, we’ll start with the local Fauna Shell, which is almost 100% interchangeable with the other interfaces.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g fauna-shell
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installing the Fauna Shell with npm, log in with your Fauna credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ fauna cloud-login

Email: email@example.com
Password: **********
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Creating the Database
&lt;/h4&gt;

&lt;p&gt;Now we are able to create our database.&lt;br&gt;
To create your database enter the fauna create-database command and give your database name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fauna create-database job-board
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To start the fauna shell with our new database we’ll enter the fauna shell command followed by the name of the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fauna shell job-board
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  GraphQL on Fauna.
&lt;/h4&gt;

&lt;p&gt;One of the many great features of &lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=WritewithFauna_MircroServicesPythonFlaskFauna_BAmolo" rel="noopener noreferrer"&gt;Fauna&lt;/a&gt; is its first class support for GraphQL.&lt;br&gt;
One big advantage of using GraphQL on Fauna is that it allows you to define a schema and it will do its magic in the background to ensure your entities, collections and their relationships are created. All you need to provide is a schema.&lt;/p&gt;
&lt;h4&gt;
  
  
  Writing Schema.
&lt;/h4&gt;

&lt;p&gt;We will use the below schema for our application.&lt;br&gt;
Create a file in the your directory and name it &lt;code&gt;job-board-schema.gql&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Listing {
 title: String!,
 description: String!,
 location: String!
 company: String!
}

type Query{
 listings: [Listing]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Importing Schema.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftvq8a1jcb2jtba41ps7w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftvq8a1jcb2jtba41ps7w.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On your database page on Fauna, go to the GraphQL tab on the left side bar. You will see a page similar to the one above.&lt;/p&gt;

&lt;p&gt;Click on “Import Schema” then select the sample schema from your application directory.&lt;/p&gt;

&lt;p&gt;This will automatically create the required collection, FQL queries to fetch and create data together with indexes that will be required for query and mutation capabilities.&lt;/p&gt;

&lt;h4&gt;
  
  
  Testing the schema (Graphiql) and Writing Queries.
&lt;/h4&gt;

&lt;p&gt;Now that we have successfully imported our GraphQL schema definition, we can now test if our GraphQL API is working by running the following mutations to seed initial data to our database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mutation {
  createListing(data:{
    title: "Python Developer",
    description: "Experience Python developer with experience in Flask and FaunaDB",
    location: "Kisumu",
    company: "Dala Systems"
  }),
  {
    _id
    title
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mutation {
  createListing(data:{
    title: "Node.js Developer",
    description: "Outstanding Node.js with 3+ Years experience in developing serverless apps",
    location: "Cape Town",
    company: "Sugar Systems"
  }),
  {
    _id
    title
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the above mutations execute successfully, they should return the &lt;code&gt;_id&lt;/code&gt; and &lt;code&gt;title&lt;/code&gt; of the newly created job listing.&lt;/p&gt;

&lt;p&gt;Moreover, you can further confirm this by running the following query should list all the available jobs posted to the collection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query {
  listings {
    data{
      title
      description
      company
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4. Setting up Redwood to work with Fauna.
&lt;/h4&gt;

&lt;p&gt;When generating the project using yarn, the default database is an instance of the PrismaClient. Since Prisma doesn’t support Fauna currently, we will make use of graphql-request to query the GraphQL API we created above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add graphql-request graphql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;api/src/lib/db.js&lt;/code&gt; add the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { GraphQLClient } from 'graphql-request'

export const request = async (query = {}) =&amp;gt; {
  const endpoint = 'https://graphql.fauna.com/graphql'

  const graphQLClient = new GraphQLClient(endpoint, {
    headers: {
      authorization: 'Bearer &amp;lt;FAUNADB_KEY&amp;gt;'
    },
  })
  try {
    return await graphQLClient.request(query)
  } catch (error) {
    console.log(error)
    return error
  }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To access our Fauna database through the GraphQL endpoint we’ll need to set a request header containing our database key as provided by Fauna.&lt;/p&gt;

&lt;h4&gt;
  
  
  Obtaining your Fauna database key.
&lt;/h4&gt;

&lt;p&gt;Head over to your database’s Fauna Shell and create a key using the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CreateKey({
      name: "redwood-app",
      role: "server"
   })

# Example result.
# NOTE: Make sure you copy and store the secret!
# {
#   ref: Ref(Keys(), "280185139463529993"),
#     ts: 1603464278974000,
#     role: 'server',
#     secret: 'fn…………………………………………………..',
#     hashed_secret: ...
# }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this you will also be required to create a &lt;code&gt;api/src/graphql/listings.sdl.js&lt;/code&gt; file and add the following contents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import gql from 'graphql-tag'

export const schema = gql`

type Listing {
  title: String!,
  description: String!,
  location: String!,
  company: String!
}

type ListingsPage {
  data: [Listing]
}

type Query{
  listings: ListingsPage
  jobs: [Listing]
}
`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Redwood.js Services
&lt;/h4&gt;

&lt;p&gt;In our api/src/services directory we'll create a listings directory with a file called listings.js. Services are where Redwood centralizes all business logic. These can be used by your GraphQL API or any other place in your backend code. The listings function is querying the Fauna GraphQL endpoint and returning our posts data so it can be consumed by our ListingsCell.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// api/src/services/listings/listings.js

import { request } from 'src/lib/db'
import { gql } from 'graphql-request'

export const listings = async () =&amp;gt; {
 const query = gql`
 {
   listings{
     data {
       title
       description
       location
       company
     }
 }
 }
 `

 const data = await request(query, 'https://graphql.fauna.com/graphql')
 return data['listings']
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  5. Writing the application.
&lt;/h4&gt;

&lt;p&gt;Now that our application is already set up, we can start creating pages. We’ll use the generate page command to create a home page and a folder to hold that page. The commands for generating a page is ‘generate’ although we can use g to save some typing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn rw g page home /
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On this page we will list all available job listings posted in our Fauna collection.&lt;/p&gt;

&lt;h4&gt;
  
  
  Redwood.js Cells.
&lt;/h4&gt;

&lt;p&gt;In Redwood.js, cells provide a simpler and more declarative approach to data fetching. They contain the GraphQL query, loading, empty, error, and success states, each one rendering itself automatically depending on what state your cell is in.&lt;br&gt;
Create a folder in web/src/components called &lt;code&gt;ListingsCell&lt;/code&gt; and inside that folder create a file called &lt;code&gt;ListingsCell.js&lt;/code&gt;.&lt;br&gt;
Inside that file add the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// web/src/components/ListingsCell/ListingsCell.js

export const QUERY = gql`
 query LISTINGS {
   listings {
     data {
       title
       description
       location
       company
     }
   }
 }
`

export const Loading = () =&amp;gt; &amp;lt;div&amp;gt;Loading Job Listings...&amp;lt;/div&amp;gt;
export const Empty = () =&amp;gt; &amp;lt;div&amp;gt;No Job Listings yet!&amp;lt;/div&amp;gt;
export const Failure = ({ error }) =&amp;gt; &amp;lt;div&amp;gt;Error: {error.message}&amp;lt;/div&amp;gt;

export const Success = ({ listings }) =&amp;gt; {
 const {data} = listings
 return (
   &amp;lt;div style={{maxWidth:"50%", margin:"auto"}}&amp;gt;
     {data.map(listing =&amp;gt; (
       &amp;lt;&amp;gt;
       &amp;lt;div style={{border: "black 1pt solid", padding: ".7em"}}&amp;gt;
       &amp;lt;h4&amp;gt;{listing.title}&amp;lt;/h4&amp;gt;
       &amp;lt;p&amp;gt;{listing.description}&amp;lt;/p&amp;gt;
       &amp;lt;p&amp;gt;Organization: {listing.company} &amp;lt;br/&amp;gt;
       Location: {listing.location}&amp;lt;/p&amp;gt;
       &amp;lt;/div&amp;gt;
       &amp;lt;/&amp;gt;
     ))}
   &amp;lt;/div&amp;gt;
 )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now in our web/src/pages folder we will see a HomePage folder with a file named HomePage.js.&lt;/p&gt;

&lt;p&gt;In this file add the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import ListingsCell from 'src/components/ListingsCell'

const HomePage = () =&amp;gt; {
 return (
   &amp;lt;&amp;gt;
     &amp;lt;h1&amp;gt;Fauna Redwood.js Job Board&amp;lt;/h1&amp;gt;
     &amp;lt;ListingsCell /&amp;gt;
   &amp;lt;/&amp;gt;
 )
}

export default HomePage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  6. Testing App.
&lt;/h4&gt;

&lt;p&gt;To preview if our app is working, we will need to run the following command in your terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn rw dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then visit &lt;a href="http://localhost:8910/" rel="noopener noreferrer"&gt;http://localhost:8910/&lt;/a&gt; you should be greeted with a preview as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj4c9lkilgdh6z3t54jic.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj4c9lkilgdh6z3t54jic.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  7. Deploying to Netlify.
&lt;/h4&gt;

&lt;p&gt;Redwood was created to make full-stack web apps easier to build and deploy on the Jamstack. Now that we have seen what building a Redwood app is like, how about we try deploying one?&lt;br&gt;
To make the app  ready for deployment, we can take advantage of the Redwood generator. To do this, run the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn rw g deploy netlify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a file at /netlify.toml which contains the commands and file paths that Netlify needs to know about to build a Redwood application.&lt;/p&gt;

&lt;p&gt;Next, we need to ensure our application is committed and pushed to Github.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git init
git add .
git commit -m 'First commit'
git remote add origin ...
git push -u origin master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this, we are going to link Netlify directly to our git repo so that a simple push to main will re-deploy our entire application.&lt;/p&gt;

&lt;p&gt;In your Netlify account select the option “New Site from Git” and follow the prompts to link your repo and it should deploy automatically.&lt;/p&gt;

&lt;p&gt;At this point, you will discover that the posts aren’t loading. The reason for this is the lack of a Fauna key in your Netlify environment. To resolve this, go to your application page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fc789jfvuqvw6m1xwn21m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fc789jfvuqvw6m1xwn21m.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the Build &amp;amp; deploy tab, scroll to the Environment section and add your Fauna database key with the key FAUNA_KEY and save. &lt;/p&gt;

&lt;p&gt;Now your application is live and working. When you visit the application URL you should see a similar page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyeletwwuuseyawpjf16l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyeletwwuuseyawpjf16l.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Upon loading, you will see the job listings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiyiqgy8ty00rqhslstyc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiyiqgy8ty00rqhslstyc.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Conclusion
&lt;/h4&gt;

&lt;p&gt;From this tutorial, we can see how simple it can be to develop a full stack application with Redwood and Fauna which is indeed a powerful database; with a web-native GraphQL interface, which supports custom business logic and integration with the serverless ecosystem. This enables developers to simplify code and ship faster.&lt;/p&gt;

&lt;p&gt;Combined together with &lt;a href="https://www.netlify.com" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt;, we can have a truly serverless and fully managed full stack application. The advantages we get from this architecture is a great boost to productivity as we can focus on implementing features that make our application and UX unique, instead of getting hung up on the DevOps of servers and databases.&lt;/p&gt;

&lt;p&gt;I hope you find Fauna to be exciting, like I do, and that you enjoyed this article. Feel free to follow me on Twitter &lt;a href="https://twitter.com/theAmolo" rel="noopener noreferrer"&gt;@theAmolo&lt;/a&gt; if you enjoyed this!&lt;/p&gt;

&lt;p&gt;BONUS: &lt;br&gt;
All code written for this tutorial can be found in the following &lt;a href="https://github.com/brianraila/rw-fauna" rel="noopener noreferrer"&gt;Github Repo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>redwoodjs</category>
      <category>fauna</category>
      <category>graphql</category>
    </item>
    <item>
      <title>How to Build Microservices with Fauna, Python/Flask and Deploy to Vercel.</title>
      <dc:creator>Amolo</dc:creator>
      <pubDate>Wed, 28 Oct 2020 19:56:55 +0000</pubDate>
      <link>https://forem.com/amolo/how-to-build-microservices-with-fauna-python-flask-and-deploy-to-vercel-4k19</link>
      <guid>https://forem.com/amolo/how-to-build-microservices-with-fauna-python-flask-and-deploy-to-vercel-4k19</guid>
      <description>&lt;h4&gt;
  
  
  INTRODUCTION.
&lt;/h4&gt;

&lt;p&gt;Microservices, this term is mostly used as a reference to the microservices architecture which is an architectural style that structures an application as a collection of loosely-coupled services.&lt;br&gt;
Each of these services is responsible for a discrete task and can communicate with other services through simple APIs to solve a larger complex business problem.&lt;/p&gt;

&lt;p&gt;One big advantage of using this approach is that the constituent services can be developed, deployed and maintained independent of each other. Therefore you are able to easily and gradually grow your application. &lt;/p&gt;
&lt;h4&gt;
  
  
  FAUNA.
&lt;/h4&gt;

&lt;p&gt;For microservices, &lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=WritewithFauna_MircroServicesPythonFlaskFauna_BAmolo" rel="noopener noreferrer"&gt;Fauna&lt;/a&gt; has a number of great features that are well suited for this architecture e.g. multi-tenancy which enables developers to create child databases inside the main database that are isolated from each other. This way you can keep data for each service or microservice separately and securely from the others.   &lt;/p&gt;

&lt;p&gt;In addition to the features above, Fauna also provides us with a powerful and fully-managed database. This way we don’t need to worry about database correctness, sharding, provisioning, latency, or scaling our database. This is why it’s many times referred to as the truly serverless database.&lt;/p&gt;

&lt;p&gt;By including &lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=WritewithFauna_MircroServicesPythonFlaskFauna_BAmolo" rel="noopener noreferrer"&gt;Fauna&lt;/a&gt; and &lt;a href="https://vercel.com" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt; in our application stack, we are able to have a fully managed serverless stack. We can make changes to the application and simply do a git push. Vercel will take care of computing resource provisioning while Fauna will provide us with a fully managed database.&lt;/p&gt;

&lt;p&gt;This is a tremendous boost to developer productivity as we are able to focus only on what makes our app unique without wasting a lot of time doing the provisioning and maintenance tasks ourselves. &lt;/p&gt;
&lt;h4&gt;
  
  
  THE APPLICATION.
&lt;/h4&gt;

&lt;p&gt;In this tutorial, we will be creating two microservices for a classic e-commerce backend to enable the following in our application. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Product Catalog Management.&lt;/li&gt;
&lt;li&gt;Product Reviews Management.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These microservices will allow us to create a new product entry, edit / update an existing product’s details, delete a product entry, create a product review, edit/update an existing product review, and delete a product review.&lt;/p&gt;

&lt;p&gt;We will take advantage of the Flask Web Framework which is a very powerful Python micro framework to expose our microservices as a web API. Compared to other frameworks such as Django,  Flask is lightweight and allows you a lot of flexibility while developing web applications.&lt;/p&gt;
&lt;h4&gt;
  
  
  CREATING YOUR DATABASE ON FAUNA.
&lt;/h4&gt;

&lt;p&gt;To hold all our application’s data, we will first need to create a database. Fortunately, this is just a single command or line of code, as shown below. Don’t forget to create a &lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=WritewithFauna_MircroServicesPythonFlaskFauna_BAmolo" rel="noopener noreferrer"&gt;Fauna&lt;/a&gt; account before continuing!&lt;/p&gt;
&lt;h4&gt;
  
  
  Fauna Shell
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=WritewithFauna_MircroServicesPythonFlaskFauna_BAmolo" rel="noopener noreferrer"&gt;Fauna's&lt;/a&gt; API has many interfaces/clients, such as drivers in JS, GO, Java and more, a cloud console, local and cloud shells, and even a VS Code extension! For this article, we’ll start with the local &lt;a href="https://docs.fauna.com/fauna/current/integrations/shell/index.html" rel="noopener noreferrer"&gt;Fauna Shell&lt;/a&gt;, which is almost 100% interchangeable with the other interfaces.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g fauna-shell
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installing the &lt;a href="https://docs.fauna.com/fauna/current/integrations/shell/index.html" rel="noopener noreferrer"&gt;Fauna Shell&lt;/a&gt; with npm, log in with your Fauna credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ fauna cloud-login

Email: email@example.com
Password: **********
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are able to create our database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fauna create-database e-commerce
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  CREATE COLLECTIONS.
&lt;/h4&gt;

&lt;p&gt;Now that we have our database created, it's time to create our collections.&lt;/p&gt;

&lt;p&gt;In Fauna, a database is made up of one or more collections. The data you create is represented as documents and saved in a collection. A collection is like an SQL table.&lt;br&gt;
Or rather, a collection, is a collection of documents.&lt;br&gt;
A fair comparison with a traditional SQL database would be as below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzplsu8mjh3o3zcd4bpt1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzplsu8mjh3o3zcd4bpt1.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For our two microservices, we will create two collections in our database. Namely.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;products collection.&lt;/li&gt;
&lt;li&gt;reviews collection.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To start an interactive shell for querying our new database, we need to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fauna shell e-commerce
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now operate our database from this shell.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ fauna shell e-commerce
Starting shell for database my_app
Connected to https://db.fauna.com
Type Ctrl+D or .exit to exit the shell
e-commerce&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To create our products collection, run the following command in the shell to create the collection with the default configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;e-commerce&amp;gt; CreateCollection({ name: "products" })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, let’s do the same for the reviews collections.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;e-commerce&amp;gt; CreateCollection({ name: "reviews" })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  INDEXING YOUR DATA.
&lt;/h4&gt;

&lt;p&gt;Fauna highly recommends indexing your data for the purposes of searching, sorting and combining results from multiple collections (typically called “joins”).&lt;br&gt;
In the context of our application, “search” indexes will allow us to get all reviews for a particular product or all products under a specific category. Search results are based on an index’s “terms” attribute, where we specify the array path to a document’s field, which must match a search argument to be included in a set of results.&lt;/p&gt;

&lt;p&gt;We will create the following indexes.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;products_by_category - To allow us to retrieve products by their category&lt;/li&gt;
&lt;li&gt;reviews_by_product - To allow us to retrieve a review based on its product.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To create the products_by_category index, run the following command in a fauna shell for our database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CreateIndex({
  name: "products_by_category",
  source: Collection("products"),
  terms: [
    {
      field: ["data", "categories"]
    }
  ]
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, do the same for the reviews_by_product index.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CreateIndex({
  name: "reviews_by_product",
  source: Collection("reviews"),
  terms: [
    {
      field: ["data", "product"]
    }
  ]
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While using Fauna, it is generally ideal to write your read queries to go through your indexes, especially for performance purposes.&lt;/p&gt;

&lt;h4&gt;
  
  
  PROJECT SETUP
&lt;/h4&gt;

&lt;p&gt;To quickly bootstrap our application and its structure we will take advantage of this &lt;a href="https://github.com/brianraila/faunadb-hipflask" rel="noopener noreferrer"&gt;Flask Template for Fauna&lt;/a&gt;.&lt;br&gt;
Clone the Github repository containing the template using the snippet below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/brianraila/faunadb-hipflask.git ecommerce-tutorial
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once this is done, &lt;code&gt;cd&lt;/code&gt; into the directory and install all required dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd e-commerce-tutorial
pip3 install -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will install &lt;strong&gt;flask&lt;/strong&gt; and &lt;strong&gt;faunadb-python&lt;/strong&gt;, along with any other required dependencies.&lt;/p&gt;

&lt;h4&gt;
  
  
  CREATE A FAUNA KEY
&lt;/h4&gt;

&lt;p&gt;In order for our application to send and receive data to Fauna we will need to create a key and provide its secret when performing queries.&lt;/p&gt;

&lt;p&gt;For this application, a key with a Server Role is sufficient to create, read and delete data.&lt;br&gt;
Head over to your database’s Fauna Shell and create a key using the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CreateKey({
      name: "flask-app",
      role: "server"
   })

# Example result.
# NOTE: Make sure you copy and store the secret!
# {
#   ref: Ref(Keys(), "280185139463529993"),
#     ts: 1603464278974000,
#     role: 'server',
#     secret: 'fnAD62i0bTBCDRjYjkcttAsY3wVyfsvynwUSqxYG',
#     hashed_secret: ...
# }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This next step is critical. Copy the secret generated and set it on your project environment by running the command below. Note that secrets are only shown once after creating keys; you’ll have to create a new key if you lose the original secret.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export FAUNA_SECRET=the-fauna-secret-you-copied
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  PROJECT OVERVIEW
&lt;/h4&gt;

&lt;p&gt;The cloned repository has the directory structure shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxtvj4jluo4ii5ucgu7b1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxtvj4jluo4ii5ucgu7b1.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The only bit we are going to focus on is the app folder. This folder contains the following files and folders.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fx2joge458jytgmzzvzfb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fx2joge458jytgmzzvzfb.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  WRITING THE MICROSERVICES.
&lt;/h4&gt;

&lt;p&gt;Using Fauna’s native API, The Fauna Query Language (FQL), we can satisfy all of our CRUD needs when resolving the various REST paths of our microservices.&lt;br&gt;
Given FQL’s functional programming design, queries ranging from the simplest CRUD to complex transactions involving precise data manipulation and retrieval, are easily achievable. Note that FQL and query executions are transactional, meaning no changes are committed if an error occurs or conditions aren’t met; this behavior is particular useful for critical business logic, eg. avoiding over-ordering of limited inventory.&lt;/p&gt;

&lt;p&gt;This template takes advantage of Flask blueprints which allow us to make our applications as modular as possible. This will help us in separating our microservices and their views into individual and independent components of the entire application. &lt;/p&gt;

&lt;p&gt;For our two services, we will create two files in the app/services folder.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;app/services/products.py  - for the Product Catalog Microservice.&lt;/li&gt;
&lt;li&gt;app/services/reviews.py - for Product Reviews Microservice.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Eventually, we will have the following endpoints.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fthhbd3ck0zg6jrsx1yzd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fthhbd3ck0zg6jrsx1yzd.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Products Microservice.
&lt;/h4&gt;

&lt;p&gt;As described above, this microservice will be responsible for creating , reading , updating and deleting products for our application.&lt;/p&gt;

&lt;p&gt;Add the following code to the products microservices file.&lt;br&gt;
[./app/services/products.py]&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from flask import (
   Blueprint, render_template, jsonify, request
   )
from app.db import client

# Fauna Imports
from faunadb import query as q
from faunadb import errors
from faunadb.objects import Ref

bp = Blueprint('products', __name__, url_prefix='/products')

@bp.route("", methods=["GET", "POST"])
def products():
   if request.method == "GET":
       category = request.args.get("category") or None

       if category:
           # Executes the provided FQL expression.
           data = client.query( 
              # Maps over an array or FQL page and calls an expression/lambda on each item.
              # In this case, we are calling q.get on each item returned from the 2nd parameter’s q.paginate.
               q.map_(
                   # q.get takes a document’s Ref and retrieves the entire document.
                   # Refs are similar to primary/foreign keys and serve as unique pointers to documents.
                   lambda x: q.get(x),
                   # q.index returns the Ref for an index. Note that all entities in FaunaDB are documents and have Refs.
                   # q.match takes the ref of an index, along with search parameters, and returns something called a SetRef.
                   # Finally, q.paginate takes a SetRef and returns a page with iterable data.
                   q.paginate(q.match(
                       q.index("products_by_category"), category)))   
                   )
           response = [i["data"] for i in data["data"]]
           for i in range(0, len(response)):response[i]['id'] = str(data["data"][i]["ref"].id())
           return jsonify(data=response)



       data = client.query(
           q.map_(
               lambda x: q.get(x), q.paginate(q.documents(q.collection("products")))
           )
       )
     # We use q.documents to return all document refs in a collection
       response = [i["data"] for i in data["data"]]
       for i in range(0, len(response)):response[i]['id'] = str(data["data"][i]["ref"].id())
       return jsonify(data=response)

   elif request.method == "POST":

       request_data = request.get_json()
       response = client.query(
           q.create(q.collection("products"), {"data": request_data})
       )
     # FQL: q.create(collection, data_to_create) - Used to create a new document in a collection
       return jsonify(id=response["ref"].id())


@bp.route("/&amp;lt;id&amp;gt;", methods=["GET", "PUT", "DELETE"])
def product(id):
   if request.method == "GET":
       try:
           response = client.query(q.get(q.ref(q.collection("products"), id)))
           return jsonify(data=response["data"])

       except errors.NotFound:
           return jsonify(data=None)

   elif request.method == "PUT":
       # FQL: update a products document
       try:
           response = client.query(
               q.update(
                   q.ref(q.collection("products"), id), {"data":request.get_json()}
               )
           )
      # FQL: we use q.update(doc_ref, data) to update an existing document in a collection 
       except Exception as e:
           return jsonify(error=str(e))

   elif request.method == "DELETE":
       # FQL: delete a product document matching the specified product Ref.
       try:
           response = client.query(q.delete(q.ref(q.collection("products"), id)))
           return response
       except Exception as e:
           return jsonify(error=str(e))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Reviews Microservice.
&lt;/h4&gt;

&lt;p&gt;As described above, this microservice will be responsible for creating, reading, updating and deleting reviews for our application.&lt;/p&gt;

&lt;p&gt;Add the following code to the reviews microservices file.&lt;br&gt;
[./app/services/reviews.py]&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from flask import (
   Blueprint, render_template, jsonify, request
   )
from app.db import client

# Fauna Imports
from faunadb import query as q
from faunadb import errors
from faunadb.objects import Ref

bp = Blueprint('reviews', __name__, url_prefix='/reviews')

@bp.route("", methods=["GET", "POST"])
def reviews():
   if request.method == "GET":
       product = request.args.get('product')
       if product:
      # FQL: Query the reviews_by_product index for products matching the category using the match function.
           data = client.query(
               q.map_(
                   lambda x: q.get(x), q.paginate(q.match(
                       q.index("reviews_by_product"), product))) 
                   )
           response = [i["data"] for i in data["data"]]
           for i in range(0, len(response)):response[i]['id'] = str(data["data"][i]["ref"].id())
           return jsonify(data=response)

       data = client.query(
           q.map_(lambda x: q.get(x), q.paginate(q.documents(q.collection("reviews"))))
       )
       response = [i["data"] for i in data["data"]]
       for i in range(0, len(response)):response[i]['id'] = str(data["data"][i]["ref"].id())
       return jsonify(data=response)

   elif request.method == "POST":

       request_data = request.get_json()
       response = client.query(
           q.create(q.collection("reviews"), {"data": request_data})
       )
       return jsonify(id=response["ref"].id())

@bp.route("/&amp;lt;id&amp;gt;", methods=["GET", "PUT", "DELETE"])
def review(id):
   if request.method == "GET":
       # Retrieve a reviews document that matched a specified id.
       try:
           response = client.query(q.get(q.ref(q.collection("reviews"), id)))
           return jsonify(data=response["data"])

       except errors.NotFound:
           return jsonify(data=None)

   elif request.method == "PUT":
       # FQL: update a reviews document that match the id specified
       try:
           response = client.query(
               q.update(
                   q.ref(q.collection("reviews"), id), {"data":response.get_json()}
               )
           )
       except Exception as e:
           return jsonify(error=str(e))

   elif request.method == "DELETE":
       # FQL: delete a reviews document that match the id specified
       try:
           response = client.query(q.delete(q.ref(q.collection("reviews"), id)))
           return response
       except Exception as e:
           return jsonify(error=str(e))

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Register Services.
&lt;/h4&gt;

&lt;p&gt;Our application has it’s microservices written as blueprints. In Flask, we will need to register each of these blueprints to make them available to our application.&lt;br&gt;
To do this, add the following code to the ./app/&lt;strong&gt;init&lt;/strong&gt;.py file&lt;/p&gt;

&lt;p&gt;[./app/&lt;strong&gt;init&lt;/strong&gt;.py]&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os
from flask import Flask

def create_app():

   app = Flask( __name__, instance_relative_config=True,)
   app.config.from_mapping( SECRET_KEY=os.environ.get('SECRET_KEY') or 'you-never-guess',)

   from app.services import index, products, reviews

   app.register_blueprint(index.bp)
   app.register_blueprint(products.bp)
   app.register_blueprint(reviews.bp)

   return app

app = create_app()

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  TESTING.
&lt;/h4&gt;

&lt;p&gt;To run our application in testing and debug mode run the following in the application directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 run.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since our microservices exist as REST API endpoints that are decomposed by paths and routes, if you’re interested, you can make use of Postman to test how well they work. Here’s a &lt;a href="https://gist.githubusercontent.com/brianraila/0e9a7656a71e8eab884b39426088f299/raw/fe8bd6ac00c601a5d20618781ed80d34497707ed/faunadb-flask-microservices-postman-collection.json" rel="noopener noreferrer"&gt;Postman Collection&lt;/a&gt; you can use to test the various routes.&lt;/p&gt;

&lt;p&gt;The following &lt;a href="https://github.com/brianraila/faunadb-flask-microservices-tutorial" rel="noopener noreferrer"&gt;Github repo&lt;/a&gt; has sample data you can use to test each of the endpoints. &lt;/p&gt;

&lt;h4&gt;
  
  
  DEPLOYING TO VERCEL.
&lt;/h4&gt;

&lt;p&gt;Vercel allows for configuration files to describe how we’d like our microservices deployed.&lt;br&gt;
The template we used comes with one by default so you will not need to do so; below is what it looks like.&lt;/p&gt;

&lt;p&gt;[./vercel.json]&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "version": 2,
    "builds": [
        {
            "src": "./index.py",
            "use": "@vercel/python"
        }
    ],
    "routes": [
        {
            "src": "/(.*)",
            "dest": "/"
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To deploy our app to &lt;a href="https://vercel.com" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt;, we first need to install the &lt;a href="https://vercel.com/docs/cli" rel="noopener noreferrer"&gt;Vercel CLI&lt;/a&gt; by running the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i -g vercel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensure you have a Vercel account, or head over to Vercel.com to create one.&lt;/p&gt;

&lt;p&gt;Once registered, run the following command to login to the CLI with your account.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vercel login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the prompts to confirm your email.&lt;br&gt;
Once you successfully login, run the following command to setup and deploy the app to Vercel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vercel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will receive a similar prompt screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4bppvlrwt1mup58p5jm0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4bppvlrwt1mup58p5jm0.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since Vercel still doesn’t know your FAUNA SECRET KEY, you will get an error while using the app. To rectify this, add the secret key to your Vercel environment as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vercel env add
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the prompts as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftis9bmkvgod1qmpvexcy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftis9bmkvgod1qmpvexcy.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add the key for the production environment and if you wish, the dev environment.&lt;/p&gt;

&lt;p&gt;Now redeploy your app using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vercel --prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now your application should be live.&lt;br&gt;
You can preview your app by visiting the link provided by Vercel.&lt;/p&gt;

&lt;h4&gt;
  
  
  CONCLUSION
&lt;/h4&gt;

&lt;p&gt;From the tutorial, we can see how easy it is to get started with Fauna for our microservices. Fauna is indeed a powerful database; through FQL we have a flexible query language to support a myriad of queries and data models. It also comes with great features suited for microservices, like multi-tenancy and granular permissions.&lt;/p&gt;

&lt;p&gt;Combined together with Vercel, we can have a truly serverless and fully managed microservice architecture. This is a great boost to productivity as we can focus on implementing features that make our application and UX unique, instead of getting hung up on the DevOps of old-school servers and databases.&lt;/p&gt;

&lt;p&gt;I hope you find Fauna to be exciting, like I do, and that you enjoyed this article. Feel free to follow me on Twitter &lt;a href="https://twitter.com/theamolo" rel="noopener noreferrer"&gt;@theAmolo&lt;/a&gt; if you enjoyed my perspective!&lt;/p&gt;

&lt;p&gt;BONUS: &lt;br&gt;
All code written for this tutorial can be found in the following &lt;a href="https://github.com/brianraila/faunadb-flask-microservices-tutorial" rel="noopener noreferrer"&gt;Github Repo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>fauna</category>
      <category>microservices</category>
      <category>flask</category>
      <category>vercel</category>
    </item>
    <item>
      <title>How to build your own URL Shortener with FaunaDB</title>
      <dc:creator>Amolo</dc:creator>
      <pubDate>Mon, 17 Aug 2020 07:08:56 +0000</pubDate>
      <link>https://forem.com/amolo/how-to-build-your-own-url-shortener-with-faunadb-99e</link>
      <guid>https://forem.com/amolo/how-to-build-your-own-url-shortener-with-faunadb-99e</guid>
      <description>&lt;h1&gt;
  
  
  Introduction.
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=Write-with-Fauna_BAmolo_URLShortener"&gt;FaunaDB&lt;/a&gt; provides you with a fully managed database, therefore you don’t have to worry about provisioning, patching and monitoring.&lt;br&gt;
Therefore, using &lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=Write-with-Fauna_BAmolo_URLShortener"&gt;FaunaDB&lt;/a&gt; is a great way for developers to increase their productivity.&lt;br&gt;
This tutorial demonstrates how to get started with GraphQL with &lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=Write-with-Fauna_BAmolo_URLShortener"&gt;FaunaDB&lt;/a&gt;. In this tutorial will be building a simple URL shortening app. With this app you can test basic create and read functionality.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Application
&lt;/h3&gt;

&lt;p&gt;The final application will allow us do the following.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enter a long unreadable/readable link and turn it into a shorter less scary link.&lt;/li&gt;
&lt;li&gt;Direct you to the original URL upon visiting the generated short URL.
Pretty much the basic features of a URL shortener such as Bitly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Pre-requisites.
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;A &lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=Write-with-Fauna_BAmolo_URLShortener"&gt;FaunaDB&lt;/a&gt; Account&lt;/li&gt;
&lt;li&gt;A Netlify Account.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Application Architecture/Stack.
&lt;/h3&gt;

&lt;p&gt;The application we build in this tutorial will model concepts of the JAMStack.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why JAMStack?&lt;/strong&gt;&lt;br&gt;
JAMStack is a relatively new way of building websites and apps that delivers a better performance, higher security, lower cost of scaling, and a better developer experience.&lt;/p&gt;

&lt;p&gt;For the frontend, we will be using React to build our web page which will be served on Netlify. One of the biggest advantages of this is that Netlify will automatically build, deploy and serve your application for you. This site will be served from their CDNs, hence you are assured of extremely fast site response times.&lt;/p&gt;

&lt;p&gt;As in the case of many applications, we will need to store our data. In this case, we will make use of &lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=Write-with-Fauna_BAmolo_URLShortener"&gt;FaunaDB&lt;/a&gt;. Due to the advantages of &lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=Write-with-Fauna_BAmolo_URLShortener"&gt;FaunaDB&lt;/a&gt; we are able to focus on the app and let the Fauna team  worry about provisioning, patching and monitoring tasks.&lt;/p&gt;

&lt;p&gt;In order to securely access our database without sharing our Fauna API keys we will use Netlify Functions as an intermediary to interact.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TIP:&lt;/strong&gt;&lt;br&gt;
Adopting an architecture similar to the one above allows you to focus on what really matters. The features you need for your application’s users while leaving other time-consuming tasks such as provisioning, automatic scaling, maintaining infrastructure and patching the provider to handle it for you, Netlify and &lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=Write-with-Fauna_BAmolo_URLShortener"&gt;FaunaDB&lt;/a&gt; in this case.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt;&lt;br&gt;
It’s possible to hit &lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=Write-with-Fauna_BAmolo_URLShortener"&gt;FaunaDB&lt;/a&gt; GraphQL endpoints from the browser over HTTP,  but in this case, we will make use of Netlify Functions for our server-side logic. Hence, our use of Netlify Functions.&lt;/p&gt;
&lt;h3&gt;
  
  
  Application Flow.
&lt;/h3&gt;

&lt;p&gt;Our basic flow for shortening a link will be as follows.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enter your long URL in a form. In this case an HTML form from our React frontend.&lt;/li&gt;
&lt;li&gt;Check for URL validity by using Regex pattern to test if the input is a valid URL.&lt;/li&gt;
&lt;li&gt;This input is then sent to your database and a short URL is generated. 
All this will be taken care of using the Netlify Function. 
If successful, the short URL will be sent back to the client as the short version of their URL.&lt;/li&gt;
&lt;li&gt;On the part of resolving shortened links, once a URL is visited, all requests meant to resolve links will be routed to functions running on Netlify. We will do this by applying routing rules in our &lt;code&gt;netlify.toml&lt;/code&gt; file.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Login to your &lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=Write-with-Fauna_BAmolo_URLShortener"&gt;FaunaDB&lt;/a&gt; account.
&lt;/h3&gt;

&lt;p&gt;If you don’t have an account, you will be required to sign up to get started which is very easy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=Write-with-Fauna_BAmolo_URLShortener"&gt;FaunaDB&lt;/a&gt; also offers a generous free tier for you not only to test your app but you can also use this to build your small hobby apps. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xnoeqdZ1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ef5ifmf3eimpd2zvw75s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xnoeqdZ1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ef5ifmf3eimpd2zvw75s.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Creating the GraphQL database.
&lt;/h3&gt;

&lt;p&gt;In order to hold all our application’s data, we will need to create a database.&lt;br&gt;
Click [ New Database], provide any preferred name for the database, in our case, we will name it &lt;code&gt;url_shortener&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PNG_qFWP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1afa4a7f1my3tf5v4e1s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PNG_qFWP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1afa4a7f1my3tf5v4e1s.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Importing your GraphQL schema to &lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=Write-with-Fauna_BAmolo_URLShortener"&gt;FaunaDB&lt;/a&gt;.
&lt;/h3&gt;

&lt;p&gt;The beauty of using GraphQL on Fauna is that it allows you to define a schema and it will do its magic to ensure your entities, their relationships are created. All you need to provide is a schema.&lt;/p&gt;

&lt;p&gt;On the GraphQL tab, you should see the following page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZV-vlQG9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rj5475h8qeii323igj45.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZV-vlQG9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rj5475h8qeii323igj45.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click [Import Schema], and select your schema file and allow for Fauna to do all the magic for you.&lt;br&gt;
Our entire application will be based around this simple schema.&lt;/p&gt;

&lt;p&gt;[schema.gql]&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type URL {
  short_url: String!
  long_url: String!
}
type Query {
  findURLbyShortURL(short_url: String!): URL
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing queries and mutations.
&lt;/h3&gt;

&lt;p&gt;For our URL shortener to work, we will need to send data to the database to save our long URLs and also need to read the database for stored URLs while resolving these URLs.&lt;br&gt;
In GraphQL lingo, these can be described as mutations and queries respectively. &lt;br&gt;
In order to understand how this works and whether it really works, let's test these using the GraphiQL interface provided by Fauna.&lt;/p&gt;

&lt;p&gt;To test saving a link, we can do the following.&lt;/p&gt;

&lt;p&gt;[Test Mutation Code Snippet]&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; # Write your query or mutation here
mutation {
          createURL(data:{
            short_url:"fdb", 
            long_url:"https://fauna.com"
          }) {
            short_url
            long_url
            _id
          }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;[Test Mutation Screenshot] &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QF-2Yf8l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/znmcgpid4rccth1excys.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QF-2Yf8l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/znmcgpid4rccth1excys.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, we can test retrieving the link we just saved, we can use the following code.&lt;/p&gt;

&lt;p&gt;[Testing Querying Code Snippet]&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Write your query or mutation here
query {
        findURLbyShortURL(short_url:"fdb"){
      long_url
        _id
        _ts
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;[Testing Querying Screenshot]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3nHzQk1v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/36yhjmelsqrzd8qr3xuo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3nHzQk1v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/36yhjmelsqrzd8qr3xuo.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TIP:&lt;/strong&gt; &lt;br&gt;
You may notice two ‘strange’ fields (_ts and _id) while querying your saved data. &lt;br&gt;
Fauna automatically takes care of creating two fields for you. A unique identifier (_id) and the timestamp  (_ts). Therefore you don’t really have to worry about creating these yourself. Simply saving your data will ensure the two fields are automatically present which I really like.&lt;/p&gt;
&lt;h3&gt;
  
  
  Obtain your API key and save it.
&lt;/h3&gt;

&lt;p&gt;On the security tab, select [New Key]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--s5sq8MEc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r4caryjqrwaroyf1gzji.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--s5sq8MEc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r4caryjqrwaroyf1gzji.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then proceed to select the type of key you want to create. In this case, a Server Key is sufficient to provide  access to our database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt;&lt;br&gt;
Fauna allows you to create two types of keys.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Admin&lt;/strong&gt;: Used to create, destroy, or manage any database or key. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server&lt;/strong&gt;: Can be used to create, destroy, or manage the database to which they are assigned.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AioPPuld--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wvmamrq565ddbf9zeb4j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AioPPuld--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wvmamrq565ddbf9zeb4j.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In order to access this database from any external application, &lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=Write-with-Fauna_BAmolo_URLShortener"&gt;FaunaDB&lt;/a&gt; requires you to provide this key for it to determine which database you have permission to access.&lt;br&gt;
Save it somewhere safely as you will require it in the upcoming steps.&lt;br&gt;
You can now make it available in your &lt;code&gt;env&lt;/code&gt; by using the following command.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;export FAUNA_SECRET=yourfaunaAPIkey&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Structuring the project
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Creating the React App.
&lt;/h4&gt;

&lt;p&gt;We will download and run the official Netlify &lt;a href="https://github.com/netlify/create-react-app-lambda"&gt;create-react-app and Lambda starter kit&lt;/a&gt;. This will set us up with a base for both our frontend and backend code and allow us to quickly get started.&lt;/p&gt;

&lt;p&gt;We will run the following commands&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/netlify/create-react-app-lambda.git
cd create-react-app-lambda
npm install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s take a quick look at the file structure here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;package.json&lt;/strong&gt;: This application's dependencies, shared between client and server code. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;netlify.toml&lt;/strong&gt;: The configuration that Netlify will use for our application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;src/&lt;/strong&gt;: The source code for the React frontend app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;src/lambda/&lt;/strong&gt;: The server source code that will be deployed to Netlify Functions.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Add your functions in the lambda folder.
&lt;/h3&gt;

&lt;p&gt;Inside your app directory, you will find a lambda folder.&lt;br&gt;
The functions in our application are going to live in this lambda folder. You can set up this to be whatever you want but Netlify recommends using this convention.&lt;br&gt;
In the case of this tutorial, we will only have two functions.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Shorten URL - Take the long URL, save it on Fauna and return a short URL.&lt;/li&gt;
&lt;li&gt;Resolve URL – Takes a short URL and will return the original long URL. &lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Write code for the two functions.
&lt;/h3&gt;

&lt;p&gt;Since we  will use Apollo to access our GraphQL API, install it then create a ‘utils.js’ file to maintain a cleaner code and allow for code reuse instead of initializing it twice.&lt;/p&gt;

&lt;p&gt;[utils.js]&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { ApolloClient, InMemoryCache } from '@apollo/client';
import fetch from 'isomorphic-fetch';

const URL = 'https://graphql.fauna.com/graphql'

const client = new ApolloClient({
   uri: URL,
   fetch: fetch,
   headers: {
       authorization: “Bearer ${process.env.FAUNA_SECRET}“,
   },
   cache: new InMemoryCache({}),
 })

export default client;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the functions directory we created above, we will write two functions. &lt;br&gt;
We will create two files &lt;code&gt;shortenURL.js&lt;/code&gt; and &lt;code&gt;resolveURL.js&lt;/code&gt;&lt;br&gt;
Inside &lt;code&gt;src/lambda/shortenURL.js&lt;/code&gt; write the following code. &lt;/p&gt;

&lt;p&gt;[shortenURL.js]&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { gql } from '@apollo/client';
import client from './utils';


export async function handler(event, context) {

   if (event.httpMethod === 'POST'){
       // get data from POST request
       console.log(event)
       let long_url = JSON.parse(event.body).long_url;

       let SHORTEN_URL_QUERY = gql`
           mutation {
             createURL( data:{short_url: "${(Math.random().toString(36).substring(7))}", long_url:"${long_url}"})
                       {
                           short_url
                           long_url
                       }
           }`;
        let results = await client.mutate({
           mutation: SHORTEN_URL_QUERY
       })

       console.log(results.data.createURL.short_url);
       return {
           statusCode: 200,
           body: JSON.stringify({

"short_url":results.data.createURL.short_url }),
       }
   }
   else {
       return {
           statusCode: 405,
           body: JSON.stringify({ error: "Method not allowed" })
       }
   }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside &lt;code&gt;src/lambda/resolveURL.js&lt;/code&gt; write the following code. &lt;br&gt;
[resolveURL.js]&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { gql } from '@apollo/client';
import client from './utils';

export async function handler(event, context) {

   let short_url = event.path.split('/', 5)[4];
   let RESOLVE_URL_QUERY = gql`
     query {
           findURLbyShortURL(short_url:"${short_url}"){
           long_url
       }
     }
   `;
   let results = await client.query({
       query: RESOLVE_URL_QUERY
     })

   return {
     statusCode: 301,
     // send HTTP redirect headers (Location)
     headers:{
       Location: results.data.findURLbyShortURL.long_url
     },
     body: results.long_url,
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;TIP:&lt;/strong&gt;&lt;br&gt;
Once you are done. It is always good development practice to test these functions. Netlify provides a CLI tool to quickly test your functions locally. You can install it by running.&lt;br&gt;
&lt;code&gt;npm install netlify-cli -g&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then on your command line use &lt;br&gt;
&lt;code&gt;ntl dev&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Implement React Frontend
&lt;/h4&gt;

&lt;p&gt;Now that we have our functions working, we will need to connect them to our frontend.&lt;/p&gt;

&lt;p&gt;We will create a simple input form with a button to allow the user to enter a long URL and send it over to a function that will take care of generating a short URL and the save it to &lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=DevTo&amp;amp;utm_medium=referral&amp;amp;utm_campaign=Write-with-Fauna_BAmolo_URLShortener"&gt;FaunaDB&lt;/a&gt;.&lt;br&gt;
To do this, go to your &lt;code&gt;src/app.js&lt;/code&gt; file and add the following code.&lt;/p&gt;

&lt;p&gt;[*app.js]&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState } from "react";
const node_fetch = require('node-fetch');

export default function App(props) {
 const [URL, setURL] = useState("");

 const shortenURL = async function(long_url) {

   let response = await node_fetch('/.netlify/functions/shortenURL', {
     body: JSON.stringify({long_url: long_url}),
     method: 'POST',
     mode: 'no-cors'
   })
   let data = await response.json();
   return data;
 }
  const handleSubmit = async (event) =&amp;gt; {
   event.preventDefault();
     if (URL !== ""){
       event.preventDefault();
       await shortenURL(URL).then(data =&amp;gt; {
         alert(“http://”+window.location.hostname + “/”+ data.shorturl);
       })
     }
     else{
       alert(`Provide a valid URL`)
     }
 }
 return (

   &amp;lt;form style={{margin:"auto", textAlign:"center"}}&amp;gt;
     &amp;lt;h5&amp;gt;Fauna URL Shortener&amp;lt;/h5&amp;gt;
     &amp;lt;label&amp;gt;
       URL to shorten:
       &amp;lt;input type="text" value={URL} onChange={e =&amp;gt; setURL(e.target.value)} /&amp;gt;
     &amp;lt;/label&amp;gt;
     &amp;lt;input type="button" value="Shorten" onClick={handleSubmit} /&amp;gt;
   &amp;lt;/form&amp;gt;
 );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will have your application looking like in the below figure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pwWkIC1q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3hkc3l44hj1l2ztowvrf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pwWkIC1q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3hkc3l44hj1l2ztowvrf.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Linking functions to React Application.
&lt;/h3&gt;

&lt;p&gt;We need a way to tell our React code to call the functions as required to ensure the application flow works as desired.&lt;/p&gt;

&lt;p&gt;For URL resolution requests, we don’t need to load our React application in order to perform the redirect.&lt;br&gt;
Instead, in the netlify.toml file at the root of our project, we will add the following line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[[redirects]]
  from = "/*"
  to = "/.netlify/functions/resolveURL/:splat"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now all requests beyond the / route will be redirected to our resolver function to take care of the routing to that URL.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deployment.
&lt;/h3&gt;

&lt;p&gt;Deploying to Netlify is relatively easy, all you need to do is to create a git repository. &lt;br&gt;
This is a good practice as you are able to easily version control your entire application.&lt;br&gt;
Next, commit your changes and push to the repository you created.&lt;br&gt;
On the Netlify GUI, go to [New Site from Git]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--00zbbv4x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rdpdfom4tyz1h2gebqd3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--00zbbv4x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rdpdfom4tyz1h2gebqd3.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then select your desired project and Netlify will take care of the building, provisioning and deploying.&lt;br&gt;
Once it's done, you will be provided with a URL to access your application. &lt;br&gt;
Wasn’t that easy?&lt;/p&gt;

&lt;h4&gt;
  
  
  Other possibilities.
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You can allow users to shorten their URL and provide customized short links that could stand for events, entities or literally anything.&lt;/li&gt;
&lt;li&gt;You can enable analytics for URL shortened&lt;/li&gt;
&lt;li&gt;You can switch from using GraphQL and use FQL instead.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>fauna</category>
      <category>graphql</category>
      <category>react</category>
      <category>serverless</category>
    </item>
  </channel>
</rss>
