grimboite/articles/dev/draft-api-rest.md

6.3 KiB

Application Programming Interface

Date: 2014-09-05 Status: Draft

Une API est (comme le dit si bien le lien ci-contre) une interface pour interagir avec une application en particulier. En gros, c'est vraiment la définition de la manière et des méthodes disponibles pour un contexte; c'est ce qui rendra votre application accessible ou non depuis l'extérieur, et qui fera en sorte qu'elle pourra interagir avec d'autres systèmes. Elle peut se présenter sous plusieurs formes, en fonction de vos besoins et des spécifications. L'idée de cet article est de présenter une interface de type REST avec Flask et de montrer une manière de l'utiliser grâce à AngularJS.

Pour l'exemple, on va partir d'une structure simple (et pour éviter la bête liste de choses à faire, ce sera la liste de cadeaux, puisque c'est bientôt les fêtes de fin d'année).

C'est quoi, et comment ça s'utilise?

En utilisant curl ! Non, sans blague: avec tout et n'importe quoi. REST définit juste un ensemble de règles à respecter, pas un protocole de communication. C'est souvent (toujours?) utilisé au travers du protocole HTTP car les headers, les verbes et les codes d'erreur déjà définis dans la norme rendent l'API simple à mettre en oeuvre.

Parmi les verbes, on a :

  • GET pour la récupération d'une ressource à partir d'une URI. C'est ce qui se passe quand le navigateur récupère un ensemble d'informations depuis un site Internet par exemple; tapoter http://www.brol.be dans la barre d'adresse, appuyez sur Entrée et cela fera un GET sur la ressource identifiée à cette URI.
  • POST pour la création d'une nouvelle ressource. Ce verbe est généralement utilisé par les formulaires lors de l'envoi d'informations.
  • PUT pour la mise-à-jour d'une ressource.
  • PATCH pour la mise-à-jour partielle.
  • DELETE pour la suppression.
  • HEAD pour récupérer uniquement le header d'une ressource. En gros, cela fait la même chose qu'un get, mais sans récupérer le contenu.
  • OPTIONS pour récupérer les actions possibles sur une URI.

A part GET et POST, les autres verbes sont/étaient finalement assez peu utilisés, mais présentent un réel intérêt dans la mesure où une même URI peut présenter un comportement différent suivant le verbe associé à l'action. Imaginez avoir l'URL suivante qui soit accessible:

http://my-site.be/api/gifts

Avec un GET, vous récupéreriez la liste complète de toutes les entrées présentes; tandis qu'un POST vous permettrait d'ajouter une nouvelle entrée. De même qu'un HEAD pourrait simplement transmetter la date à laquelle la liste a été mise-à-jour pour la dernière fois. De cette manière, pas besoin de faire un GET complet pour le client, si sa dernière requête est ultérieur à la dernière date de mise-à-jour.

En continuant l'exemple avec l'URL suivante:

http://my-site.be/api/gift/1

Un PUT permettrait de mettre la ressource portant l'identifiant numéro 1 à jour, grâce à un ensemble de données passées en paramètres, tandis qu'un DELETE supprimerait purement et simplement cette ressource.

Exemple pratique

Pour un exemple pratique, l'idéal est de commencer avec Flask. D'abord parce que c'est du Python (et donc, c'est bien), ensuite parce que la syntaxe est suffisamment claire que pour comprendre sans trop se fouler. Ensuite, il existe plusieurs librairies pour faciliter l'écriture d'une API Rest directement à partir de la base de données (à pouf: Flask-Restless pour SQLAlchemy et Flask-peewee).

Pour définir l'API en elle-même, rien de plus facile: on définit tout d'abord une fonction:

:::python
from flask import request
@app.route('/api/objects', methods=['GET', 'POST'])
def endpoint():
    if request.method == 'GET':
        pass
    elif request.method == 'POST':
        pass

Parmi les options, on spécifie quels verbes peuvent être utilisés, et en fonction du contexte, on traite les informations différement.

Maintenant qu'on a l'idée principale, on peut passer par un projet un chouia plus complet, avec une base de données et un modèle qui-va-bien en utilisant peewee (au niveau des dépendances, on a flask et flask-peewee):

:::python
from datetime import datetime
from flask import Flask
from flask import render_template
from flask_peewee.rest import RestAPI
import peewee

app = Flask(__name__, static_folder='static', static_url_path='') # création de l'appli Flask
database = peewee.SqliteDatabase('ev.db', threadlocals=True)  # création de la base de données.

database.connect() 

class Event(peewee.Model):   
    """
    Définition d'un nouvel évènement.
    Contient un champ description et une date.
    """
    
    description = peewee.TextField()
    date = peewee.DateTimeField(default=datetime.now)
    
    def __unicode__(self):
        return u"%s @ %s" % (self.description, self.date)
        
    class Meta:
        database = database
        
try:
    Event.create_table()
except Exception:
    pass
    
@app.route('/') # la racine de l'appli :)
def index():
    return render_template('index.html')

""" 
Crée l'api, enregistre la classe Event définie ci-dessus, et crée les points d'accès.
"""
api = RestAPI(app)
api.register(Event)
api.setup()

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

On lance ensuite l'application avec python application.py, et on accède à notre nouvelle API via l'URL http://localhost:5000/api/event. Cette action va faire un GET sur la classe et retournera la liste complète des instances. Par défaut, la liste sera vide:

Sources: