SlideShare a Scribd company logo
REST APIREST API
USING FLASK & SQLALCHEMYUSING FLASK & SQLALCHEMY
Alessandro Cucci
Python Developer, Energee3
REPRESENTATIONAL STATE TRANSFERREPRESENTATIONAL STATE TRANSFER
ROY THOMAS FIELDING - 2010ROY THOMAS FIELDING - 2010
HTTP://WWW.ICS.UCI.EDU/~FIELDING/PUBS/DISSERTATION/REST_ARCH_STYLE.HTMHTTP://WWW.ICS.UCI.EDU/~FIELDING/PUBS/DISSERTATION/REST_ARCH_STYLE.HTM
RESTREST
GUIDING CONSTRAINTSGUIDING CONSTRAINTS
CLIENT-SERVERCLIENT-SERVER
STATELESSSTATELESS
CACHEABLECACHEABLE
LAYERED SYSTEMLAYERED SYSTEM
CODE ON DEMAND (OPTIONAL)CODE ON DEMAND (OPTIONAL)
RESTREST
GUIDING CONSTRAINTSGUIDING CONSTRAINTS
UNIFORM INTERFACEUNIFORM INTERFACE
IDENTIFICATION OF RESOURCESIDENTIFICATION OF RESOURCES
MANIPULATION OF RESOURCES THROUGH REPRESENTATIONSMANIPULATION OF RESOURCES THROUGH REPRESENTATIONS
SELF-DESCRIPTIVE MESSAGESSELF-DESCRIPTIVE MESSAGES
HYPERMEDIA AS THE ENGINE OF APPLICATION STATEHYPERMEDIA AS THE ENGINE OF APPLICATION STATE
REST URI EXAMPLESREST URI EXAMPLES
h�p://myapi.com/customers
h�p://myapi.com/customers/33245
REST ANTI-PATTERNSREST ANTI-PATTERNS
h�p://myapi.com/update_customer&id=12345&
format=json
h�p://myapi.com/customers/12345/update
RELATIONSHIP BETWEEN URL AND HTTPRELATIONSHIP BETWEEN URL AND HTTP
METHODSMETHODS
URL GET PUT POST DELETE
h�p://api.myvinylcollec�on.com
/records/
LIST of records in
collec�on
Method not
allowed.
CREATE a
new entry in
the
collec�on.
DELETE the
en�re
collec�on.
h�p://api.myvinylcollec�on.com
/records/1
RETRIEVE a
representa�on of
the addressed
member of the
collec�on
REPLACE
the
addressed
member of
the
collec�on.
Method not
allowed.
DELETE the
addressed
member of
the
collec�on.
WHAT DO WE NOT CARE FOR THIS EVENINGWHAT DO WE NOT CARE FOR THIS EVENING
Stability & Tes�ng
Long-Term maintainability
Edge Cases
Opera�ons, Caching & Deployment
MY VINYL COLLECTION APIMY VINYL COLLECTION API
HTTP://FLASK.POCOO.ORG/HTTP://FLASK.POCOO.ORG/
HELLO API!HELLO API!
from flask import Flask
app = Flask(__name__)
if __name__ == '__main__':
app.run()
$ python myvinylcollectionapi.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Rest API using Flask & SqlAlchemy
HELLO API!HELLO API!
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello PyRE!"
if __name__ == '__main__':
app.run()
HELLO API!HELLO API!
from flask import Flask, jsonify
app = Flask(__name__)
@app.route("/")
def hello():
return jsonify(data="Hello PyRE!")
if __name__ == '__main__':
app.run()
HTTP GET METHODSHTTP GET METHODS
URL GET
h�p://api.myvinylcollec�on.com
/records
LIST of records in
collec�on
h�p://api.myvinylcollec�on.com
/records/1
RETRIEVE a
representa�on of the
addressed member of
the collec�on
from flask import Flask, jsonify, abort
app = Flask(__name__)
RECORDS = [
{
'id': 0,
'artist': "Queen",
'title': "A Night At The Opera",
'year': "1975",
'label': "EMI"
},
{
'id': 1,
'artist': "Pink Floyd",
'title': "The Dark Side Of The Moon",
'year': "1989",
'label': "EMI"
},
...
]
@app.route("/records")
def get_records():
return jsonify(RECORDS)
@app.route("/records/<int:index>")
def get_record(index):
try:
record = RECORDS[index]
except IndexError:
abort(404)
return jsonify(record)
if __name__ == '__main__':
app.run()
HTTP GET METHODHTTP GET METHOD
$ curl -X GET localhost:5000/records
[
{
"artist": "Queen",
"id": 0,
"label": "EMI",
"title": "A Night At The Opera",
"year": "1975"
},
{
"artist": "Pink Floyd",
"id": 1,
"label": "EMI",
"title": "The Dark Side Of The Moon",
"year": "1989"
}
]
HTTP GET Method
$ curl -X GET localhost:5000/records/1
{
"artist": "Pink Floyd",
"id": 1,
"label": "EMI",
"title": "The Dark Side Of The Moon",
"year": "1989"
}
$ curl -X GET localhost:5000/records/5
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server.
If you entered the URL manually please check
your spelling and try again.</p>
JSONIFY THAT ERROR!JSONIFY THAT ERROR!
@app.errorhandler(404)
def page_not_found(error):
return jsonify(
error="Not Found",
status_code=404
), 404
$ curl -X GET localhost:5000/records/5
{
"error": "Not Found",
"status_code": 404
}
GOOD NEWS:GOOD NEWS:
IT WORKS!IT WORKS!
BAD NEWS:BAD NEWS:
STATIC DATASTATIC DATA
SEPARATION OF CONCERNSSEPARATION OF CONCERNS
SQLITESQLITE + DISCOGS.COM+ DISCOGS.COM + PANDAS+ PANDAS
CREATE TABLE "collection" (
`index` INTEGER PRIMARY KEY AUTOINCREMENT,
`Catalog#` TEXT,
`Artist` TEXT,
`Title` TEXT,
`Label` TEXT,
`Format` TEXT,
`Rating` REAL,
`Released` INTEGER,
`release_id` INTEGER,
`CollectionFolder` TEXT,
`Date Added` TEXT,
`Collection Media Condition` TEXT,
`Collection Sleeve Condition` TEXT,
`Collection Notes` REAL
)
CSV COLLECTION EXPORTCSV COLLECTION EXPORT
import pandas
import sqlite3
conn = sqlite3.connect('record_collection.db')
conn.text_factory = sqlite3.Binary
df = pandas.read_csv('collection.csv')
df.to_sql('collection', conn)
Rest API using Flask & SqlAlchemy
OBJECT RELATIONAL MAPPER (ORM)OBJECT RELATIONAL MAPPER (ORM)
HTTP://DOCS.SQLALCHEMY.ORGHTTP://DOCS.SQLALCHEMY.ORG
MODEL.PYMODEL.PY
from flask_sqlalchemy import SQLAlchemy
from flask_sqlalchemy import orm
db = SQLAlchemy()
class Record(db.Model):
__tablename__ = "collection"
index = db.Column(db.Integer, primary_key=True)
Artist = db.Column(db.Text, nullable=False)
Title = db.Column(db.Text, nullable=False)
Label = db.Column(db.Text)
Released = db.Column(db.Text)
def as_dict(self):
columns = orm.class_mapper(self.__class__).mapped_table.c
return {
col.name: getattr(self, col.name)
for col in columns
}
QUERYQUERY
>>> # .all() return a list
>>> all_records = Record.query.all()
>>> len(all_records)
80
>>> # .first() return the first item that matches
>>> record = Record.query.filter(Record.index == 9).first()
>>> record.Title
"Back In Black"
>>> record.Artist
"AC/DC"
>>> record.Released
"1980"
>>> # .filter_by() is a shortcut
>>> record = Record.query.filter_by(index == 6).first()
>>> record.Title
"Hotel California"
from flask import Flask, jsonify
from model import db, Record
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///record_collection.db"
db.init_app(app)
@app.route("/records")
def get_records():
records = [r.as_dict() for r in Record.query.all()]
return jsonify(records)
@app.route("/records/<int:index>")
def get_record(index):
record = Record.query.filter(Record.index == index).first_or_404()
return jsonify(record.as_dict())
$ curl -X GET localhost:5000/records
[
{
"Artist": "The Police",
"index": 0,
"Title": "Reggatta De Blanc"
},
{
"Artist": "The Beatles",
"index": 1,
"Title": "Abbey Road"
},
...
]
$ curl -X GET localhost:5000/records/1
{
"Artist": "The Beatles",
"index": 1,
"Title": "Abbey Road"
}
HTTP POST METHODSHTTP POST METHODS
URL POST
h�p://api.myvinylcollec�on.com
/records/
CREATE a new
entry in the
collec�on.
h�p://api.myvinylcollec�on.com
/records/1
Method not
allowed.
POST ON LOCALHOST:5000/RECORDS/IDPOST ON LOCALHOST:5000/RECORDS/ID
@app.errorhandler(405)
def method_not_allowed(error):
return jsonify(
error="Method Not Allowed",
status_code=405
), 405
from flask import Flask, jsonify, abort, request
...
@app.route("/records/<int:index>", methods=['GET', 'POST'])
def get_record(index):
if request.method == 'POST':
abort(405)
record = Record.query.filter(Record.index == index).first_or_404()
return jsonify(record.as_dict())
$ curl -X POST localhost:5000/records/1
{
"error": "Method Not Allowed",
"status_code": 405
}
INSERT INTO DATABASEINSERT INTO DATABASE
>>> # .add() insert a record
>>> db.session.add(record)
>>> # changes won't be saved until committed!
>>> db.session.commit()
ADDING A RECORD TO MY COLLECTIONADDING A RECORD TO MY COLLECTION
@app.route("/records", methods=['GET', 'POST'])
def get_records():
if request.method == 'POST':
record = Record(**json.loads(request.data))
db.session.add(record)
db.session.commit()
return jsonify(record.as_dict()), 201
records = [r.as_dict() for r in Record.query.all()]
return jsonify(records)
ADDING A RECORD TO MY COLLECTIONADDING A RECORD TO MY COLLECTION
$ curl -i -H "Content-Type: application/json" -X POST localhost:5000/records 
> -d '{"Artist":"Neil Joung", "Title":"Harvest", 
> "Label":"Reprise Records", "Released":"1977"}'
HTTP/1.0 201 CREATED
Content-Type: application/json
Content-Length: 104
Server: Werkzeug/0.11.11 Python/2.7.12+
Date: Sat, 03 Dec 2016 11:03:10 GMT
{
"Artist": "Neil Young",
"Label": "Reprise Records",
"Released": "1977",
"Title": "American Stars 'N Bars",
"index": 91
}
HTTP PUT METHODSHTTP PUT METHODS
URL PUT
h�p://api.myvinylcollec�on.com
/records/
Method not allowed.
h�p://api.myvinylcollec�on.com
/records/1
REPLACE the
addressed member
of the collec�on.
@app.route("/records", methods=['GET', 'POST', 'PUT'])
def get_records():
if request.method == 'POST':
record = Record(**json.loads(request.data))
db.session.add(record)
db.session.commit()
return jsonify(record.as_dict()), 201
elif request.method == 'PUT':
abort(405)
records = [r.as_dict() for r in Record.query.all()]
return jsonify(records), 200
@app.route("/records/<int:index>", methods=['GET', 'POST', 'PUT'])
def get_record(index):
if request.method == 'POST':
abort(405)
else:
record = Record.query.filter(Record.index == index).first_or_404()
if request.method == 'PUT':
for k, v in json.loads(request.data).iteritems():
setattr(record, k, v)
db.session.add(record)
db.session.commit()
return jsonify(record.as_dict()), 200
PUT ON COLLECTIONPUT ON COLLECTION
$ curl -i -H "Content-Type: application/json" 
> -X POST localhost:5000/records 
> -d '{"Artist":"Neil Joung", "Title":"Harvest", 
> "Label":"Reprise Records", "Released":"1977"}'
HTTP/1.0 405 METHOD NOT ALLOWED
Content-Type: application/json
Content-Length: 59
Server: Werkzeug/0.11.11 Python/2.7.12+
Date: Sat, 03 Dec 2016 10:20:06 GMT
{
"error": "Method Not Allowed",
"status_code": 405
}
PUT ON RESOURCEPUT ON RESOURCE
$ curl -i -H "Content-Type: application/json" 
> -X PUT localhost:5000/records/91 
> -d '{"Artist":"Neil Joung", "Title":"Harvest", 
> "Label":"Reprise Records", "Released":"1977"}'
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 104
Server: Werkzeug/0.11.11 Python/2.7.12+
Date: Sat, 03 Dec 2016 11:07:22 GMT
{
"Artist": "Neil Young",
"Label": "Reprise Records",
"Released": "1977",
"Title": "American Stars 'N Bars",
"index": 91
}
HTTP DELETE METHODSHTTP DELETE METHODS
URL DELETE
h�p://api.myvinylcollec�on.com
/records/
DELETE the en�re
collec�on.
h�p://api.myvinylcollec�on.com
/records/1
DELETE the
addressed member
of the collec�on.
DELETE ON COLLECTIONDELETE ON COLLECTION
@app.route("/records", methods=['GET', 'POST', 'PUT', 'DELETE'])
def get_records():
if request.method == 'POST':
record = Record(**json.loads(request.data))
db.session.add(record)
db.session.commit()
return jsonify(record.as_dict()), 201
elif request.method == 'PUT':
abort(405)
records = [r.as_dict() for r in Record.query.all()]
if request.method == 'DELETE':
for r in records:
db.session.delete(r)
db.session.commit()
records = [r.as_dict() for r in Record.query.all()]
return jsonify(records), 200
DELETE ON RESOURCEDELETE ON RESOURCE
@app.route("/records/<int:index>", methods=['GET', 'POST', 'PUT', 'DELETE'])
def get_record(index):
if request.method == 'POST':
abort(405)
else:
record = Record.query.filter(Record.index == index).first_or_404()
if request.method == 'PUT':
for k, v in json.loads(request.data).iteritems():
setattr(record, k, v)
db.session.add(record)
db.session.commit()
elif request.method == 'DELETE':
db.session.delete(record)
db.session.commit()
return jsonify(record.as_dict()), 200
DELETE ON RESOURCEDELETE ON RESOURCE
$ curl -i -X DELETE localhost:5000/records/91
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 104
Server: Werkzeug/0.11.11 Python/2.7.12+
Date: Sat, 03 Dec 2016 10:40:00 GMT
{
"Artist": "Neil Young",
"Label": "Reprise Records",
"Released": "1977",
"Title": "American Stars 'N Bars",
"index": 91
}
DELETE ON RESOURCEDELETE ON RESOURCE
$ curl -i -X DELETE localhost:5000/records/91
HTTP/1.0 HTTP/1.0 404 NOT FOUND
Content-Type: application/json
Content-Length: 50
Server: Werkzeug/0.11.11 Python/2.7.12+
Date: Sat, 03 Dec 2016 10:40:09 GMT
{
"error": "Not Found",
"status_code": 404
}
DELETE ON COLLECTIONDELETE ON COLLECTION
$ curl -i -X DELETE localhost:5000/records
Rest API using Flask & SqlAlchemy
FLASK-LOGINFLASK-LOGIN
HTTPS://FLASK-LOGIN.READTHEDOCS.IOHTTPS://FLASK-LOGIN.READTHEDOCS.IO
PWD AUTHENTICATIONPWD AUTHENTICATION
from flask import Flask, jsonify, abort
from flask_login import LoginManager, current_user
app = Flask(__name__)
login_manager = LoginManager(app)
@login_manager.request_loader
def check_token(request):
token = request.headers.get('Authorization')
if token == 'L3T_M3_PA55!':
return "You_can_pass" # DON'T TRY THIS AT HOME!
return None
@app.route("/")
def get_main_root():
if current_user:
return jsonify(data='Hello Login'), 200
else:
abort(401)
HOW IT WORKSHOW IT WORKS
$ curl -i localhost:5000
HTTP/1.0 401 UNAUTHORIZED
Content-Type: application/json
WWW-Authenticate: Basic realm="Authentication Required"
Content-Length: 37
Server: Werkzeug/0.11.11 Python/2.7.12+
Date: Sat, 03 Dec 2016 14:46:55 GMT
{
"error": "Unauthorized access"
}
$ curl -i -H "Authorization: L3T_M3_PA55!" localhost:5000
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 28
Server: Werkzeug/0.11.11 Python/2.7.12+
Date: Sat, 03 Dec 2016 14:42:00 GMT
{
"data": "Hello Login"
}
SECURING OUR API - RESOURCESECURING OUR API - RESOURCE
@app.route("/records/<int:index>", methods=['GET', 'POST', 'PUT', 'DELETE'])
def get_record(index):
if request.method == 'POST':
abort(405)
else:
record = Record.query.filter(Record.index == index).first_or_404()
if request.method == 'PUT':
if current_user:
for k, v in json.loads(request.data).iteritems():
setattr(record, k, v)
db.session.add(record)
db.session.commit()
else:
abort(401)
elif request.method == 'DELETE':
if current_user:
db.session.delete(record)
db.session.commit()
else:
abort(401)
return jsonify(record.as_dict()), 200
SECURING OUR API - COLLECTIONSECURING OUR API - COLLECTION
@app.route("/records", methods=['GET', 'POST', 'PUT', 'DELETE'])
def get_records():
if request.method == 'POST':
record = Record(**json.loads(request.data))
db.session.add(record)
db.session.commit()
return jsonify(record.as_dict()), 201
elif request.method == 'PUT':
abort(405)
records = [r.as_dict() for r in Record.query.all()]
if request.method == 'DELETE':
if current_user:
for r in records:
db.session.delete(r)
db.session.commit()
records = [r.as_dict() for r in Record.query.all()]
return jsonify(records), 200
else:
abort(401)
return jsonify(records), 200
HOMEWORKSHOMEWORKS
Pagina�on with Flask-SqlAlchemy
Rate Limi�ng with Flask-Limiter
Cache with Flask-Cache
THANK YOU!THANK YOU!
{
'slides': 'www.alessandrocucci.it/pyre/restapi',
'code': 'https://goo.gl/4UOqEr'
}
Ad

Recommended

Basic Web Exploit Development
Basic Web Exploit Development
Riswanda N.S
 
Exercices : Algorithmes et Langage C
Exercices : Algorithmes et Langage C
Zakariyaa AIT ELMOUDEN
 
Function Pointer
Function Pointer
Dr-Dipali Meher
 
Structure in c
Structure in c
Prabhu Govind
 
Contoh store procedure dan function
Contoh store procedure dan function
Erwin Setiawan
 
Object oriented programming in python
Object oriented programming in python
baabtra.com - No. 1 supplier of quality freshers
 
What is Dictionary In Python? Python Dictionary Tutorial | Edureka
What is Dictionary In Python? Python Dictionary Tutorial | Edureka
Edureka!
 
Async await in C++
Async await in C++
cppfrug
 
Introducción a Scala
Introducción a Scala
Jose Emilio Labra Gayo
 
02. prak.-pemrograman-berorientasi-objek
02. prak.-pemrograman-berorientasi-objek
Jamil Jamil
 
Flask Basics
Flask Basics
Eueung Mulyana
 
Generators In Python
Generators In Python
Simplilearn
 
Python
Python
Sangita Panchal
 
Pertemuan 9 Proses Testing
Pertemuan 9 Proses Testing
Endang Retnoningsih
 
Python Functions Tutorial | Working With Functions In Python | Python Trainin...
Python Functions Tutorial | Working With Functions In Python | Python Trainin...
Edureka!
 
COURS_PYTHON_22.ppt
COURS_PYTHON_22.ppt
IbtissameAbbad1
 
Algoritma dan Struktur Data - Binary Search
Algoritma dan Struktur Data - Binary Search
KuliahKita
 
Php database connectivity
Php database connectivity
baabtra.com - No. 1 supplier of quality freshers
 
C++ string
C++ string
Dheenadayalan18
 
How to use Map() Filter() and Reduce() functions in Python | Edureka
How to use Map() Filter() and Reduce() functions in Python | Edureka
Edureka!
 
Pointers in C
Pointers in C
guestdc3f16
 
Jenis dan proses interupsi
Jenis dan proses interupsi
Vicky Setya Hermawan
 
PYthon
PYthon
Rajesh Tiwary
 
Chapitre 3 elements de base de java
Chapitre 3 elements de base de java
Amir Souissi
 
Dukungan implementasi
Dukungan implementasi
alimgunawan
 
External dependencies ,pre init hook &amp; post init hook in odoo
External dependencies ,pre init hook &amp; post init hook in odoo
Celine George
 
Initiation à ASP.NET 4.0
Initiation à ASP.NET 4.0
Jean-Baptiste Vigneron
 
F# for C# Programmers
F# for C# Programmers
Scott Wlaschin
 
Python RESTful webservices with Python: Flask and Django solutions
Python RESTful webservices with Python: Flask and Django solutions
Solution4Future
 
Build restful ap is with python and flask
Build restful ap is with python and flask
Jeetendra singh
 

More Related Content

What's hot (20)

Introducción a Scala
Introducción a Scala
Jose Emilio Labra Gayo
 
02. prak.-pemrograman-berorientasi-objek
02. prak.-pemrograman-berorientasi-objek
Jamil Jamil
 
Flask Basics
Flask Basics
Eueung Mulyana
 
Generators In Python
Generators In Python
Simplilearn
 
Python
Python
Sangita Panchal
 
Pertemuan 9 Proses Testing
Pertemuan 9 Proses Testing
Endang Retnoningsih
 
Python Functions Tutorial | Working With Functions In Python | Python Trainin...
Python Functions Tutorial | Working With Functions In Python | Python Trainin...
Edureka!
 
COURS_PYTHON_22.ppt
COURS_PYTHON_22.ppt
IbtissameAbbad1
 
Algoritma dan Struktur Data - Binary Search
Algoritma dan Struktur Data - Binary Search
KuliahKita
 
Php database connectivity
Php database connectivity
baabtra.com - No. 1 supplier of quality freshers
 
C++ string
C++ string
Dheenadayalan18
 
How to use Map() Filter() and Reduce() functions in Python | Edureka
How to use Map() Filter() and Reduce() functions in Python | Edureka
Edureka!
 
Pointers in C
Pointers in C
guestdc3f16
 
Jenis dan proses interupsi
Jenis dan proses interupsi
Vicky Setya Hermawan
 
PYthon
PYthon
Rajesh Tiwary
 
Chapitre 3 elements de base de java
Chapitre 3 elements de base de java
Amir Souissi
 
Dukungan implementasi
Dukungan implementasi
alimgunawan
 
External dependencies ,pre init hook &amp; post init hook in odoo
External dependencies ,pre init hook &amp; post init hook in odoo
Celine George
 
Initiation à ASP.NET 4.0
Initiation à ASP.NET 4.0
Jean-Baptiste Vigneron
 
F# for C# Programmers
F# for C# Programmers
Scott Wlaschin
 
02. prak.-pemrograman-berorientasi-objek
02. prak.-pemrograman-berorientasi-objek
Jamil Jamil
 
Generators In Python
Generators In Python
Simplilearn
 
Python Functions Tutorial | Working With Functions In Python | Python Trainin...
Python Functions Tutorial | Working With Functions In Python | Python Trainin...
Edureka!
 
Algoritma dan Struktur Data - Binary Search
Algoritma dan Struktur Data - Binary Search
KuliahKita
 
How to use Map() Filter() and Reduce() functions in Python | Edureka
How to use Map() Filter() and Reduce() functions in Python | Edureka
Edureka!
 
Chapitre 3 elements de base de java
Chapitre 3 elements de base de java
Amir Souissi
 
Dukungan implementasi
Dukungan implementasi
alimgunawan
 
External dependencies ,pre init hook &amp; post init hook in odoo
External dependencies ,pre init hook &amp; post init hook in odoo
Celine George
 

Similar to Rest API using Flask & SqlAlchemy (20)

Python RESTful webservices with Python: Flask and Django solutions
Python RESTful webservices with Python: Flask and Django solutions
Solution4Future
 
Build restful ap is with python and flask
Build restful ap is with python and flask
Jeetendra singh
 
Flask restless
Flask restless
Michael Andrew Shaw
 
Building a Backend with Flask
Building a Backend with Flask
Make School
 
Python Ireland Nov 2010 - RESTing with Django
Python Ireland Nov 2010 - RESTing with Django
Python Ireland
 
SW Security Lec4 Securing architecture.pptx
SW Security Lec4 Securing architecture.pptx
KhalidShawky1
 
RESTful SOA - 中科院暑期讲座
RESTful SOA - 中科院暑期讲座
Li Yi
 
rest-api-basics.pptx
rest-api-basics.pptx
AgungSutikno1
 
RefCard RESTful API Design
RefCard RESTful API Design
OCTO Technology
 
Building an API with Django and Django REST Framework
Building an API with Django and Django REST Framework
Christopher Foresman
 
UnRESTful APIs with Django
UnRESTful APIs with Django
Ari Lacenski
 
All you need to know when designing RESTful APIs
All you need to know when designing RESTful APIs
Jesús Espejo
 
FastAPI - Rest Architecture - in english.pdf
FastAPI - Rest Architecture - in english.pdf
inigraha
 
Introduction to rest using flask
Introduction to rest using flask
Wekanta
 
Pinterest like site using REST and Bottle
Pinterest like site using REST and Bottle
Gaurav Bhardwaj
 
Http and REST APIs.
Http and REST APIs.
Rahul Tanwani
 
Designing beautiful REST APIs
Designing beautiful REST APIs
Tomek Cejner
 
Attacking REST API
Attacking REST API
Siddharth Bezalwar
 
REST APIS web development for backend familiarity
REST APIS web development for backend familiarity
ARTUROGOMEZGARCIA2
 
NEPHP '13: Pragmatic API Development
NEPHP '13: Pragmatic API Development
Andrew Curioso
 
Python RESTful webservices with Python: Flask and Django solutions
Python RESTful webservices with Python: Flask and Django solutions
Solution4Future
 
Build restful ap is with python and flask
Build restful ap is with python and flask
Jeetendra singh
 
Building a Backend with Flask
Building a Backend with Flask
Make School
 
Python Ireland Nov 2010 - RESTing with Django
Python Ireland Nov 2010 - RESTing with Django
Python Ireland
 
SW Security Lec4 Securing architecture.pptx
SW Security Lec4 Securing architecture.pptx
KhalidShawky1
 
RESTful SOA - 中科院暑期讲座
RESTful SOA - 中科院暑期讲座
Li Yi
 
rest-api-basics.pptx
rest-api-basics.pptx
AgungSutikno1
 
RefCard RESTful API Design
RefCard RESTful API Design
OCTO Technology
 
Building an API with Django and Django REST Framework
Building an API with Django and Django REST Framework
Christopher Foresman
 
UnRESTful APIs with Django
UnRESTful APIs with Django
Ari Lacenski
 
All you need to know when designing RESTful APIs
All you need to know when designing RESTful APIs
Jesús Espejo
 
FastAPI - Rest Architecture - in english.pdf
FastAPI - Rest Architecture - in english.pdf
inigraha
 
Introduction to rest using flask
Introduction to rest using flask
Wekanta
 
Pinterest like site using REST and Bottle
Pinterest like site using REST and Bottle
Gaurav Bhardwaj
 
Designing beautiful REST APIs
Designing beautiful REST APIs
Tomek Cejner
 
REST APIS web development for backend familiarity
REST APIS web development for backend familiarity
ARTUROGOMEZGARCIA2
 
NEPHP '13: Pragmatic API Development
NEPHP '13: Pragmatic API Development
Andrew Curioso
 
Ad

Recently uploaded (20)

Step by step guide to install Flutter and Dart
Step by step guide to install Flutter and Dart
S Pranav (Deepu)
 
How the US Navy Approaches DevSecOps with Raise 2.0
How the US Navy Approaches DevSecOps with Raise 2.0
Anchore
 
Insurance Underwriting Software Enhancing Accuracy and Efficiency
Insurance Underwriting Software Enhancing Accuracy and Efficiency
Insurance Tech Services
 
How Insurance Policy Management Software Streamlines Operations
How Insurance Policy Management Software Streamlines Operations
Insurance Tech Services
 
Decipher SEO Solutions for your startup needs.
Decipher SEO Solutions for your startup needs.
mathai2
 
Wondershare PDFelement Pro 11.4.20.3548 Crack Free Download
Wondershare PDFelement Pro 11.4.20.3548 Crack Free Download
Puppy jhon
 
Who will create the languages of the future?
Who will create the languages of the future?
Jordi Cabot
 
Folding Cheat Sheet # 9 - List Unfolding 𝑢𝑛𝑓𝑜𝑙𝑑 as the Computational Dual of ...
Folding Cheat Sheet # 9 - List Unfolding 𝑢𝑛𝑓𝑜𝑙𝑑 as the Computational Dual of ...
Philip Schwarz
 
Artificial Intelligence Workloads and Data Center Management
Artificial Intelligence Workloads and Data Center Management
SandeepKS52
 
Software Testing & it’s types (DevOps)
Software Testing & it’s types (DevOps)
S Pranav (Deepu)
 
Reimagining Software Development and DevOps with Agentic AI
Reimagining Software Development and DevOps with Agentic AI
Maxim Salnikov
 
Milwaukee Marketo User Group June 2025 - Optimize and Enhance Efficiency - Sm...
Milwaukee Marketo User Group June 2025 - Optimize and Enhance Efficiency - Sm...
BradBedford3
 
DevOps for AI: running LLMs in production with Kubernetes and KubeFlow
DevOps for AI: running LLMs in production with Kubernetes and KubeFlow
Aarno Aukia
 
Integrating Survey123 and R&H Data Using FME
Integrating Survey123 and R&H Data Using FME
Safe Software
 
SAP PM Module Level-IV Training Complete.ppt
SAP PM Module Level-IV Training Complete.ppt
MuhammadShaheryar36
 
Porting Qt 5 QML Modules to Qt 6 Webinar
Porting Qt 5 QML Modules to Qt 6 Webinar
ICS
 
MOVIE RECOMMENDATION SYSTEM, UDUMULA GOPI REDDY, Y24MC13085.pptx
MOVIE RECOMMENDATION SYSTEM, UDUMULA GOPI REDDY, Y24MC13085.pptx
Maharshi Mallela
 
Rierino Commerce Platform - CMS Solution
Rierino Commerce Platform - CMS Solution
Rierino
 
OpenTelemetry 101 Cloud Native Barcelona
OpenTelemetry 101 Cloud Native Barcelona
Imma Valls Bernaus
 
Transmission Media. (Computer Networks)
Transmission Media. (Computer Networks)
S Pranav (Deepu)
 
Step by step guide to install Flutter and Dart
Step by step guide to install Flutter and Dart
S Pranav (Deepu)
 
How the US Navy Approaches DevSecOps with Raise 2.0
How the US Navy Approaches DevSecOps with Raise 2.0
Anchore
 
Insurance Underwriting Software Enhancing Accuracy and Efficiency
Insurance Underwriting Software Enhancing Accuracy and Efficiency
Insurance Tech Services
 
How Insurance Policy Management Software Streamlines Operations
How Insurance Policy Management Software Streamlines Operations
Insurance Tech Services
 
Decipher SEO Solutions for your startup needs.
Decipher SEO Solutions for your startup needs.
mathai2
 
Wondershare PDFelement Pro 11.4.20.3548 Crack Free Download
Wondershare PDFelement Pro 11.4.20.3548 Crack Free Download
Puppy jhon
 
Who will create the languages of the future?
Who will create the languages of the future?
Jordi Cabot
 
Folding Cheat Sheet # 9 - List Unfolding 𝑢𝑛𝑓𝑜𝑙𝑑 as the Computational Dual of ...
Folding Cheat Sheet # 9 - List Unfolding 𝑢𝑛𝑓𝑜𝑙𝑑 as the Computational Dual of ...
Philip Schwarz
 
Artificial Intelligence Workloads and Data Center Management
Artificial Intelligence Workloads and Data Center Management
SandeepKS52
 
Software Testing & it’s types (DevOps)
Software Testing & it’s types (DevOps)
S Pranav (Deepu)
 
Reimagining Software Development and DevOps with Agentic AI
Reimagining Software Development and DevOps with Agentic AI
Maxim Salnikov
 
Milwaukee Marketo User Group June 2025 - Optimize and Enhance Efficiency - Sm...
Milwaukee Marketo User Group June 2025 - Optimize and Enhance Efficiency - Sm...
BradBedford3
 
DevOps for AI: running LLMs in production with Kubernetes and KubeFlow
DevOps for AI: running LLMs in production with Kubernetes and KubeFlow
Aarno Aukia
 
Integrating Survey123 and R&H Data Using FME
Integrating Survey123 and R&H Data Using FME
Safe Software
 
SAP PM Module Level-IV Training Complete.ppt
SAP PM Module Level-IV Training Complete.ppt
MuhammadShaheryar36
 
Porting Qt 5 QML Modules to Qt 6 Webinar
Porting Qt 5 QML Modules to Qt 6 Webinar
ICS
 
MOVIE RECOMMENDATION SYSTEM, UDUMULA GOPI REDDY, Y24MC13085.pptx
MOVIE RECOMMENDATION SYSTEM, UDUMULA GOPI REDDY, Y24MC13085.pptx
Maharshi Mallela
 
Rierino Commerce Platform - CMS Solution
Rierino Commerce Platform - CMS Solution
Rierino
 
OpenTelemetry 101 Cloud Native Barcelona
OpenTelemetry 101 Cloud Native Barcelona
Imma Valls Bernaus
 
Transmission Media. (Computer Networks)
Transmission Media. (Computer Networks)
S Pranav (Deepu)
 
Ad

Rest API using Flask & SqlAlchemy

  • 1. REST APIREST API USING FLASK & SQLALCHEMYUSING FLASK & SQLALCHEMY Alessandro Cucci Python Developer, Energee3
  • 2. REPRESENTATIONAL STATE TRANSFERREPRESENTATIONAL STATE TRANSFER ROY THOMAS FIELDING - 2010ROY THOMAS FIELDING - 2010 HTTP://WWW.ICS.UCI.EDU/~FIELDING/PUBS/DISSERTATION/REST_ARCH_STYLE.HTMHTTP://WWW.ICS.UCI.EDU/~FIELDING/PUBS/DISSERTATION/REST_ARCH_STYLE.HTM
  • 4. RESTREST GUIDING CONSTRAINTSGUIDING CONSTRAINTS UNIFORM INTERFACEUNIFORM INTERFACE IDENTIFICATION OF RESOURCESIDENTIFICATION OF RESOURCES MANIPULATION OF RESOURCES THROUGH REPRESENTATIONSMANIPULATION OF RESOURCES THROUGH REPRESENTATIONS SELF-DESCRIPTIVE MESSAGESSELF-DESCRIPTIVE MESSAGES HYPERMEDIA AS THE ENGINE OF APPLICATION STATEHYPERMEDIA AS THE ENGINE OF APPLICATION STATE
  • 5. REST URI EXAMPLESREST URI EXAMPLES h�p://myapi.com/customers h�p://myapi.com/customers/33245 REST ANTI-PATTERNSREST ANTI-PATTERNS h�p://myapi.com/update_customer&id=12345& format=json h�p://myapi.com/customers/12345/update
  • 6. RELATIONSHIP BETWEEN URL AND HTTPRELATIONSHIP BETWEEN URL AND HTTP METHODSMETHODS URL GET PUT POST DELETE h�p://api.myvinylcollec�on.com /records/ LIST of records in collec�on Method not allowed. CREATE a new entry in the collec�on. DELETE the en�re collec�on. h�p://api.myvinylcollec�on.com /records/1 RETRIEVE a representa�on of the addressed member of the collec�on REPLACE the addressed member of the collec�on. Method not allowed. DELETE the addressed member of the collec�on.
  • 7. WHAT DO WE NOT CARE FOR THIS EVENINGWHAT DO WE NOT CARE FOR THIS EVENING Stability & Tes�ng Long-Term maintainability Edge Cases Opera�ons, Caching & Deployment
  • 8. MY VINYL COLLECTION APIMY VINYL COLLECTION API
  • 10. HELLO API!HELLO API! from flask import Flask app = Flask(__name__) if __name__ == '__main__': app.run() $ python myvinylcollectionapi.py * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
  • 12. HELLO API!HELLO API! from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello PyRE!" if __name__ == '__main__': app.run()
  • 13. HELLO API!HELLO API! from flask import Flask, jsonify app = Flask(__name__) @app.route("/") def hello(): return jsonify(data="Hello PyRE!") if __name__ == '__main__': app.run()
  • 14. HTTP GET METHODSHTTP GET METHODS URL GET h�p://api.myvinylcollec�on.com /records LIST of records in collec�on h�p://api.myvinylcollec�on.com /records/1 RETRIEVE a representa�on of the addressed member of the collec�on
  • 15. from flask import Flask, jsonify, abort app = Flask(__name__) RECORDS = [ { 'id': 0, 'artist': "Queen", 'title': "A Night At The Opera", 'year': "1975", 'label': "EMI" }, { 'id': 1, 'artist': "Pink Floyd", 'title': "The Dark Side Of The Moon", 'year': "1989", 'label': "EMI" }, ... ]
  • 16. @app.route("/records") def get_records(): return jsonify(RECORDS) @app.route("/records/<int:index>") def get_record(index): try: record = RECORDS[index] except IndexError: abort(404) return jsonify(record) if __name__ == '__main__': app.run()
  • 17. HTTP GET METHODHTTP GET METHOD $ curl -X GET localhost:5000/records [ { "artist": "Queen", "id": 0, "label": "EMI", "title": "A Night At The Opera", "year": "1975" }, { "artist": "Pink Floyd", "id": 1, "label": "EMI", "title": "The Dark Side Of The Moon", "year": "1989" } ]
  • 18. HTTP GET Method $ curl -X GET localhost:5000/records/1 { "artist": "Pink Floyd", "id": 1, "label": "EMI", "title": "The Dark Side Of The Moon", "year": "1989" } $ curl -X GET localhost:5000/records/5 <title>404 Not Found</title> <h1>Not Found</h1> <p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>
  • 19. JSONIFY THAT ERROR!JSONIFY THAT ERROR! @app.errorhandler(404) def page_not_found(error): return jsonify( error="Not Found", status_code=404 ), 404 $ curl -X GET localhost:5000/records/5 { "error": "Not Found", "status_code": 404 }
  • 20. GOOD NEWS:GOOD NEWS: IT WORKS!IT WORKS! BAD NEWS:BAD NEWS: STATIC DATASTATIC DATA
  • 22. SQLITESQLITE + DISCOGS.COM+ DISCOGS.COM + PANDAS+ PANDAS
  • 23. CREATE TABLE "collection" ( `index` INTEGER PRIMARY KEY AUTOINCREMENT, `Catalog#` TEXT, `Artist` TEXT, `Title` TEXT, `Label` TEXT, `Format` TEXT, `Rating` REAL, `Released` INTEGER, `release_id` INTEGER, `CollectionFolder` TEXT, `Date Added` TEXT, `Collection Media Condition` TEXT, `Collection Sleeve Condition` TEXT, `Collection Notes` REAL )
  • 24. CSV COLLECTION EXPORTCSV COLLECTION EXPORT
  • 25. import pandas import sqlite3 conn = sqlite3.connect('record_collection.db') conn.text_factory = sqlite3.Binary df = pandas.read_csv('collection.csv') df.to_sql('collection', conn)
  • 27. OBJECT RELATIONAL MAPPER (ORM)OBJECT RELATIONAL MAPPER (ORM) HTTP://DOCS.SQLALCHEMY.ORGHTTP://DOCS.SQLALCHEMY.ORG
  • 28. MODEL.PYMODEL.PY from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import orm db = SQLAlchemy() class Record(db.Model): __tablename__ = "collection" index = db.Column(db.Integer, primary_key=True) Artist = db.Column(db.Text, nullable=False) Title = db.Column(db.Text, nullable=False) Label = db.Column(db.Text) Released = db.Column(db.Text) def as_dict(self): columns = orm.class_mapper(self.__class__).mapped_table.c return { col.name: getattr(self, col.name) for col in columns }
  • 29. QUERYQUERY >>> # .all() return a list >>> all_records = Record.query.all() >>> len(all_records) 80 >>> # .first() return the first item that matches >>> record = Record.query.filter(Record.index == 9).first() >>> record.Title "Back In Black" >>> record.Artist "AC/DC" >>> record.Released "1980" >>> # .filter_by() is a shortcut >>> record = Record.query.filter_by(index == 6).first() >>> record.Title "Hotel California"
  • 30. from flask import Flask, jsonify from model import db, Record app = Flask(__name__) app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///record_collection.db" db.init_app(app) @app.route("/records") def get_records(): records = [r.as_dict() for r in Record.query.all()] return jsonify(records) @app.route("/records/<int:index>") def get_record(index): record = Record.query.filter(Record.index == index).first_or_404() return jsonify(record.as_dict())
  • 31. $ curl -X GET localhost:5000/records [ { "Artist": "The Police", "index": 0, "Title": "Reggatta De Blanc" }, { "Artist": "The Beatles", "index": 1, "Title": "Abbey Road" }, ... ] $ curl -X GET localhost:5000/records/1 { "Artist": "The Beatles", "index": 1, "Title": "Abbey Road" }
  • 32. HTTP POST METHODSHTTP POST METHODS URL POST h�p://api.myvinylcollec�on.com /records/ CREATE a new entry in the collec�on. h�p://api.myvinylcollec�on.com /records/1 Method not allowed.
  • 33. POST ON LOCALHOST:5000/RECORDS/IDPOST ON LOCALHOST:5000/RECORDS/ID @app.errorhandler(405) def method_not_allowed(error): return jsonify( error="Method Not Allowed", status_code=405 ), 405 from flask import Flask, jsonify, abort, request ... @app.route("/records/<int:index>", methods=['GET', 'POST']) def get_record(index): if request.method == 'POST': abort(405) record = Record.query.filter(Record.index == index).first_or_404() return jsonify(record.as_dict())
  • 34. $ curl -X POST localhost:5000/records/1 { "error": "Method Not Allowed", "status_code": 405 }
  • 35. INSERT INTO DATABASEINSERT INTO DATABASE >>> # .add() insert a record >>> db.session.add(record) >>> # changes won't be saved until committed! >>> db.session.commit()
  • 36. ADDING A RECORD TO MY COLLECTIONADDING A RECORD TO MY COLLECTION @app.route("/records", methods=['GET', 'POST']) def get_records(): if request.method == 'POST': record = Record(**json.loads(request.data)) db.session.add(record) db.session.commit() return jsonify(record.as_dict()), 201 records = [r.as_dict() for r in Record.query.all()] return jsonify(records)
  • 37. ADDING A RECORD TO MY COLLECTIONADDING A RECORD TO MY COLLECTION $ curl -i -H "Content-Type: application/json" -X POST localhost:5000/records > -d '{"Artist":"Neil Joung", "Title":"Harvest", > "Label":"Reprise Records", "Released":"1977"}' HTTP/1.0 201 CREATED Content-Type: application/json Content-Length: 104 Server: Werkzeug/0.11.11 Python/2.7.12+ Date: Sat, 03 Dec 2016 11:03:10 GMT { "Artist": "Neil Young", "Label": "Reprise Records", "Released": "1977", "Title": "American Stars 'N Bars", "index": 91 }
  • 38. HTTP PUT METHODSHTTP PUT METHODS URL PUT h�p://api.myvinylcollec�on.com /records/ Method not allowed. h�p://api.myvinylcollec�on.com /records/1 REPLACE the addressed member of the collec�on.
  • 39. @app.route("/records", methods=['GET', 'POST', 'PUT']) def get_records(): if request.method == 'POST': record = Record(**json.loads(request.data)) db.session.add(record) db.session.commit() return jsonify(record.as_dict()), 201 elif request.method == 'PUT': abort(405) records = [r.as_dict() for r in Record.query.all()] return jsonify(records), 200 @app.route("/records/<int:index>", methods=['GET', 'POST', 'PUT']) def get_record(index): if request.method == 'POST': abort(405) else: record = Record.query.filter(Record.index == index).first_or_404() if request.method == 'PUT': for k, v in json.loads(request.data).iteritems(): setattr(record, k, v) db.session.add(record) db.session.commit() return jsonify(record.as_dict()), 200
  • 40. PUT ON COLLECTIONPUT ON COLLECTION $ curl -i -H "Content-Type: application/json" > -X POST localhost:5000/records > -d '{"Artist":"Neil Joung", "Title":"Harvest", > "Label":"Reprise Records", "Released":"1977"}' HTTP/1.0 405 METHOD NOT ALLOWED Content-Type: application/json Content-Length: 59 Server: Werkzeug/0.11.11 Python/2.7.12+ Date: Sat, 03 Dec 2016 10:20:06 GMT { "error": "Method Not Allowed", "status_code": 405 }
  • 41. PUT ON RESOURCEPUT ON RESOURCE $ curl -i -H "Content-Type: application/json" > -X PUT localhost:5000/records/91 > -d '{"Artist":"Neil Joung", "Title":"Harvest", > "Label":"Reprise Records", "Released":"1977"}' HTTP/1.0 200 OK Content-Type: application/json Content-Length: 104 Server: Werkzeug/0.11.11 Python/2.7.12+ Date: Sat, 03 Dec 2016 11:07:22 GMT { "Artist": "Neil Young", "Label": "Reprise Records", "Released": "1977", "Title": "American Stars 'N Bars", "index": 91 }
  • 42. HTTP DELETE METHODSHTTP DELETE METHODS URL DELETE h�p://api.myvinylcollec�on.com /records/ DELETE the en�re collec�on. h�p://api.myvinylcollec�on.com /records/1 DELETE the addressed member of the collec�on.
  • 43. DELETE ON COLLECTIONDELETE ON COLLECTION @app.route("/records", methods=['GET', 'POST', 'PUT', 'DELETE']) def get_records(): if request.method == 'POST': record = Record(**json.loads(request.data)) db.session.add(record) db.session.commit() return jsonify(record.as_dict()), 201 elif request.method == 'PUT': abort(405) records = [r.as_dict() for r in Record.query.all()] if request.method == 'DELETE': for r in records: db.session.delete(r) db.session.commit() records = [r.as_dict() for r in Record.query.all()] return jsonify(records), 200
  • 44. DELETE ON RESOURCEDELETE ON RESOURCE @app.route("/records/<int:index>", methods=['GET', 'POST', 'PUT', 'DELETE']) def get_record(index): if request.method == 'POST': abort(405) else: record = Record.query.filter(Record.index == index).first_or_404() if request.method == 'PUT': for k, v in json.loads(request.data).iteritems(): setattr(record, k, v) db.session.add(record) db.session.commit() elif request.method == 'DELETE': db.session.delete(record) db.session.commit() return jsonify(record.as_dict()), 200
  • 45. DELETE ON RESOURCEDELETE ON RESOURCE $ curl -i -X DELETE localhost:5000/records/91 HTTP/1.0 200 OK Content-Type: application/json Content-Length: 104 Server: Werkzeug/0.11.11 Python/2.7.12+ Date: Sat, 03 Dec 2016 10:40:00 GMT { "Artist": "Neil Young", "Label": "Reprise Records", "Released": "1977", "Title": "American Stars 'N Bars", "index": 91 }
  • 46. DELETE ON RESOURCEDELETE ON RESOURCE $ curl -i -X DELETE localhost:5000/records/91 HTTP/1.0 HTTP/1.0 404 NOT FOUND Content-Type: application/json Content-Length: 50 Server: Werkzeug/0.11.11 Python/2.7.12+ Date: Sat, 03 Dec 2016 10:40:09 GMT { "error": "Not Found", "status_code": 404 }
  • 47. DELETE ON COLLECTIONDELETE ON COLLECTION $ curl -i -X DELETE localhost:5000/records
  • 50. PWD AUTHENTICATIONPWD AUTHENTICATION from flask import Flask, jsonify, abort from flask_login import LoginManager, current_user app = Flask(__name__) login_manager = LoginManager(app) @login_manager.request_loader def check_token(request): token = request.headers.get('Authorization') if token == 'L3T_M3_PA55!': return "You_can_pass" # DON'T TRY THIS AT HOME! return None @app.route("/") def get_main_root(): if current_user: return jsonify(data='Hello Login'), 200 else: abort(401)
  • 51. HOW IT WORKSHOW IT WORKS $ curl -i localhost:5000 HTTP/1.0 401 UNAUTHORIZED Content-Type: application/json WWW-Authenticate: Basic realm="Authentication Required" Content-Length: 37 Server: Werkzeug/0.11.11 Python/2.7.12+ Date: Sat, 03 Dec 2016 14:46:55 GMT { "error": "Unauthorized access" } $ curl -i -H "Authorization: L3T_M3_PA55!" localhost:5000 HTTP/1.0 200 OK Content-Type: application/json Content-Length: 28 Server: Werkzeug/0.11.11 Python/2.7.12+ Date: Sat, 03 Dec 2016 14:42:00 GMT { "data": "Hello Login" }
  • 52. SECURING OUR API - RESOURCESECURING OUR API - RESOURCE @app.route("/records/<int:index>", methods=['GET', 'POST', 'PUT', 'DELETE']) def get_record(index): if request.method == 'POST': abort(405) else: record = Record.query.filter(Record.index == index).first_or_404() if request.method == 'PUT': if current_user: for k, v in json.loads(request.data).iteritems(): setattr(record, k, v) db.session.add(record) db.session.commit() else: abort(401) elif request.method == 'DELETE': if current_user: db.session.delete(record) db.session.commit() else: abort(401) return jsonify(record.as_dict()), 200
  • 53. SECURING OUR API - COLLECTIONSECURING OUR API - COLLECTION @app.route("/records", methods=['GET', 'POST', 'PUT', 'DELETE']) def get_records(): if request.method == 'POST': record = Record(**json.loads(request.data)) db.session.add(record) db.session.commit() return jsonify(record.as_dict()), 201 elif request.method == 'PUT': abort(405) records = [r.as_dict() for r in Record.query.all()] if request.method == 'DELETE': if current_user: for r in records: db.session.delete(r) db.session.commit() records = [r.as_dict() for r in Record.query.all()] return jsonify(records), 200 else: abort(401) return jsonify(records), 200
  • 54. HOMEWORKSHOMEWORKS Pagina�on with Flask-SqlAlchemy Rate Limi�ng with Flask-Limiter Cache with Flask-Cache
  • 55. THANK YOU!THANK YOU! { 'slides': 'www.alessandrocucci.it/pyre/restapi', 'code': 'https://goo.gl/4UOqEr' }