Getting started with RESTful APIs using the Flask microframework for Python
In this tutorial we are going to learn how to create a simple REST API using Flask Python and SQL Alchemy. A good RESTful API structure imples the logical segmentation from the Models and the Data, but for this tutorial purpose we will create everything on the same file. One other thing that we will be using is a virtual environment because we can have a clean and isolated environment that doesn’t depend/share on other virtual environments' libraries and doesn’t access global installed libraries on your system.
Let’s get started then:
Mac OS X:
$ sudo easy_install virtualenv
$ sudo pip install virtualenv
$ sudo apt-get install python-virtualenv
Super!! Let’s move on and create our project folder:
$ mkdir ratings $ cd ratings
Now we just need to set up a new virtual environment:
You can choose another name for the environment instead of “venv”, this is just for demonstration purpose.
$ virtualenv venv
To start the above environment we just need to run the following command:
$ . venv/bin/activate
In our venv we will first install Flask framework:
(venv) ratings $ pip install Flask
And next we will install Flask-SQLAlchemy:
(venv) ratings $ pip install Flask-SQLAlchemy
Before we go any further we will have to do two things:
- Create a database called rating with one table called produts with two columns an INT rate and a VARCHAR name;
- Create a file on the project directory called rating_db.conf which will contain the database configuration:
[DB] user: root password: root db: rating host: 127.0.0.1
You have to enter your database data configuration, this is just an example for the tutorial.
For more information about Flask-SQLAlchemy you read it here: http://flask-sqlalchemy.pocoo.org/2.1/
Basic code configurations:
On the same directory as the rating_db.conf, let’s now create a python file rating.py. Now open it with your favorite editor or IDE and create this basic Flask Python structure:
from flask import Flask application = Flask(__name__) @application.route("/") def hello(): return "Hello World!" if __name__ == "__main__": application.run()
What does all this mean?!
The @application.route(“/”) defines a new route, which is translated as an url provided from the browser for example.
The def hello() is the function that will answer to that route.
What happens in the end? Well, everytime we hit the root of our project we will get a Hello World!.
Let's run a Simple HTTP Server to initialize our application and see this in action:
(venv) ratings $ python rating.py
If now hit the address created by the above command on your browser you will get the "Hello World!".
See! Easy! Congrats, you managed to create your first endpoint!
Now let's get back to the real deal!
This may seem confusing, but it's not. What we are doing here is nothing more than saying to the app where is our database configuration and establishing a new connection through the data provided in the file.
We are also mapping our table of products as a model in the code. We should separate the database model into a configuration file like I've mentioned before, but for this tutorial purpose we are going to map it directly on our file.
import ConfigParser from flask.ext.sqlalchemy import SQLAlchemy from flask import Flask, jsonify, request application = Flask(__name__) # Read config file config = ConfigParser.ConfigParser() config.read('rating_db.conf') # MySQL configurations application.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://' + config.get('DB', 'user') + \ ':' + config.get('DB', 'password') + '@' + \ config.get('DB', 'host') + '/' + config.get('DB', 'db') application.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True mysql = SQLAlchemy() # map models class Products(mysql.Model): __tablename__ = 'products' id = mysql.Column(mysql.Integer, primary_key=True) rate = mysql.Column(mysql.Integer, nullable=False) name = mysql.Column(mysql.String(128), nullable=False) def __repr__(self): return '<Products (%s, %s) >' % (self.rate, self.name) @application.route("/") def hello(): return "Hello World!" if __name__ == "__main__": application.run()
Before starting to code, if you want to know more about how flask endpoints structure work you can do it right here: http://flask.pocoo.org/docs/0.10/quickstart/
Alright, now we have the basics to start building a simple RESTful API. In this tutorial we will be doing a basic CRUD.
Let's add the new routes just bellow this
@application.route("/") def hello(): return "Hello World!"
Like the title suggests, we are going to create a new product in our table of products using a POST method:
@application.route('/product', methods=['POST']) def createProduct(): # fetch name and rate from the request rate = request.get_json()["rate"] name = request.get_json()["name"] product = Products(rate=rate, name=name) #prepare query statement curr_session = mysql.session #open database session try: curr_session.add(product) #add prepared statment to opened session curr_session.commit() #commit changes except: curr_session.rollback() curr_session.flush() # for resetting non-commited .add() productId = product.id #fetch last inserted id data = Products.query.filter_by(id=productId).first() #fetch our inserted product config.read('rating_db.conf') result = [data.name, data.rate] #prepare visual data return jsonify(session=result)
Fetches all data using a request method GET.
@application.route('/product', methods=['GET']) def getProduct(): data = Products.query.all() #fetch all products on the table data_all =  for product in data: data_all.append([product.id, product.name, product.rate]) #prepare visual data return jsonify(products=data_all)
This function basically fetches all the data in our table of products into an array "data_all" which later will be iterated in order to display all our products for the user to see.
Why patch instead of put? Well since we are updating an existing product we should always use a PATCH method, as the PUT method is used for replacing a resource in it's entirety.
<int:productId> means we are expecting to receive a dynamic argument in the url.
@application.route('/<int:productId>/product', methods=['PATCH']) def updateProduct(productId): rate = request.get_json()["rate"] #fetch rate curr_session = mysql.session try: product = Products.query.filter_by(id=productId).first() #fetch the product do be updated product.rate = rate #update the column rate with the info fetched from the request curr_session.commit() #commit changes except: curr_session.rollback() curr_session.flush() productId = product.id data = Products.query.filter_by(id=productId).first() #fetch our updated product config.read('rating_db.conf') result = [data.name, data.rate] #prepare visual data return jsonify(session=result)
This is a very simple function. We get and id of a product, we delete it. How?!
@application.route('/product/<int:productId>', methods=['DELETE']) def deleteProduct(productId): curr_session = mysql.session #initiate database session Products.query.filter_by(id=productId).delete() #find the product by productId and deletes it curr_session.commit() #commit changes to the database return getProduct() #return all create products
More concrete, we get the productId from the url (int:productId) that belongs to a product in our table, pass the productId to our function, find the product and delete it. Thats it!
In the end we call the function "getProduct()" and display the remaining products for the user to see.
You can use postman or DHC to simulate the requests and see your API working.
If you want to know more about HTTP methods check this link: http://www.restapitutorial.com/lessons/httpmethods.html