What is REST
REST (Representational State Transfer) is an architecture style for designing networked applications. The idea is using simple HTTP methods for making calls between machines rather than complex mechanisms such as CORBA, RPC or SOAP.
So a RESTful system typically communicates over the Hypertext Transfer Protocol with the same HTTP verbs (GET, POST, PUT, DELETE, etc.)
Flask and Flask-RESTful
Flask is a microframework for Python based on Werkzeug, Jinja2. Flask-RESTful provides an extension to Flask for building REST APIs.
Installing packages
For the api, we need to install some packages like Flask-Restful, pymongo etc. It's good practice to install packages and modules for a project in a virtual environment. So i am going to create a virtual environment and activate it.
$ virtualenv env
$ source env/bin/activate
Now the required packages can be installed using pip. (Link: requirements.txt)
$ pip install -r requirements.txt
Api
Lets Code the API first.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
from flask import Flask, jsonify, url_for, redirect, request | |
from flask_pymongo import PyMongo | |
from flask_restful import Api, Resource | |
app = Flask(__name__) | |
app.config["MONGO_DBNAME"] = "students_db" | |
mongo = PyMongo(app, config_prefix='MONGO') | |
APP_URL = "http://127.0.0.1:5000" | |
class Student(Resource): | |
def get(self, registration=None, department=None): | |
data = [] | |
if registration: | |
studnet_info = mongo.db.student.find_one({"registration": registration}, {"_id": 0}) | |
if studnet_info: | |
return jsonify({"status": "ok", "data": studnet_info}) | |
else: | |
return {"response": "no student found for {}".format(registration)} | |
elif department: | |
cursor = mongo.db.student.find({"department": department}, {"_id": 0}).limit(10) | |
for student in cursor: | |
student['url'] = APP_URL + url_for('students') + "/" + student.get('registration') | |
data.append(student) | |
return jsonify({"department": department, "response": data}) | |
else: | |
cursor = mongo.db.student.find({}, {"_id": 0, "update_time": 0}).limit(10) | |
for student in cursor: | |
print student | |
student['url'] = APP_URL + url_for('students') + "/" + student.get('registration') | |
data.append(student) | |
return jsonify({"response": data}) | |
def post(self): | |
data = request.get_json() | |
if not data: | |
data = {"response": "ERROR"} | |
return jsonify(data) | |
else: | |
registration = data.get('registration') | |
if registration: | |
if mongo.db.student.find_one({"registration": registration}): | |
return {"response": "student already exists."} | |
else: | |
mongo.db.student.insert(data) | |
else: | |
return {"response": "registration number missing"} | |
return redirect(url_for("students")) | |
def put(self, registration): | |
data = request.get_json() | |
mongo.db.student.update({'registration': registration}, {'$set': data}) | |
return redirect(url_for("students")) | |
def delete(self, registration): | |
mongo.db.student.remove({'registration': registration}) | |
return redirect(url_for("students")) | |
class Index(Resource): | |
def get(self): | |
return redirect(url_for("students")) | |
api = Api(app) | |
api.add_resource(Index, "/", endpoint="index") | |
api.add_resource(Student, "/api", endpoint="students") | |
api.add_resource(Student, "/api/<string:registration>", endpoint="registration") | |
api.add_resource(Student, "/api/department/<string:department>", endpoint="department") | |
if __name__ == "__main__": | |
app.run(debug=True) |
This is a basic api with only one Resource Student. First we created an instance of Flask,
app = Flask(__name__)
after that we configured app with MongoDB.
The resource Student has HTTP methods defined in it as it's own method. By calling different HTTP methods we can perform basic CRUD operations. Like post for inserting/creating, put for updating, get for reading and delete for deleting a document.
In the code post, put, delete methods are basic. These methods perform create, update and delete operation on the collection student.
But in the get method, by calling different url we can perform different operations. If no parameter passed with url, the method will return all the documents in the collection. If a registration number passed with the url then, it will check the parameter name and will return one document. If request is made in /api/department/<string:department> url, it will check for parameter name department in the get method and returns all the documents for a particular department.
There are several urls for same resource so we added different endpoints for them.
Testing the Api
We will use python requests module (version > 2.4.2) for testing the api. But also curl and other mechanism can be used. For get request we can view the data in browsers also.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
In [1]: from requests import get, post, put, delete | |
In [2]: get("http://127.0.0.1:5000/api") | |
In [3]: data = {"name": "Example Name", "registration": "123433199", "department": "cse"} | |
In [4]: post("http://127.0.0.1:5000/api", json=data).json() | |
In [5]: put("http://127.0.0.1:5000/api/123433199", json={"website": "www.example.com"}).json() | |
In [6]: delete("http://127.0.0.1:5000/api/123433199").json() |
requests module gives us convenient way to test our api. Enough REST. Lets take some rest ;)