Flask web API with Firebase
Hello again, today I’m going to pick up where I left off with more Flask~ing (…..can I say that? o_0 ). As usual with my multi-part posts I suggest you start with the first, you can find that here. I spoke about setting up your Flask environment and touched on routing your web application. I want to now move onto showing you how to incorporate an API with Flask. API-First design has now become common practise with teams of developers, often the API is designed to serve your front end web site as a client with the scope of opening up the API for public use.
To do this I will be using Firebase. Firebase provides a great backend as a service (BaaS) product to quickly get up and running with you API. You can log in with your Google account to use the service, the free service is perfectly adequate for our purposes. The documentation on the firebase website is very good and easy to pick up so I won’t go through it. However I will provide you a base you can import to your app database, which is just one big JSON object.
{
"films" : {
"film1" : {
"Rating" : "9",
"Title" : "The Matrix",
"Year" : "1999"
}
}
}
Now that you have Firebase set up we are ready to build our Flask API.
Theory######
Just a quick run through about what we are trying to achieve. In this example, we are going to create a form where someone can enter information about a movie. We will ask for title, the year of release and a rating. Upon submitting the form we are going to use the api service to shoot the information as JSON to our database on firebase. In order to do this we are going to use a few different packages. We will use;
- WTForms - a python library for form rendering and validation
- Flask-WTF – a library which intergrates WTForms with Flask
- python-firebase – a python interface to Firebase.
Let’s get to it######
To make our life easier there is a great python package for quickly allowing us to use the Firebase API. We will need this library for our example so please go ahead and get it, note – don’t use the package from the PIP repo as it has some bugs. Instead grab it from github. Credit to Ozgur.
Let pick up with the code we left off in the last post, view.py:
from firebase import firebase
from flask import Flask
from .forms import FirePut
app = Flask(__name__)
firebase = firebase.FirebaseApplication(‘<path tofirebase app>’, None)
@app.route(‘/’)
def index():
return “<h1>Hello, world!</h1>”
@app.route(‘/testing’)
def testing():
return “<h1>This is another testing page</h1>”
If __name__ == ‘__main__’:
app.run(debug=True)
The astute among you would of noticed that the above code has three amendments. The first is importing the firebase package, the next is where we import a package called FirePut, this will be explained later. Lastly firebase is initisalised. The
count = 0
@app.route(‘/api/put’, methods=[‘GET’, ‘POST’])
def fireput():
form = FirePut()
If form.validate_on_submit():
global count
count += 1
putData = {‘Title’ : form.title.data, ‘Year’ : form.year.data, ‘Rating’ : form.rating.data}
firebase.put(‘/films’, ‘film’ + str(count), putData)
return render_template(‘api-put-result.html’, form=form, putData=putData)
return render_template(‘My-Form.html’)
Ok that’s a lot of new code to digest, let’s start at the top. I started off by declaring a global variable ‘count’, then we created a route for the api declaring GET and POST methods for the route. Next I declared my function fireput() but this can really be another of your choosing. Then I declared a form field and initialised the FirePut that was imported earlier.
Next I constructed an if statement that uses the wtform method validate_on_submit() to check that the form submitted meets it’s validators( we will see how this works later). The “global count” is telling our method that we want to access the count variable and we are simply incrementing the value by one every time the method runs, (of course in the real world this value would need to be persistent). The putData variable is a dictionary containing the data we want to send over to firebase. We are using the form variable to access our FirePut method, (we still need to see what this is) for now all you need to know is this is allowing us to access information that is typed on our form.
The putData variable is used in the next line, we call the firebase put method, specify the films object that we want to add to as the first parameter then the film id (in this case I have chosen to use filmN where N is the incrementing count). The third parameter is the data we want to send, in this case the putData variable. Lastly use flasks render_template method and pass our html page, along with creating parameters that contain the form and putData.
So in short we are saying:
- If the form is posted correctly
- Increase our count
- Take the captured form data and place it in the putData dictionary
- Shoot that data off to firebase
- And return the api-put-result html page
- Else return the My-Form.html page
Now as it stands this alone won’t work. Remember the .forms import of FirePut? This will handle our form processing, we need to create the file before the above will work. Let us take a look at form.py;
from flask.ext.wtf import Form
from wtforms import StringField, BooleanField
from wtforms.validators import DataRequired
Class FirePut(Form):
title = StringField(‘title’, validators=[DataRequired()])
year = StringField(‘year’, validators=[DataRequired()])
rating = StringField(‘rating’, validators=[DataRequired()])
Here we are using wtform and its flask intergration library flask.ext.wtf along with form validation with wtf.forms.validators. So this class we defined takes the wtf Form as a parameter and within it we define variables of object type StringField, where we pass the name of the field we want to map to in the html as param1 and a validator of DataRequired in param2. This is a simple validator that says we won’t allow nothing to be entered in this field. We do the same for year and rating. Now lets look at the html for this. My-Form.html
{% block content %}
<h3> Complete below</h3>
<p>Please complete the form below<p>
<form action="" method="post" name="api">
<p> Please enter a movie you want to add.: <br>
{{ form.title(size=40) }}<br>
{% for error in form.title.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}<br>
<p> Please enter the year the movie was released.: <br>
{{ form.year(size=40) }} <br>
{% for error in form.year.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}<br>
<p> Please enter the rating you give the movie out of 10.: <br>
{{ form.rating(size=40) }} <br>
{% for error in form.rating.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}<br>
<p><input type ="submit" value="Add" class="btn btn-sm btn-primary"></p>
</form>
{% endblock %}
You would have noticed that this doesn’t look like your conventional html code. What we are seeing here is the Jinja template engine at work. Here we are creating a form with 3 fields, these fields map to the variables we created in form.py - movie title, movie year and movie rating. Jinja allows us to map our wtform to the actual input from the client.
{{ form.title(size=40) }}
This is how we are accessing our form variables. Remember when we set up our route, we created a variable form = FirePut(). Our template has access to this variable so when we say form.title we are referencing the title variable we set up in our FirePut() method, the parameter size=40 is specifying the size of the input box. The validation has been handled on the next line.
{% for error in form.title.errors %}
<span style=”color: red;”>[{{ error }}]</span>
Our validator of DataRequired runs if an error is found we produce the error message giving it a red styling. We repeat this for Year and Rating.
The last piece of the puzzle is the view the user will get after submitting the form. Lets take a look at the api-form-result.html:
{% block content %}
<h3> Complete below</h3>
<p> The movie you entered is: {{PutData[‘Title’] }} <br>
<p> The year this movie was made is: {{ putData[‘Year’] }} <br>
<p> The rating you gave this movie is: {{ putData[‘Rating’] }} <br>
{% endblock %}
Here we are simply presenting the data submitted back to the user. The putData dictionary is getting accessed to place the values on the page.
So lets see this in action######
If all has gone well, you should end up with a form looking like below:
Enter your movie credentials. Once you submit these, the firebase put() method will place the information in the database and then the api-form-result.html will get rendered to the browser
Fin######
We covered a lot of concepts from templating to form processing and using Firebase in flask. I hope this post has demonstrated how you can go about building a quick api for your web application.