Flask restless
-
Upload
michael-andrew-shaw -
Category
Technology
-
view
248 -
download
1
Transcript of Flask restless
FLASK RESTLESSFAST AND EASY REST API’S
Code SamplesGithub
https://github.com/mandshaw/flask_microbrewery
What is Flask RestlessLibrary built around flask
Model driven
Define your models
Define their relationships
Expose your models
Specify what to expose them on (GET, POST, PUT, DELETE
What is Flask Restless
Uses SQLAlchemy
Supports SQLite, Postgresql, MySQL, Oracle and many more
Built in query language (FOR FREE!)
Models
What is a model?
Comes from SQLAlchemy or Flask-SQLAlchemy
Used to represent objects which will become records in a database
Flask-SQLAlchemy
Abstracts away a lot of unnecessary SQLAlchemy config and makes your life easier.
Read more here
Defining a Model# Define the modelsclass Beer(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.Unicode, unique=True)
Will execute:
CREATE TABLE beer (
id INTEGER NOT NULL,
name VARCHAR,
PRIMARY KEY (id),
UNIQUE (name),
)
Turning a Model into a API
# Create the DBdb.create_all()# Create the Flask-Restless API manager.manager = APIManager(app, flask_sqlalchemy_db=db)# Create the API endpoints from the DB Models# These will be available at /api/<tablename>manager.create_api(Beer, methods=['GET', 'POST', 'PUT', 'DELETE'])
DEMO STEP/1
Relationships
Creating a one to many Relationship
Relationship always goes on the ‘one’ side # Define the modelsclass Beer(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.Unicode, unique=True) # Create a foreign key type_id = db.Column(db.Integer, db.ForeignKey(‘type.id’)) class Type(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.Unicode, unique=True) # Create a relationship beers = db.relationship('Beer', backref=db.backref('type'), lazy=‘dynamic')
DEMO STEP/2
Making Fields Invisible
Excluding Columns
You can use exclude_columns or include_columns to hide columns in the response
manager.create_api(Beer, methods=['GET', 'POST', 'PUT', 'DELETE'], exclude_columns=['reviews', 'type'])
DEMO STEP/3
Pre and Post Processing
Consider
On a POST or PUT for a review you want to add the date that the review was created
Do you?
Do this client side (What time zone? What format)
Do this server side
Processors# Augments the request with the current db DATETIMESTAMP # When submitted def add_current_date(**kw): kw['data']['date'] = 'CURRENT_TIMESTAMP' return kw # Create the API endpoints from the DB Models# These will be available at /api/<tablename> manager.create_api( Review, methods=['GET', 'POST', 'PUT', 'DELETE'], preprocessors = { 'POST': [add_current_date], 'PUT_SINGLE': [add_current_date] })
Processors
Preprocessors -> before the requests is processed
Postprocessors -> before the response is returned
DEMO STEP/4
Validation
Validation
Not performed by Flask-Restless
Roll your own or use a combination of the SQLAlchemy validate decorator and flasks abort
Validationfrom flask import Flask, abort from sqlalchemy.orm import validates
class Review(db.Model): id = db.Column(db.Integer, primary_key=True) date = db.Column(db.DateTime) stars = db.Column(db.Integer) comment = db.Column(db.Unicode) beer_id = db.Column(db.Integer, db.ForeignKey('beer.id')) author_id = db.Column(db.Integer, db.ForeignKey('reviewer.id')) @validates('stars') def validate_name(self, key, stars): if stars >= 1 and stars <=5: return stars else: return abort(400, description='A review must have a star rating of between 1 and 5')
Pagination
Server side Pagination
Natively uses server side pagination (default is 10 results per page)
<host>/api/<resource>?page=2 Give you page 2
Set the results_per_page attribute when creating your api to over-ride
manager.create_api(Reviewer, methods=['GET', 'POST', 'PUT', 'DELETE'], results_per_page=2)
Querying data
NULL is the Chuck Norris of the database. Nothing can be compared to it. - Unknown
Querying Data
Support query params on GETS
Uses Query Filters
<host>/api/<resource>/?q={“filter”:[…filters…]}
Query FiltersLists of
{“name”: name, “op”: op, “val”: val}
{“name”: name, “op”: op, “field”: field}
name The field to use
op The operator to use
val The Value to use
field The field to compare name to
Valid Operatorsequal ==, eq, equals, equals_to
not equal !=, neq, does_not_equal, not_equal_to
comparison >, gt, <, lt, >=, ge, gte, geq, <=, le, lte, leq
membership in, not_in
null check is_null, is_not_null
like like
has has
any any
Querying Data
Extremely feature rich
Order by
Group By
Single result expected
READ THE DOCS
ExamplesGet all the Hipsters
GET localhost:5000/api/reviewer?q={"filters":[{"name":"name","op": "ilike", "val":"Hipster%"}]}
Reviews with more than 3 stars
GET localhost:5000/api/review?q={"filters":[{"name":"stars","op": "gt", "val":3}]}
All reviews made by Hipster Jane
GET localhost:5000/api/review?q={"filters":[{"name":"author","op":"has","val":{"name":"name", "op":"eq", "val":"Hipster Jane”}}]}
Examples
You can also use relationships in a GET
All reviews made by Hipster Jane(id=2)
GET localhost:5000/api/reviewer/2/reviews
Further Reading
You can use SQLAlchemy migrate to migrate you DB revisions
Read all about it (and lots more) here
QUESTIONS?