Flask & RESTful services
@marjaimate - PyLadies Apr 2016
We help forging your software, product and company
Assumptions
-
You heard about Python
-
You know what a web service is
- You don't know anything about Flask
- You don't know what a RESTful service is
Python Web Frameworks
Django, Web2Py, Pylons all known fully fledged frameworks.
There are a lot more than these standout options. You can also write your own if you have spare time!
Flask - Micro framework
It's a lightweight and extensible framework for building web applications, let it be backend APIs, blogs, micro services, etc.
Flask - Micro framework
# pies.py
from flask import Flask
app = Flask(__name__)
@app.route("/", methods=["GET"])
def pies():
return "cherry, steak & kidney, fisherman's"
@app.route('/pies/<pie>', methods=["GET"])
def get_pie(pie):
return 'Pie: %s' % pie
if __name__ == "__main__":
app.run()
Flask - Micro framework
Supports packages / plugins for:
- Various database adapters (SQLAlchemy, CouchDB, etc.)
- Templating languages (DTL, WTForms)
- RPC-like APIs (XML-RPC, JSON-RPC)
- Themes
- Uploads
- ...
Flask - Routing
@app.route('/user/<username>')
def show_user_profile(username):
# show the user profile for that user
return 'User %s' % username
@app.route('/post/<int:post_id>')
def show_post(post_id):
# show the post with the given id, the id is an integer
return 'Post %d' % post_id
# Using HTTP verbs
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
do_the_login()
else:
show_the_login_form()
Flask - Request
from flask import request
# ...
@app.route('/login', methods=['POST', 'GET'])
def login():
error = None
if request.method == 'POST':
if valid_login(request.form['username'],
request.form['password']):
return log_the_user_in(request.form['username'])
else:
error = 'Invalid username/password'
# the code below is executed if the request method
# was GET or the credentials were invalid
return render_template('login.html', error=error)
Flask - Error handling
# 401 unauthorized
@app.route('/login')
def login():
abort(401)
this_is_never_executed()
# 404 not found
from flask import render_template
@app.errorhandler(404)
def page_not_found(error):
return render_template('page_not_found.html'), 404
RESTful services
What is REST?
Representational State
Transfer
What is REST?
- Using HTTP verbs: GET, POST, PUT, PATCH, DELETE, etc.
- Each action corresponds to a CRUD action
- A (mostly) deterministic interface between web systems
REST example
HTTP Status | URI | Description |
---|---|---|
GET | /cats | List the herd of cats |
POST | /cats | Create a new cat, add to the collection |
GET | /cats/:name | Retrieve a cat's details |
PUT / PATCH | /cats/:name | Update or create a cat's details |
DELETE | /cats/:name | Delete the cat :( |
Flask-RESTful
Flask-RESTful is an extension for Flask that adds support for quickly building REST APIs.
Initially built by Twilio
Flask-RESTful
from flask import Flask, request
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
cats = {}
class CatSimple(Resource):
def get(self, cat_id):
return {cat_id: cats[cat_id]}
def put(self, cat_id):
cats[cat_id] = request.form['data']
return {cat_id: cats[cat_id]}
api.add_resource(CatSimple, '/<string:cat_id>')
if __name__ == '__main__':
app.run(debug=True)
Arguments parsing
from flask_restful import reqparse
parser = reqparse.RequestParser()
parser.add_argument('rate', type=int, help='Rate to charge for this resource')
args = parser.parse_args()
# Required arguments
parser.add_argument('name', required=True, help="Name cannot be blank!")
# Param rewrite
parser.add_argument('name', dest='public_name')
# If an argument fails to pass validation, Flask-RESTful will respond
# with a 400 Bad Request and a response highlighting the error.
# Strict mode is optional
args = parser.parse_args(strict=True)
Routing your resources
# Mount resource routes to the api object
api.add_resource(TodoSimple, '/<string:todo_id>')
# Multiple routes allowed for the same resource
api.add_resource(
CatList,
'/',
'/cats'
)
# Use the routes for dependency injection
class TodoNext(Resource):
def __init__(**kwargs):
# smart_engine is a black box dependency
self.smart_engine = kwargs['smart_engine']
# ...
smart_engine = SmartEngine()
api.add_resource(TodoNext, '/next', resource_class_kwargs={ 'smart_engine': smart_engine })
Let's do some coding
Flask & REST
By Máté Marjai
Flask & REST
Creating Flask and RESTful services - talk for PyLadies Dublin Apr 2016
- 1,025