• Stars
    star
    121
  • Rank 293,924 (Top 6 %)
  • Language
    Python
  • License
    MIT License
  • Created over 10 years ago
  • Updated almost 10 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Code for my PyCon talk "Writing RESTful Web Services with Flask"

Writing RESTful Web Services with Flask

Build Status

This repository contains a fully working API project that utilizes the techniques that I discussed in my PyCon 2014 talk on building beautiful APIs with Flask.

The API in this example implements a "students and classes" system and demonstrates RESTful principles, CRUD operations, error handling, user authentication, pagination, rate limiting and HTTP caching controls.

Requirements

To install and run this application you need:

  • Python 2.7 or 3.3+
  • virtualenv
  • git (only to clone this repository, you can download the code as a zip file if you prefer)

Installation

The commands below install the application and its dependencies:

$ git clone https://github.com/miguelgrinberg/api-pycon2014.git
$ cd api-pycon2014
$ virtualenv venv
$ . venv/bin/activate
(venv) pip install -r requirements.txt

Note for Microsoft Windows users: replace the virtual environment activation command above with venv\Scripts\activate.

The core dependencies are Flask, Flask-HTTPAuth, Flask-SQLAlchemy, Flask-Script and redis (only used for the rate limiting feature). For unit tests nose and coverage are used. The httpie command line HTTP client is also installed as a convenience.

Unit Tests

To ensure that your installation was successful you can run the unit tests:

(venv) $ python manage.py test
test_bad_auth (tests.test_api.TestAPI) ... ok
test_cache_control (tests.test_api.TestAPI) ... ok
test_classes (tests.test_api.TestAPI) ... ok
test_etag (tests.test_api.TestAPI) ... ok
test_pagination (tests.test_api.TestAPI) ... ok
test_password_auth (tests.test_api.TestAPI) ... ok
test_rate_limits (tests.test_api.TestAPI) ... ok
test_registrations (tests.test_api.TestAPI) ... ok
test_students (tests.test_api.TestAPI) ... ok

Name                     Stmts   Miss Branch BrMiss  Cover   Missing
--------------------------------------------------------------------
api                          0      0      0      0   100%
api.app                     13      0      5      1    94%
api.auth                    13      0      2      0   100%
api.decorators              84      1     26      1    98%   17
api.errors                  31      9      0      0    71%   15-18, 29-32, 36-39
api.helpers                 23      6     11      6    65%   11, 18-20, 27, 34
api.models                  86      2      4      1    97%   48, 118
api.rate_limit              38      1      6      1    95%   38
api.token                   18      2      2      1    85%   15, 21
api.v1_0                    20      3      2      0    86%   11, 16, 21
api.v1_0.classes            36      0      0      0   100%
api.v1_0.registrations      25      0      0      0   100%
api.v1_0.students           36      0      0      0   100%
--------------------------------------------------------------------
TOTAL                      423     24     58     11    93%
----------------------------------------------------------------------
Ran 9 tests in 4.378s

OK

The report printed below the tests is a summary of the test coverage. A more detailed report is written to a cover folder. To view it, open cover/index.html with your web browser.

User Registration

The API can only be accessed by authenticated users. New users can be registered with the application from the command line:

(venv) $ python manage.py adduser <username>
Password: <password>
Confirm: <password>
User <username> was registered successfully.

The system supports multiple users, so the above command can be run as many times as needed with different usernames. Users are stored in the application's database, which by default uses the SQLite engine. An empty database is created in the current folder if a previous database file is not found.

API Documentation

The API supported by this application contains three top-level resources:

  • /api/v1.0/students/: The collection of students.
  • /api/v1.0/classes/: The collection of classes.
  • /api/v1.0/registrations/: The collection of student/class registrations.

All other resource URLs are to be discovered from the responses returned from the above three.

There are four resource types supported by this API, described in the sections below. Note that this API supports resource representations in JSON format only.

Resource Collections

All resource collections have the following structure:

{
    "urls": [
        [URL 1],
        [URL 2],
        ...
    ],
    "meta": {
        "page": [current_page],
        "pages": [total_page_count],
        "per_page": [items_per_page],
        "total": [total item count],
        "prev": [link to previous page],
        "next": [link to next page],
        "first": [link to first page],
        "last": [link to last page]
    }
}

The urls key contains an array with the URLs of the requested resources. Note that results are paginated, so not all the resource in the collection might be returned. Clients should use the navigation links in the meta portion to obtain more resources.

Student Resource

A student resource has the following structure:

{
    "url": [student URL],
    "name": [student name],
    "registrations": [link to student registrations]
}

When creating or updating a student resource only the name field needs to be provided. The following example creates a student resource by sending a POST request to the top-level students URL. The httpie command line client is used to send this request.

(venv) $ http --auth <username> POST http://localhost:5000/api/v1.0/students/ name=david
http: password for <username>@localhost:5000: <password>
HTTP/1.0 201 CREATED
Content-Length: 2
Content-Type: application/json
Date: Fri, 04 Apr 2014 00:53:44 GMT
Location: http://localhost:5000/api/v1.0/students/1
Server: Werkzeug/0.9.4 Python/2.7

{}

Only the name field needs to be provided when creating or modifying a student resource. Note the Location header included in the response, which contains the URL of the newly created resource. This URL can now be used to get specific information about this resource:

(venv) $ http --auth <username> GET http://localhost:5000/api/v1.0/students/1
http: password for <username>@localhost:5000: <password>
HTTP/1.0 200 OK
Content-Length: 157
Content-Type: application/json
Date: Fri, 04 Apr 2014 00:54:02 GMT
ETag: "c65dfd7eef67b79e15a614c800009830"
Server: Werkzeug/0.9.4 Python/2.7

{
    "name": "david",
    "registrations": "http://localhost:5000/api/v1.0/students/1/registrations/",
    "url": "http://localhost:5000/api/v1.0/students/1"
}

The student resource supports GET, POST, PUT and DELETE methods.

Class Resource

The class resource has a similar structure:

{
    "url": [class URL],
    "name": [class name],
    "registrations": [link to class registrations]
}

Using httpie a class can be created as follows:

(venv) $ http --auth <username> POST http://localhost:5000/api/v1.0/classes/ name=algebra
http: password for <username>@localhost:5000: <password>
HTTP/1.0 201 CREATED
Content-Length: 2
Content-Type: application/json
Date: Fri, 04 Apr 2014 00:53:44 GMT
Location: http://localhost:5000/api/v1.0/classes/1
Server: Werkzeug/0.9.4 Python/2.7

{}

Once again, the URL for the new resource is given in the Location header.

The class resource supports GET, POST, PUT and DELETE methods.

Registration Resource

The registration resource associates a student with a class. Below is the structure of this resource:

{
    "url": [registration URL],
    "student": [student URL],
    "class": [class URL],
    "timestamp": [date of registration]
}

To create a registration a POST request to the top-level registration URL is sent:

(venv) $ http --auth <username> POST http://localhost:5000/api/v1.0/registrations/ student=http://localhost:5000/api/v1.0/students/1 class=http://localhost:5000/api/v1.0/classes/1
http: password for <username>@localhost:5000: <password>
HTTP/1.0 201 CREATED
Content-Length: 2
Content-Type: application/json
Date: Fri, 04 Apr 2014 01:05:50 GMT
Location: http://localhost:5000/api/v1.0/registrations/1/1
Server: Werkzeug/0.9.4 Python/2.7

{}

The only required fields to create a registration resource are student and class, which should be set to the resource URLs for the respective student and class resources. The timestamp field is assigned automatically based on the clock at the time the request is sent.

Using the URL returned in the Location header now the registration resource can be queried:

(venv) $ http --auth <username> GET http://localhost:5000/api/v1.0/registrations/1/1
http: password for miguel@localhost:5000: <password>
HTTP/1.0 200 OK
Content-Length: 227
Content-Type: application/json
Date: Fri, 04 Apr 2014 01:06:14 GMT
ETag: "512ece33e166ba6759ad31d913adfe17"
Server: Werkzeug/0.9.4 Python/2.7

{
    "url": "http://localhost:5000/api/v1.0/registrations/1/1",
    "student": "http://localhost:5000/api/v1.0/students/1",
    "class": "http://localhost:5000/api/v1.0/classes/1",
    "timestamp": "Fri, 04 Apr 2014 01:05:50 GMT"
}

The registration resource supports GET, POST and DELETE methods.

Using Token Authentication

The default configuration uses username and password for request authentication. To switch to token based authentication the configuration stored in config.py must be edited. In particular, the line that begins with USE_TOKEN_AUTH must be changed to:

USE_TOKEN_AUTH = True 

After this change restart the application for the change to take effect.

With this change authenticating using username and password will not work anymore. Instead an authentication token must be requested:

(venv) $ http --auth <username> GET http://localhost:5000/auth/request-token
http: password for <username>@localhost:5000: <password>
HTTP/1.0 200 OK
Cache-Control: no-cache, no-store, max-age=0
Content-Length: 139
Content-Type: application/json
Date: Fri, 04 Apr 2014 01:18:55 GMT
Server: Werkzeug/0.9.4 Python/2.7

{
    "token": "eyJhbGciOiJIUzI1NiIsImV4cCI6MTM5NjU3NzkzNSwiaWF0IjoxMzk2NTc0MzM1fQ.eyJpZCI6MX0.8XFUzlGz5XPGJp0weoOXy6avwr7OS1ojMbJYpBvw42I"
}

The returned token must be sent as authentication for all requests into the API:

(venv) $ http --auth eyJhbGciOiJIUzI1NiIsImV4cCI6MTM5NjU3NzkzNSwiaWF0IjoxMzk2NTc0MzM1fQ.eyJpZCI6MX0.8XFUzlGz5XPGJp0weoOXy6avwr7OS1ojMbJYpBvw42I: GET http://localhost:5000/api/v1.0/students/
HTTP/1.0 200 OK
Content-Length: 345
Content-Type: application/json
Date: Fri, 04 Apr 2014 01:21:52 GMT
ETag: "b6ce14e7c7496c7d3b22fff0f0fba666"
Server: Werkzeug/0.9.4 Python/2.7

{
    "urls": [
        "http://localhost:5000/api/v1.0/students/1"
    ],
    "meta": {
        "page": 1,
        "pages": 1,
        "per_page": 50,
        "total": 1,
        "prev": null,
        "next": null,
        "first": "http://localhost:5000/api/v1.0/students/?per_page=50&page=1",
        "last": "http://localhost:5000/api/v1.0/students/?per_page=50&page=1"
    }
}

Note the colon character following the token, this is to prevent httpie from asking for a password, since token authentication does not require one.

HTTP Caching

The different API endpoints are configured to respond using the appropriate caching directives. The GET requests return an ETag header that HTTP caches can use with the If-Match and If-None-Match headers.

The GET request that returns the authentication token is not supposed to be cached, so the response includes a Cache-Control directive that disables caching.

Rate Limiting

This API supports rate limiting as an optional feature. To use rate limiting the application must have access to a Redis server running on the same host and listening on the default port.

To enable rate limiting change the following line in config.py:

USE_RATE_LIMITS = True

The default configuration limits clients to 5 API calls per 15 second interval. When a client goes over the limit a response with the 429 status code is returned immediately, without carrying out the request. The limit resets as soon as the current 15 second period ends.

When rate limiting is enabled all responses return three additional headers:

X-RateLimit-Limit: [period in seconds]
X-RateLimit-Remaining: [remaining calls in this period]
X-RateLimit-Reset: [time when the limits reset, in UTC epoch seconds]

Conclusion

I hope you find this example useful. If you have any questions feel free to ask!

More Repositories

1

flasky

Companion code to my O'Reilly book "Flask Web Development", second edition.
Python
8,256
star
2

Flask-SocketIO

Socket.IO integration for Flask applications.
Python
5,111
star
3

microblog

A microblogging web application written in Python and Flask that I developed as part of my Flask Mega-Tutorial series.
Python
4,297
star
4

python-socketio

Python Socket.IO server and client
Python
3,742
star
5

Flask-Migrate

SQLAlchemy database migrations for Flask applications using Alembic
Python
2,243
star
6

flask-video-streaming

Supporting code for my article on video streaming with Flask.
Python
1,353
star
7

microdot

The impossibly small web framework for Python and MicroPython.
Python
1,326
star
8

Flask-HTTPAuth

Simple extension that provides Basic, Digest and Token HTTP authentication for Flask routes
Python
1,206
star
9

flask-celery-example

This repository contains the example code for my blog article Using Celery with Flask.
Python
1,171
star
10

REST-auth

Example application for my RESTful Authentication with Flask article.
Python
905
star
11

REST-tutorial

Files for my REST API tutorials featuring a server written in Python and a web client written in Javascript.
HTML
656
star
12

Flask-SocketIO-Chat

A simple chat application that demonstrates how to structure a Flask-SocketIO application.
Python
639
star
13

flack

Companion code to my PyCon 2016 "Flask at Scale" tutorial session.
Python
502
star
14

Flask-Moment

Formatting of dates and times in Flask templates using moment.js.
Python
364
star
15

microblog-api

A modern (as of 2023) Flask API back end.
Python
345
star
16

APIFairy

A minimalistic API framework built on top of Flask, Marshmallow and friends.
Python
316
star
17

turbo-flask

Integration of Hotwire's Turbo library with Flask.
Python
291
star
18

flasky-with-celery

How to incorporate Celery into a well structured Flask application
Python
279
star
19

flask-tables

Beautiful Interactive tables in your Flask templates.
Python
272
star
20

react-flask-app

A Flask + React demo application.
JavaScript
266
star
21

flask-sock

WebSocket support without gevent for Flask and other WSGI frameworks.
Python
247
star
22

Flask-PageDown

Implementation of StackOverflow's "PageDown" markdown editor for Flask and Flask-WTF.
Python
240
star
23

flask-oauth-example

Example code from my "OAuth Authentication with Flask" article.
Python
238
star
24

python-engineio

Python Engine.IO server and client
Python
224
star
25

flasky-first-edition

Companion code to the first edition of my O'Reilly book "Flask Web Development".
Python
218
star
26

promisio

JavaScript-style async programming for Python.
Python
210
star
27

aioflask

Flask running on asyncio!
Python
200
star
28

oreilly-flask-apis-video

This repository contains the software that accompanies my O'Reilly training video "Building Web APIs with Flask".
Python
192
star
29

api-pycon2015

Code for my PyCon talk "Is Your REST API RESTful?"
Python
154
star
30

oreilly-intro-to-flask-video

This repository contains the software that accompanies my O'Reilly training video "An Introduction to Flask".
Python
152
star
31

greenletio

Asyncio integration with sync code using greenlets.
Python
146
star
32

flask-pycon2014

Code for my PyCon 2014 tutorial "Flask By Example"
Python
145
star
33

merry

Decorator based error handling for Python
Python
144
star
34

two-factor-auth-flask

Example application for my "Two Factor Authentication with Flask" blog article.
Python
143
star
35

flask-twilio-video

A small video conference application using Flask and Twilio Programmable Video
JavaScript
119
star
36

alchemical

SQLAlchemy 2.0+ wrapper that simplifies its use in Python applications. Can be used on its own or alongside Flask, FastAPI or other web frameworks.
Python
117
star
37

flask-gridjs

Beautiful Interactive tables in your Flask templates using grid.js.
HTML
107
star
38

flask-examples

Code for my "Python Web Development with Flask" presentation.
Python
99
star
39

socketio-examples

A few examples that demonstrate the features of the Python Socket.IO server
JavaScript
89
star
40

microflack_admin

Shell
86
star
41

flask-paranoid

Simple user session protection
Python
74
star
42

retrofun

Code from my "SQLAlchemy 2 In Practice" book.
Python
72
star
43

slam

Serverless deployment of Python APIs
Python
70
star
44

simple-websocket

Simple WebSocket server and client for Python.
Python
69
star
45

quick-socketio-tutorial

Python
68
star
46

sqlalchemy-soft-delete

Implementation of soft deletes for Flask and SQLAlchemy
Python
67
star
47

flask-pycon2015

Code for my PyCon 2015 tutorial "Flask Workshop"
Python
63
star
48

react-microblog

Code for my React Mega-Tutorial course.
JavaScript
61
star
49

django-verify

Extending the Django authentication system with a phone verification step.
Python
53
star
50

anaglyph.py

3D Anaglyph image generator
Python
48
star
51

heat-tutorial

Supporting files for my "OpenStack Orchestration in Depth" tutorial.
41
star
52

climax

A lightweight argparse wrapper inspired by click.
Python
40
star
53

Flask-Runner

A set of standard command line arguments for Flask applications
Python
40
star
54

michelino

A firmware for Arduino based remote controlled robot vehicles.
C++
39
star
55

look-ma-no-http

Code from my EuroPython 2019 talk "Look Ma, No HTTP!"
Python
37
star
56

flask-webcast

Code from my O'Reilly webcast "Python Web Development with Flask"
Python
36
star
57

flask-react-twilio-chat

A chat application based on the Twilio Conversations API with a Flask back end and a React front end.
JavaScript
31
star
58

mylang

The "my" programming language from my toy language tutorial.
Python
31
star
59

flask-stripe-orders

Python
29
star
60

microblog-verify

Microblog application from the Flask Mega-Tutorial with added two-factor authentication via the Twilio Verify API.
Python
28
star
61

microblog-authy

Microblog application from the Flask Mega-Tutorial with added two-factor push authentication via Authy
Python
27
star
62

asyncio-testing

Unit testing asyncio code
Python
27
star
63

microflack_common

Python
26
star
64

micropython-iot-tutorial

Source code for the "MicroPython and the Internet of Things" tutorial by Miguel Grinberg
Python
25
star
65

aio-executor

A concurrent.futures.Executor implementation that runs asynchronous tasks in an asyncio loop.
Python
22
star
66

eudcc-decoder

React application that scans, decodes and validates EU Digital COVID-19 certificates, all in the browser.
JavaScript
21
star
67

flask-phone-input

An example application that shows how to integrate the intTelInput.js library with Flask and Flask-WTF.
HTML
20
star
68

flask-webauthn-demo

HTML
20
star
69

microflack_users

Python
19
star
70

microflack_ui

JavaScript
19
star
71

twilio-serverless-video

JavaScript
18
star
72

circular-dependencies-webcast

Example code for my webcast on circular dependencies in Python
Python
18
star
73

react-microblog-ts

A version of the React Mega-Tutorial project adapted to TypeScript
TypeScript
18
star
74

webcast-assistant

A little Flask + React application that helps me host live streaming events
JavaScript
17
star
75

easy-cli

Easy, yet powerful, command line configuration based on zsh, tmux and vim.
Vim Script
17
star
76

sendgrid-flask-mail

An example Flask and Flask-Mail application that sends emails through Twilio SendGrid
Python
16
star
77

python-testing

Code from my Python unit testing blog articles
Python
16
star
78

microflack_tokens

Python
16
star
79

twilio-send-sms-demo

Python
16
star
80

easy-etcd

Start an etcd cluster with ease!
Shell
16
star
81

microflack_socketio

Python
16
star
82

microflack_messages

Python
14
star
83

flatdoc

Flat documentation generator
Python
14
star
84

flask-live-coding-webcast

This repository contains the code I wrote during my O'Reilly webcast "Let's Build a Web Application!"
Python
13
star
85

cygwin-installer

A script that simplifies the installation of Cygwin
Batchfile
12
star
86

flask-preact

An example integration between Flask and the Preact front end library.
HTML
12
star
87

easy-lb-haproxy

Simple load balancer container for Docker based on haproxy, confd and etcd
Shell
12
star
88

twilio-api-explorer

An interactive browser for Twilio's OpenAPI specs.
JavaScript
10
star
89

Flask-MarrowMailer

Marrow Mailer integration for Flask.
Python
9
star
90

twilio-serverless-video-call

A simple video calling application hosted on the Twilio serverless platform
JavaScript
9
star
91

micropython-esp8266-vagrant

A virtual machine that simplifies building MicroPython for the ESP8266 microcontroller.
Shell
9
star
92

Flask-Intro

Sample code from my "Introduction to Flask" presentation.
Python
8
star
93

flask-token-auth-demo

7
star
94

microblog-2012

Microblog application for the original Flask Mega-Tutorial from 2012
Python
7
star
95

micropython-pico-code

Code for my MicroPython with the Raspberry Pi Pico book.
Python
7
star
96

arduino-digital-picture-frame

An Arduino digital picture frame server, with a Python client for it.
Python
6
star
97

easy-lb-nginx

Simple load balancer container based on nginx, confd and etcd
Shell
6
star
98

microblog-2018

The 2018 and 2021 versions of the microblog project of the Flask Mega-Tutorial
Python
6
star
99

live-screen-sharing

JavaScript
5
star
100

softcover-for-docker

Docker container image for the softcover toolchain for building ebooks.
Dockerfile
5
star