Un exemple d'Application Programming Interface

Publié le 05/09/2014

Une API est (comme le dit si bien le lien ci-contre) une interface pour interagir avec une application en particulier. Il s'agit de définir la manière et les méthodes disponibles pour interagir avec un contexte. C'est ce qui rendra votre application accessible ou non depuis l'extérieur, et qui fera en sorte que d'autres systèmes pourront communiquer avec elle.

Cette API 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. 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 permettra 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 supprimera 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 arriver à un résultat sans trop se fouler.

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:

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):

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.

Sources et ressources