DEV Community

LordGhostX
LordGhostX

Posted on

Building Faunabin: A Pastebin Clone with Python and Fauna

In the past couple of months, I've been building applications with Fauna such as a Telegram bot and a URL shortener. It got me interested in building more, especially since Fauna makes it very easy to configure and manage serverless databases. So, I decided to explore more about this database and build something a little more complex.

In this article, we will be building an online text-pasting tool similar to Pastebin using Python, Flask, and Fauna. We will also be deploying our app to Heroku.

Alt Text

Creating Faunabin User Interface

We are going to build the user interface for Faunabin with Flask-Bootstrap which is an extension that allows for easy integration of Bootstrap into Flask applications.

We will be building two web pages for Faunabin. The first will have a text box where users can paste their notes (paste page), while the second page will enable users to view what they pasted (result page).

Step 1: Install Required Libraries

We need to install both Flask and Flask-Bootstrap libraries via the Python Package Manager (pip).

$ pip install flask
$ pip install flask-bootstrap
Enter fullscreen mode Exit fullscreen mode

Step 2: Set Up Our Flask Server

Open your text editor, create a file with the name app.py, then save the code below in it.

from flask import Flask, render_template
from flask_bootstrap import Bootstrap

app = Flask(__name__)
Bootstrap(app)

@app.route("/")
def index():
    return render_template(index.html)

if __name__ == "__main__":
    app.run(debug=True)
Enter fullscreen mode Exit fullscreen mode

Step 3: Build Our Paste Page

The paste page is where users are provided with a text box to paste whatever they wish, with options to tweak their paste (just like the image above).

First, create a folder named templates in the same folder as our app.py. A templates folder is used by Flask to store its HTML files which will be rendered by the server in later parts of the application. Our project folder should resemble the image below:

Alt Text

Create another file named index.html which will be stored inside the templates folder and save the code below in it.

{% extends "bootstrap/base.html" %}
{% block title %}Faunabin: Paste text and share with your friends{% endblock %}

{% block content %}
<div class="jumbotron text-center">
  <h1>Faunabin</h1>
  <h3>Paste text and share with your friends</h3>
</div>

<div class="container">
  <form method="POST">
    <div class="form-group">
      <h4>Faunabin Paste Title</h4>
      <input type="text" class="form-control" name="title" required>
    </div>
    <div class="form-group">
      <textarea class="form-control" name="paste-text" rows="20" required>
      </textarea>
    </div>
    <div class="form-group text-center">
      <button type="submit" class="btn btn-lg btn-primary">Create New Paste</button>
    </div>
  </form>
</div>
{% endblock %}
Enter fullscreen mode Exit fullscreen mode

When we run our app.py file we should get a response similar to the image below:

Alt Text

Alt Text

Step 4: Build Our Result Page

The result page is where users view pastes that have been created on Faunabin. First, create a file named paste.html in the templates folder and save the code below in it:

{% extends "bootstrap/base.html" %}
{% block title %}Paste Title{% endblock %}

{% block content %}
<div class="jumbotron text-center">
  <h1>Faunabin</h1>
  <h3>Paste text and share with your friends</h3>
</div>

<div class="container">
  <form>
    <div class="form-group">
      <h4>View Faunabin Paste</h4>
      <textarea class="form-control" rows="20" readonly>
      </textarea>
    </div>
    <div class="form-group text-center">
      <a href="{{ url_for('index') }}"><button type="button" class="btn btn-lg btn-primary">Create Another Paste</button></a>
    </div>
  </form>
</div>
{% endblock %}
Enter fullscreen mode Exit fullscreen mode

When this template is rendered we should get a result similar to the image below:

Alt Text

At this point, our project folder structure should resemble the image below:

Alt Text

Getting Started with Fauna

Step 1: Set Up Our Fauna Database

The first thing we need to do is create the database for Faunabin in our Fauna dashboard. If you have not created an account on Fauna before now, create one here: https://dashboard.fauna.com/accounts/register

Alt Text

Provide a name for your database then press the SAVE button. The next thing we have to do is create a collection in our database. A collection is similar to SQL tables that contain data with similar characteristics e.g user collection that contain information about users in the database. We will start by pressing the NEW COLLECTION button.

Alt Text

Then, we supply a name for the collection we will be creating and working with (we will be using pastes for this example). Once you have supplied this information proceed by pressing the SAVE button.

Alt Text

Alt Text

We also need to create an index for our collection. A Fauna index allows us to browse through data that is stored in a database collection, based on specific attributes. To create one, navigate to the DB Overview tab on the Fauna sidebar (left side of the screen) then click the NEW INDEX button.

Alt Text

Alt Text

Supply the name you want to use for your index, set the terms to data.identifier as we will be using that variable to reference our pastes later. Also, remember to select the Unique attribute for our index, this ensures that we do not have a duplicate in our database entries.

Step 2: Generate Fauna API Key

We will need to create a Fauna API Key to connect to our database from Faunabin. To do this, navigate to the security settings on the Fauna sidebar (left side of the screen).

Alt Text
Alt Text

Alt Text

Once you have done this, you will be presented with your API key (hidden here for privacy reasons). The key should be copied as soon as it is generated then stored somewhere you can easily retrieve it.

Step 3: Integrate Fauna into Python

Next, we need to get the Python library for Fauna. It’s available on pip and can be installed with a single line in our terminal.

$ pip install faunadb
Enter fullscreen mode Exit fullscreen mode

After this is installed, we are going to run the sample code provided in Fauna Python driver docs https://docs.fauna.com/fauna/current/drivers/python.html

from faunadb import query as q
from faunadb.objects import Ref
from faunadb.client import FaunaClient

client = FaunaClient(secret="your-secret-here")

indexes = client.query(q.paginate(q.indexes()))

print(indexes)
Enter fullscreen mode Exit fullscreen mode

The code above shows how the Fauna Python driver connects to a database with its API key and prints the indexes associated with it. The result from running this code is similar to the image below.

Alt Text

Integrating Fauna with Faunabin

Now that we have successfully integrated our Python script with Fauna, let’s get started with integrating Fauna with the user interface of Faunabin we created earlier.

Step 1: Creating New Pastes

We need to take the paste text and paste title from the form in the index page, generate a unique identifier, then save it in Fauna. Our updated app.py should resemble the one below:

import pytz
from datetime import datetime
from secrets import token_urlsafe
from flask import Flask, render_template, request, redirect
from flask_bootstrap import Bootstrap
from faunadb import query as q
from faunadb.objects import Ref
from faunadb.client import FaunaClient

app = Flask(__name__)
Bootstrap(app)
client = FaunaClient(secret="your-secret-here")


@app.route("/", methods=["GET", "POST"])
def index():
    if request.method == "POST":
        title = request.form.get("title").strip()
        paste_text = request.form.get("paste-text").strip()

        identifier = token_urlsafe(5)
        paste = client.query(q.create(q.collection("pastes"), {
            "data": {
                "identifier": identifier,
                "paste_text": paste_text,
                "title": title,
                "date": datetime.now(pytz.UTC)
            }
        }))

        return redirect(request.host_url + identifier)
    return render_template("index.html")


if __name__ == "__main__":
    app.run(debug=True)
Enter fullscreen mode Exit fullscreen mode

We used the create method of the FQL client to store the paste text and title as provided by the user along with paste identifier and creation date in our database collection using client.query(q.create(q.collection(collection_name), data)).

Here, we imported a couple of functions from flask so we can read form data, generate unique identifiers, and redirect users to the saved paste page. We can see our newly created document in our Fauna dashboard when we create a new paste.

Alt Text

Step 2: Reading Old Pastes

Since we generated a unique identifier to store each paste submitted by users on Faunabin, we need to create a route in Flask that will take an identifier as input then fetch the related paste and render the data to the user. Our updated code should resemble the one below:

import pytz
from datetime import datetime
from secrets import token_urlsafe
from flask import Flask, render_template, request, redirect, abort
from flask_bootstrap import Bootstrap
from faunadb import query as q
from faunadb.objects import Ref
from faunadb.client import FaunaClient

app = Flask(__name__)
Bootstrap(app)
client = FaunaClient(secret="your-secret-here")


@app.route("/", methods=["GET", "POST"])
def index():
    if request.method == "POST":
        title = request.form.get("title").strip()
        paste_text = request.form.get("paste-text").strip()

        identifier = token_urlsafe(5)
        paste = client.query(q.create(q.collection("pastes"), {
            "data": {
                "identifier": identifier,
                "paste_text": paste_text,
                "title": title,
                "date": datetime.now(pytz.UTC)
            }
        }))

        return redirect(request.host_url + identifier)
    return render_template("index.html")


@app.route("/<string:paste_id>/")
def render_paste(paste_id):
    try:
        paste = client.query(
            q.get(q.match(q.index("paste_by_identifier"), paste_id)))
    except:
        abort(404)

    return render_template("paste.html", paste=paste[data])


if __name__ == "__main__":
    app.run(debug=True)
Enter fullscreen mode Exit fullscreen mode

We used the get method of the FQL client to fetch the paste data we saved in Fauna earlier by specifying the paste ID and index we want to use with client.query(q.get(q.match(q.index(index_name), search_query))).

We are also going to update our paste.html we stored in our templates folder to render the data we are passing accordingly:

{% extends "bootstrap/base.html" %}
{% block title %}{{ paste.title }}{% endblock %}

{% block content %}
<div class="jumbotron text-center">
  <h1>Faunabin</h1>
  <h3>Paste text and share with your friends</h3>
</div>

<div class="container">
  <form>
    <div class="form-group">
      <h4>View Faunabin Paste</h4>
      <textarea class="form-control" rows="20" readonly>
      {{ "\n" + paste.paste_text }}
      </textarea>
    </div>
    <div class="form-group text-center">
      <a href="{{ url_for('index') }}"><button type="button" class="btn btn-lg btn-primary">Create Another Paste</button></a>
    </div>
  </form>
</div>
{% endblock %}
Enter fullscreen mode Exit fullscreen mode

Now that wraps up the whole code for Faunabin which is a Pastebin clone built with Python and Fauna.

Deploying Faunabin to Heroku

Deploying an application means you are uploading it online so it can be accessible to anyone, anywhere in the world. In this article, we would be deploying Faunabin to a free and popular hosting platform called Heroku.

The prerequisites needed to work with Heroku is an account on Heroku, Heroku CLI, and GIT.

Step 1: Install Gunicorn

Gunicorn is a pure-Python HTTP server for WSGI applications. It allows you to run any Python application concurrently by running multiple Python processes within a single dyno. It provides a perfect balance of performance, flexibility, and configuration simplicity when deploying a web app to somewhere such as Heroku.

$ pip install gunicorn
Enter fullscreen mode Exit fullscreen mode

Step 2: Create a WSGI File

from app import app

if __name__ == "__main__":
    app.run()
Enter fullscreen mode Exit fullscreen mode

A WSGI file is an entry to our Python application. Create a file with the name wsgi.py in the same folder as our app.py and save the content above in it. Our file structure should look like this.

Alt Text

Step 3: Generate Requirements File

The next step is to generate your requirements.txt file with either pip freeze or pipreqs. Whatever method you use, make sure gunicorn is in your requirements file.

$ pip freeze > requirements.txt
Enter fullscreen mode Exit fullscreen mode

OR

$ pip install pipreqs
$ pipreqs .
Enter fullscreen mode Exit fullscreen mode

Our file structure and requirements.txt should look like the image below.

Alt Text

Step 4: Create a Procfile

web: gunicorn wsgi:app
Enter fullscreen mode Exit fullscreen mode

A Procfile is used to specify commands that should be executed by a Heroku app when they are started. Create a file with the name Procfile in the same folder as our app.py and wsgi.py then save the content above in it. Our file structure should look like this.

Alt Text

Step 5: Create a Heroku Application

Navigate to the Create new app tab in your Heroku dashboard and you will be presented with a screen similar to the one below. Choose a name for your app and the region it should be deployed to.

Alt Text

Step 6: Deploy Faunabin to Heroku

$ heroku login
$ git init
$ heroku git:remote -a faunabin
$ git add .
$ git commit -m "deploying to heroku"
$ git push heroku master
Enter fullscreen mode Exit fullscreen mode

Alt Text

Alt Text

Congratulations! We have successfully deployed Faunabin to Heroku and it can be accessed anywhere in the world with the web address that was given by Heroku after deployment. Since the name of the app created in this tutorial is faunabin, its URL would be https://faunabin.herokuapp.com

Conclusion

In this article, we built an online text-pasting tool similar to Pastebin with Fauna's serverless database and Python called Faunabin. We saw how easy it is to integrate Fauna into a Python application, got the chance to explore its CRUD functionalities, and finally deployed Faunabin to Heroku.

The source code of Faunabin is available on GitHub. If you have any questions, don't hesitate to contact me on Twitter: @LordGhostX

Top comments (4)

Collapse
 
waylonwalker profile image
Waylon Walker

I need to dive into fauna a bit. Is it easy to use client side? I mostly do python but don't want to have to manage servers outside of work.

Collapse
 
lordghostx profile image
LordGhostX

Yeah, you should take a look at it. It's also easy to use client side

Collapse
 
olanetsoft profile image
Idris Olubisi💡

Interesting 🤲

Collapse
 
lordghostx profile image
LordGhostX

Thank you