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.
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
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)
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:
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 %}
When we run our app.py
file we should get a response similar to the image below:
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 %}
When this template is rendered we should get a result similar to the image below:
At this point, our project folder structure should resemble the image below:
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
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.
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.
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.
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).
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
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)
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.
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)
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.
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)
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 %}
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.
- Create a Heroku account here - https://signup.heroku.com/login
- Follow this guide to install Heroku CLI - https://devcenter.heroku.com/articles/heroku-cli
- Follow this guide to install GIT - https://git-scm.com/book/en/v2/Getting-Started-Installing-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
Step 2: Create a WSGI File
from app import app
if __name__ == "__main__":
app.run()
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.
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
OR
$ pip install pipreqs
$ pipreqs .
Our file structure and requirements.txt
should look like the image below.
Step 4: Create a Procfile
web: gunicorn wsgi:app
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.
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.
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
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)
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.
Yeah, you should take a look at it. It's also easy to use client side
Interesting 🤲
Thank you