Home Tags Anciens articles Mon CV

Flask : les APIs

Riez.

Développer du Web, pour moi, a toujours censé être une activité fun. Pour que cela le rest (oh la vanne en début d’article), il faut utiliser des langages et des frameworks qui vous parlent, qui conviennent à vos besoins et avec lesquels vous êtes à l’aise.

Depuis quelques temps, je fais du Python à tout bout de champ. Django est souvent le premier candidat qui nous vient à l’esprit quand on pense « Python » et « Web ». Mais il existe des alternatives, notamment Flask, un microframework web.

Je ne vais pas le détailler beaucoup ici mais plutôt me concentrer sur un module, Flask-RESTful, qui permet l’écriture aisée d’APIs REST au sein d’une application Flask ou en standalone.

Qu’est-ce que Flask-RESTful?

Rapidement, c’est une extension de Flask qui ajoute à ce dernier le support pour construire des API REST.

Il fonctionne avec les librairies et les ORMs déjà présents dans votre application Flask, vu qu’un objet instancié de cette extension hérite des paramètres de votre application Flask (à voir dans l’exemple que je décris plus bas).

Installation

Cette extension s’installe simplement, que vous soyez en virtualenv ou non, via la commande pip:

$ pip install flask-restful

Good to go !

Une API minimale

Une API minimale écrite avec Flask-RESTful serait :

from flask import Flask
from flask_restful import Resource, Api

app = Flask(__name__)
api = Api(app)

@api.resource('/foo')
class Todo(Resource):
    def get(self):
        return {'Hello' : 'world'}

if __name__ == '__main__':
    app.run(port=80, debug=True)

Un peu d’explications.

En premier lieu, on créé notre objet API, qui hérite des paramètres de notre application Flask (notamment son accès à un SGBD, par exemple).

from flask import Flask
from flask_restful import Resource, Api

app = Flask(__name__)
api = Api(app)

Dans cette API minimaliste, et disons-le franchement inutile (c’est un exemple, souvenez-vous), on définit une route d’API « /foo » sur notre application.

@api.resource('/foo')
class Todo(Resource):
    def get(self):
        return {'Hello' : 'world'}

On utilise pour cela un décorateur qui indique la route, puis on définit une classe qui sera notre ressource.

Dans cette classe, on définit les méthodes qui seront nommées comme les méthodes HTTP utilisées avec cette ressource.

En l’occurrence, une requête de type GET retournera …

Surprise, hein.

On lance ensuite le serveur avec :

if __name__ == '__main__':
    app.run(port=80, debug=True)

Comme dans une application Flask classique. A noter que je lui donne en paramètre l’instruction afin d’utiliser directement le port 80 durant mon développement. Sans celui-ci, l’application se lance sur le port 5000.

Le serveur standalone inclut dans Flask n’a pas vocation a être utilisé en production. Privilégiez par exemple Apache avec le mod_wsgi

N’importe quel développeur Python faisant du Web 🙂

Et pour faire quelque chose d’utile ?

Une fois que vous avez compris le principe des ressources et des requêtes définies pour y accéder, les possibilités sont infinies.

En effet, vous pouvez passer des paramètres à chaque requêtes, de la même manière que dans une méthode de classe classique. Tout devient alors dynamique!

Pour vous l’expliquer, je vais prendre cet exemple de la documentation et vous le commenter.

from flask import Flask, request
from flask_restful import Resource, Api

app = Flask(__name__)
api = Api(app)

# on créé un dictionnaire qui va contenir nos données
todos = {}

# on créé la ressource principale
@api.resource('/<string:todo_id>')
class TodoSimple(Resource):
    # le GET nous permet d'aller chercher la todo désirée
    def get(self, todo_id):
        return {todo_id: todos[todo_id]}

    # grâce au put, on ajoute au dictionnaire une requête formatée id -> 
    # data
    def put(self, todo_id):
        todos[todo_id] = request.form['data']
        return {todo_id: todos[todo_id]}

if __name__ == '__main__':
    app.run(debug=True)

Une fois cette API lancée, on peut ajouter une todo via un requête PUT:

$ curl http://localhost:5000/todo1 -d "data=Acheter du pain" -X PUT

On peut ensuite requêter notre API pour aller chercher cette donnée via un GET:

$ curl http://localhost:5000/todo1 
{"todo1": "Acheter du pain"}

Dans notre méthode, le paramètre todo1 est bien passé à la méthode de classe de manière classique:

def get(self, todo_id):
    return {todo_id: todos[todo_id]}

Conclusion

Cet article n’avait pour dessein que de vous donner un aperçu rapide de cette extension et vous donner les « outils » nécessaires pour démarrer. Vous n’êtes limités que par votre imagination.

Notre requête PUT pourrait par exemple aller attaquer un MongoDB, pour stocker les données de notre TODO sous forme de NoSQL.

Source : la documentation officielle.

PS : comme vous le constatez, j’ai écrit cet article avec beaucoup d’humour 🙂