This Flask API Tutorial explains popular Flask extensions like Flask twitter Oembedder, Flask API, and Flask RESTful with examples:
The Flask framework has quite an abundant number of extensions. These extensions are quite useful and are easy to be developed. We know that the Flask framework is very Pythonic and has a minimal set of APIs, and is very flexible, which is why the Flask community has created so many extensions for many specific tasks.
As a part of the Flask tutorial series, this tutorial has an example of a few Flask extensions. We will discuss the following extensions.
- Flask twitter Oembedder
- Flask API
- Flask RESTful
=> Visit Here To Learn Flask From Scratch
Though we have discussed many extensions as a part of our previous tutorials, This tutorial explains more with the perspective of examining the components of a Flask extension.
Table of Contents:
What Is A Flask Extension
A flask extension is an installable Python module or a package that implements additional functionality to a Flask application. A Flask extension can be as simple as the one that adds support of consuming an external API such as Twitter to embed a tweet on a web page.
Or, a Flask extension might be a new framework such as Flask API or Flask-RESTful to build apps that follow an architectural pattern or a development paradigm.
Flask twitter Oembedder
In this section, we take the example of an existing open-source simple project from here
Clone this project in your local machine and install it using pip with the help of the below-mentioned command.
# in an activated virtual environment pip install -e flask_twitter_oembedder/
This extension helps in embedding a Tweet with the help of a Jinja2 template tag. However, to use this extension, you will have to apply for a developer account at Twitter. Once you get a developer account, create an App, and you will get keys and secrets to consume Twitter’s API.
Once you have the keys and secrets, store them at a safe place so that the application can access those. We have kept those in the environment variables and have added to the Flask app config, as shown below. Our demo app keeps the configuration values in the config.py file.
# Twitter details import os TWITTER_ACCESS_TOKEN = os.environ.get('TWITTER_ACCESS_TOKEN', None) TWITTER_TOKEN_SECRET = os.environ.get('TWITTER_TOKEN_SECRET', None) TWITTER_CONSUMER_KEY = os.environ.get('TWITTER_CONSUMER_KEY', None) TWITTER_CONSUMER_SECRET = os.environ.get('TWITTER_CONSUMER_SECRET', None)
We get the values of the required variables from the environment variables. If the corresponding value is not present in the environment variable, then that is stored as None.
Once you add the above lines in the config file, go to the Flask application’s __init__.py and initialize it by modifying it, as shown below.
from flask_caching import Cache from flask_twitter_oembedder import TwitterOEmbedder cache = Cache(app, config={'CACHE_TYPE': 'simple'}) twitter_oembedder = TwitterOEmbedder(app, cache)
These lines will initialize the Flask extension. Now we can modify hello.html under templates and add the below-mentioned tag as shown below.
{{ oembed_tweet('1277228221394587649') }}
We added this tag before the for loop in the existing template. That very long digit is the tweet id. We get this id from the Tweet URL after tweeting. After saving the template file, we navigate to the /hello/greetings endpoint and receive the results, as shown in the below image.
Flask RESTful
Our Flask RESTful example application is the one that respects the constraints of the REST architecture. However, it is not like a protocol, and the developers are flexible while implementing features, following the REST constraints.
Please read more about the constraints of the REST architecture here.
Modern web applications allow clients to request the resources at easy to read and stable endpoints in a stateless manner.
Flask RESTful Example
Let’s implement some features in a RESTful manner in our Flask RESTful example application too.
We have a way of storing and serving data related to Albums and Songs. Let’s implement an API using Flask RESTful extension.
First, install Flask RESTful using the below command.
pip install flask-restful
For easy maintenance and understanding, let us create a file called api.py inside the app directory and mention the following lines of code in it. For now, consider APIs similar to Flask Views.
We are going to implement features corresponding to HTTP verbs to respond when the Client sends a request to the Server endpoint of the application.
from flask import request from flask_restful import Resource, reqparse, abort, Api from . import app api = Api(app, prefix='/myapi/v1') def abort_if_song_doesnt_exist(song_name): if song_name not in SONGS: abort(404, message="Song {} doesn't exist".format(song_name)) parser = reqparse.RequestParser() parser.add_argument('title') parser.add_argument('singer') SONGS = { 'Song1': { 'title': 'Past Life', 'singer': 'Selena Gomez' } } class Songs(Resource): def get(self): return {'songs': SONGS} def post(self): args = parser.parse_args(strict=True) song_name = int(max(SONGS.keys()).lstrip('Song')) + 1 song_name = 'Song%d' % song_name SONGS[song_name] = {'title': args['title'], 'singer': args['singer']} return { song_name:SONGS[song_name] }, 201 api.add_resource(Songs, '/songs') class Song(Resource): def get(self, song_name): abort_if_song_doesnt_exist(song_name) return { song_name: SONGS[song_name] } def delete(self, song_name): abort_if_song_doesnt_exist(song_name) del SONGS[song_name] return '', 204 def put(self, song_name): args = parser.parse_args(strict=True) abort_if_song_doesnt_exist(song_name) SONGS[song_name] = {'title': args['title'], 'singer': args['singer']} return { song_name: SONGS[song_name] }, 201 api.add_resource(Song, '/songs/<string:song_name>')
We have created two resources called Songs and Song by subclassing Resource abstract class of Flask-RESTful. The Class called Songs has two methods get and post corresponding to the two HTTP verbs; GET and POST, respectively.
The Songs resource serves all songs to the registered endpoint when the Client requests it and adds a song to the list of existing songs when the data is posted at the same endpoint.
Similarly, in the case of class Song, HTTP GET, DELETE, and PUT are implemented using the methods get, delete, and put. Method get sends a response with the requested song as JSON, method delete removes a song from SONGS, and the put method updates an existing song in SONGS.
Now let us add these resources to our sample application by initializing them in __init__.py file under the app folder.
from . import api
Let’s install curl and try the features on the stated endpoints.
sudo apt -y install curl
Get all songs
curl -k https://localhost:8080/api/v1/songs
We get the response, as shown below.
{ "songs": { "Song1": { "title": "Past Life", "singer": "Selena Gomez" } } }
Now let’s use the below-mentioned command to add a song.
curl -k -d "title=Summer Days&singer=Martin Garrix" https://localhost:8080/api/v1/songs
We get the response from our API, as shown below.
{ "Song2": { "title": "Summer Days", "singer": "Martin Garrix2" } }
Now again, if we query the list of songs as we did in the previous command, and we will get both the songs in the response.
{ "songs": { "Song1": { "title": "Past Life", "singer": "Selena Gomez" }, "Song2": { "title": "Summer Days", "singer": "Martin Garrix2" } } }
Similarly, HTTP DELETE and PUT work as intended. Let us add a few tests for the Version v1 of this Simple API that we have created.
def test_myapi_v1_songs(client): resp = client.get("/api/v1/songs/") #import pdb;pdb.set_trace() assert 200 == resp.status_code def test_myapi_v1_add_song(client): """ The application can store the same data multiple times""" data = { "title": "Summer Days", "singer": "Martin Garrix" } resp = client.post( "/api/v1/songs/", data=data ) assert 201 == resp.status_code
Now run these tests from the command-line, as shown below.
pytest app/tests/test_api.py
Similarly, we can write tests for other methods for more coverage.
An important thing to note down is that the songs that we added persist as a part of the single process under which the development server is running. It means that all new data will be lost as soon as the process shuts down.
Moreover, the task of creating version v1 of the API seems redundant, and it is different than the way we were saving data in the application with the help of forms and views.
Usually, RESTful API implementation requires getting data from the clients, marshaling between Client and server ends, and persistence with the help of database models that we have created.
Moreover, the endpoints are secured for unintended and crafted inputs.
Therefore, we recommend that the above-given examples are only for learning the concepts and the constraints of the REST architecture using HTTP methods. Please remember that this is only one of the many ways of web services, in general, are created. Moreover, there are many ways in which REST architecture can be implemented.
We encourage readers to explore further how REST can have different file formats and custom methods using other protocols and not only JSON and HTTP. Just to give a glimpse of one production use, we provide the example below.
We use a Flask-Appbuilder BaseApi to implement similar features under different endpoints. Open the api.py file and update it with the below-mentioned code.
APIs using appbuilder from flask_appbuilder.api import BaseApi, expose from . import appbuilder class SongsApi(BaseApi): resource_name = 'songs' @expose('/', methods=['POST', 'GET']) def songs(self): if request.method == 'GET': return self.response(200, songs=SONGS) else: args = parser.parse_args(strict=True) song_name = int(max(SONGS.keys()).lstrip('Song')) + 1 song_name = 'Song%d' % song_name SONGS[song_name] = {'title': args['title'], 'singer': args['singer']} return self.response(201, song=SONGS[song_name]) appbuilder.add_api(SongsApi) class SongApi(BaseApi): resource_name = 'songs' @expose("/<string:song_name>", methods=['GET', 'DELETE', 'PUT']) def song(self, song_name): if request.method == 'GET': abort_if_song_doesnt_exist(song_name) return self.response(200, song_name=SONGS[song_name] ) elif request.method == 'DELETE': abort_if_song_doesnt_exist(song_name) del SONGS[song_name] return self.response(204, message="OK") elif request.method == 'PUT': args = parser.parse_args(strict=True) abort_if_song_doesnt_exist(song_name) SONGS[song_name] = {'title': args['title'], 'singer': args['singer']} return self.response(201, song_name=SONGS[song_name]) else: self.response_404() appbuilder.add_api(SongApi)
Now let’s add some more tests to test the endpoints that are built using the Flask-Appbuilder. We will run these tests using PyTest.
def test_v1_songs(client): resp = client.get("/api/v1/songs/", follow_redirects=True) #import pdb;pdb.set_trace() assert 200 == resp.status_code def test_v1_add_song(client): """ The application can store the same data multiple times""" # Get the existing number of songs resp = client.get("/api/v1/songs/", follow_redirects=True) data = { "title": "Summer Days", "singer": "Martin Garrix" } resp = client.post( "/api/v1/songs/", data=data, follow_redirects=True ) assert 201 == resp.status_code
Flask-Appbuilder also helps in providing the Swagger UI to list and try the published API. Open config.py and update it with the configuration shown below.
FAB_API_SWAGGER_UI=True
Now navigate to the https://localhost:8080/swaggerview/v1 and you will be able to see the Swagger view as shown below.
Now let’s create APIs for the existing database models that we have. We need to use the ModelApi of the Flask-Appbuilder.
Update the api.py file with the following lines of code.
from flask_appbuilder.models.sqla.interface import SQLAInterface from flask_appbuilder.api import ModelRestApi from .models import Song as SongModel class MySongModelApi(ModelRestApi): resource_name = 'newsongs' datamodel = SQLAInterface(SongModel) appbuilder.add_api(MySongModelApi)
After defining a class based on ModelRestApi, we again need to register it with the Flask-Appbuilder using the method add_api.
Now navigate to the Swagger UI as earlier, and you will see an API reference similar to the one shown below.
You can try out the API from the Swagger view or by sending the curl to the endpoints as earlier.
Flask API
Flask API is a framework that is quite similar to the Django REST framework. You can access Flask API documentation here. It is the drop-in replacement for the Flask framework.
We can choose any of the above-given examples to implement the Flask REST API driven features in our application.
Now let’s commit the source and publish the changes to the origin repo using Git. As soon as we commit to the origin with the branch name and send a pull request, the unit tests will automatically trigger under the Git Actions as a part of the pull request checks.
Flask RestPlus
Flask RestPlus is one more Flask extension that helps in the creation of REST API using Flask. This project has been forked into another extension called Flask-RESTX and is no longer maintained.
This project has a good collection of decorators to describe the APIs and exposes its documentation using Swagger. You can check the details of this project here.
Frequently Asked Questions
Q #1) How do I create a REST API with Flask?
Answer: We can use the Flask framework with other Flask extensions such as Flask-RESTful, Flask API, Flask RESTX, Connexion, etc. to create REST API based web applications. Most of the extensions work with the other builtin features of the Flask framework and any other existing ORM/libraries.
Q #2) What is a REST API example?
Answer: An example application that implements RESTFul API is given in this tutorial. Flask-RESTful has been used to create the sample application. Read about the Flask RESTful example section in this tutorial.
Q #3) What is RESTful API for?
Answer: An Application Programming Interface that generally uses HTTP requests and has corresponding backend methods for HTTP verbs such as GET, POST, PUT, etc. to allow communication between Client and Server is called a RESTful API.
Such an application follows REST architecture principles and constraints to implement its features.
Conclusion
We covered the concepts of Flask extensions with the help of three extensions, such as Flask-twitter-oembedder, Flask API, and Flask-RESTful.
With the help of the Flask-twitter-oembedder, we covered the concepts of Twitter API too. In general, we have also included the ideas of implementing a RESTful web service, that follows the REST architecture principles and constraints.
In our next tutorial, we will cover the comparison between Django and Flask framework to help our readers understand the strengths and weaknesses of both the frameworks. It will also help in choosing one framework against the other based on the particular project requirements.
=> Explore The Simple Flask Training Series Here