API REST en Python Avec Flask
API REST en Python Avec Flask
SQLAlchemy - Partie 1
Démo
Mise en route
La plupart des applications Web modernes sont alimentées par une API REST
sous le capot. Ainsi, les développeurs peuvent séparer le code front end de la
logique dorsale, et les utilisateurs peuvent interagir avec l'interface de manière
dynamique. Dans cette série de didacticiels en trois parties, vous allez créer une
API REST avec le framework Web Flask.
Vous créerez une base avec un projet Flask de base, puis vous ajouterez des
points d'extrémité et les connecterez à une base de données SQLite. Vous
testerez votre API à l'aide de la documentation Swagger UI API que vous
construirez en cours de route.
Démo
Dans cette série de didacticiels en trois parties, vous allez construire une API
REST pour conserver la trace des notes des personnes qui peuvent vous rendre
visite tout au long de l'année. Dans ce tutoriel, vous créerez des personnes
comme la fée des dents, le lapin de Pâques et Knecht Ruprecht.
Idéalement, tu veux être en bons termes avec ces trois personnes. C'est pourquoi
vous leur enverrez des notes, afin d'augmenter vos chances d'obtenir des
cadeaux de valeur de leur part.
L'API REST que vous allez créer servira une structure de données de personnes
simple où les personnes sont associées au nom de famille et où toute mise à jour
est marquée par un nouvel horodatage.
Pour commencer
Dans cette section, vous allez préparer l'environnement de développement pour
votre projet d'API REST Flask. Tout d'abord, vous allez créer un environnement
virtuel et installer toutes les dépendances dont vous avez besoin pour votre
projet.
Dans cette section, vous allez construire la structure de votre projet. Vous
pouvez nommer le dossier racine de votre projet comme vous le souhaitez. Par
exemple, vous pouvez le nommer rp_flask_api/. Créez le dossier et naviguez
dedans :
$ mkdir rp_flask_api
$ cd rp_flask_api
Dans ce cas, vous nommez le dossier racine de votre projet rp_flask_api/. Les
fichiers et dossiers que vous créerez au cours de cette série seront situés dans ce
dossier ou dans ses sous-dossiers.
Windows
PS> python -m venv venv
PS> .\venv\Scripts\activate
(venv) PS>
Linux
$ python -m venv venv
$ source venv/Scripts/activate
(venv) $
Le framework micro web Flask est la principale dépendance dont votre projet a
besoin. En plus de Flask, installez Connexion pour gérer les requêtes HTTP :
# app.py
app = Flask(__name__)
@app.route("/")
def home():
return render_template("home.html")
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000, debug=True)
En bref, ce code fait fonctionner un serveur web de base et lui fait répondre avec
un modèle home.html, qui sera servi au navigateur lorsqu'il naviguera vers
l'URL "/".
Remarque : le serveur de développement de Flask utilise par défaut le port 5000.
Sur les nouvelles versions de macOS, ce port est déjà utilisé par le récepteur
AirPlay de macOS. Ci-dessus, vous avez changé le port de votre application
Flask avec port=8000. Si vous le souhaitez, vous pouvez modifier les
préférences du récepteur AirPlay sur votre Mac.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>RP Flask REST API</title>
</head>
<body>
<h1>
Hello, World!
</h1>
</body>
</html>
Flask est livré avec le moteur de template Jinja (Jinja Templating Engine), qui
vous permet d'améliorer vos templates. Mais votre modèle home.html est un
fichier HTML ( HTML file) de base sans aucune fonctionnalité Jinja. Ce n'est
pas grave pour l'instant, car le but de home.html est de vérifier que votre projet
Flask répond comme prévu.
Avec l'environnement virtuel Python actif, vous pouvez exécuter votre
application avec cette ligne de commande dans le répertoire contenant le fichier
app.py :
rp_flask_api/
│
├── templates/
│ └── home.html
│
└── app.py
Il s'agit d'une structure idéale pour démarrer tout projet Flask. Vous constaterez
que le code source vous sera utile lorsque vous travaillerez sur de futurs projets.
Vous pouvez le télécharger ici :
Dans les sections suivantes, vous allez développer le projet et ajouter vos
premiers points de terminaison d'API REST.
Lorsque vous utilisez OpenAPI avec Swagger, vous pouvez créer une interface
utilisateur (IU) pour explorer l'API. Tout cela peut se produire lorsque vous
créez un fichier de configuration auquel votre application Flask peut accéder.
# swagger.yml
openapi: 3.0.0
info:
title: "RP Flask REST API"
description: "An API about people and notes"
version: "1.0.0"
Lorsque vous définissez une API, vous devez inclure la version de votre
définition OpenAPI. Vous utilisez le mot-clé openapi pour cela. La chaîne de
version est importante car certaines parties de la structure de l'OpenAPI peuvent
changer au fil du temps.
Ensuite, ajoutez servers et url, qui définissent le chemin racine de votre API :
# swagger.yml
# ...
servers:
- url: "/api"
# swagger.yml
# ...
paths:
/people:
get:
operationId: "people.read_all"
tags:
- "People"
summary: "Read the list of people"
responses:
"200":
description: "Successfully read people list"
Le bloc paths commence la configuration des chemins d'accès aux URL de l'API
:
Avec la définition de l'url dans les serveurs, cela crée le point de terminaison
GET /api/people auquel vous pouvez accéder à l'adresse
http://localhost:8000/api/people.
openapi: 3.0.0
info:
title: "RP Flask REST API"
description: "An API about people and notes"
version: "1.0.0"
servers:
- url: "/api"
paths :
/people:
get:
operationId: "people.read_all"
tags:
- "People"
summary: "Read the list of people"
responses:
"200":
description: "Successfully read people list"
Le fichier swagger.yml est comme un schéma directeur pour votre API. Avec les
spécifications que vous incluez dans swagger.yml, vous définissez les données
que votre serveur Web peut attendre et la façon dont il doit répondre aux
demandes. Mais jusqu'à présent, votre projet Flask ne connaît pas votre fichier
swagger.yml. Lisez la suite pour utiliser Connexion afin de connecter votre
spécification OpenAPI à votre application Flask.
# app.py
from flask import render_template # Remove: import Flask
import connexion
app = connexion. App(__name__, specification_dir="./")
app.add_api("swagger.yml")
@app.route("/")
def home():
return render_template("home.html")
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000, debug=True)
Pour que cela fonctionne, créez un fichier people.py avec une fonction read_all()
:
# people.py
5def get_timestamp():
return datetime.now().strftime(("%Y-%m-%d %H:%M:%S"))
8PEOPLE = {
"Fairy": {
"fname": "Tooth",
"lname": "Fairy",
"timestamp": get_timestamp(),
},
"Ruprecht": {
"fname": "Knecht",
"lname": "Ruprecht",
"timestamp": get_timestamp(),
},
"Bunny": {
"fname": "Easter",
"lname": "Bunny",
"timestamp": get_timestamp(),
}
}
def read_all():
return list(PEOPLE.values())
À la ligne 5, vous créez une fonction d'aide appelée get_timestamp() qui génère
une représentation en chaîne de l'horodatage actuel.
Ensuite, vous créez la fonction read_all() à la ligne 26. Votre serveur exécutera
read_all() lorsqu'il recevra une requête HTTP de type GET /api/people. La
valeur de retour de read_all() est une liste de dictionnaires contenant des
informations sur une personne.
Jusqu'à présent, votre API REST Flask a un seul point de terminaison. Il est
maintenant temps de construire une API fournissant un accès CRUD complet à
votre structure de personnes. Comme vous vous en souvenez, la définition de
votre API ressemble à ceci :
Ajoutez un bloc de composants avec des schémas pour une seule personne :
# swagger.yml
openapi: 3.0.0
info:
title: "RP Flask REST API"
description: "An API about people and notes"
version: "1.0.0"
servers:
- url: "/api"
components:
schemas:
Person:
type: "object"
required:
- lname
properties:
fname:
type: "string"
lname:
type: "string"
# ...
Pour éviter la duplication du code, vous créez un bloc composant. Pour l'instant,
vous ne sauvegardez que le modèle de données Personne dans le bloc schemas :
Le tiret (-) devant - lname indique que required peut contenir une liste de
propriétés. Toute propriété que vous définissez comme requise doit également
exister dans properties, ce qui inclut les propriétés suivantes :
La clé de type définit la valeur associée à sa clé parent. Pour Person, toutes les
propriétés sont des chaînes de caractères. Vous représenterez ce schéma dans
votre code Python sous la forme d'un dictionnaire (dictionary ) plus tard dans ce
tutoriel.
# ...
paths:
/people:
get:
# ...
post:
operationId: "people.create"
tags:
- People
summary: "Create a person"
requestBody:
description: "Person to create"
required: True
content:
application/json:
schema:
x-body-name: "person"
$ref: "#/components/schemas/Person"
responses:
"201":
description: "Successfully created person"
La structure de post ressemble au schéma existant de get. Une différence est que
vous envoyez également requestBody au serveur. Après tout, vous devez
indiquer à Flask les informations dont il a besoin pour créer une nouvelle
personne. Une autre différence est operationId, que vous définissez comme
people.create.
{
"fname": "Tooth",
"lname": "Fairy"
}
Cet objet JSON ressemble au composant Personne que vous avez défini
précédemment dans swagger.yml et que vous référencez avec $ref dans schema.
Vous utilisez également un code d'état HTTP 201, qui est une réponse positive
indiquant la création d'une nouvelle ressource.
Remarque : si vous souhaitez en savoir plus sur les codes d'état HTTP, vous
pouvez consulter la documentation de Mozilla sur les codes d'état des réponses
http ( HTTP response status codes).
Avec people.create, vous dites à votre serveur de chercher une fonction create()
dans le module people. Ouvrez people.py et ajoutez create() au fichier :
# people.py
# ...
def create(person):
lname = person.get("lname")
fname = person.get("fname", "")
Remarque : le nom de famille d'une personne doit être unique, car vous utilisez
lname comme clé de dictionnaire de PEOPLE. Cela signifie que vous ne pouvez
pas avoir deux personnes avec le même nom de famille dans votre projet pour le
moment.
Si les données du corps de la requête sont valides, vous mettez à jour PEOPLE à
la ligne 13 et répondez avec le nouvel objet et un code HTTP 201 à la ligne 18.
Traiter une personne
Jusqu'à présent, vous êtes en mesure de créer une nouvelle personne et d'obtenir
une liste avec toutes vos personnes. Dans cette section, vous allez mettre à jour
swagger.yml et people.py pour travailler avec un nouveau chemin qui gère une
seule personne existante.
# swagger.yml
# ...
components:
schemas:
# ...
parameters:
lname:
name: "lname"
description: "Last name of the person to get"
in: path
required: True
schema:
type: "string"
paths:
/people:
# ...
/people/{lname}:
get:
operationId: "people.read_one"
tags:
- People
summary: "Read one person"
parameters:
- $ref: "#/components/parameters/lname"
responses:
"200":
description: "Successfully read person"
Comme pour le chemin /people, vous commencez par l'opération get pour le
chemin /people/{lname}. La sous-chaîne {lname} est un caractère de
remplacement pour le nom de famille, que vous devez transmettre en tant que
paramètre d'URL. Ainsi, par exemple, le chemin URL api/people/Ruprecht
contient Ruprecht comme nom de famille.
Remarque : Les paramètres de l'URL sont sensibles à la casse. Cela signifie que
vous devez taper un nom de famille comme Ruprecht avec un R majuscule.
operationId pointe vers une fonction read_one() dans people.py, donc allez dans
ce fichier et créez la fonction manquante :
# people.py
# ...
def read_one(lname):
if lname in PEOPLE:
return PEOPLE[lname]
else:
abort(
404, f"Person with last name {lname} not
found"
)
Lorsque votre application Flask trouve le nom de famille fourni dans PEOPLE,
elle renvoie les données pour cette personne particulière. Sinon, le serveur
renvoie une erreur HTTP 404.
Pour mettre à jour une personne existante, mettez à jour swagger.yml avec ce
code :
# swagger.yml
# ...
paths:
/people:
# ...
/people/{lname}:
get:
# ...
put:
tags:
- People
operationId: "people.update"
summary: "Update a person"
parameters:
- $ref: "#/components/parameters/lname"
responses:
"200":
description: "Successfully updated person"
requestBody:
content:
application/json:
schema:
x-body-name: "person"
$ref: "#/components/schemas/Person"
Avec cette définition de l'opération put, votre serveur attend update() dans
people.py :
# people.py
20# ...
Pour se débarrasser d'une personne dans votre ensemble de données, vous devez
utiliser une opération de suppression :
# swagger.yml
# ...
paths:
/people:
# ...
/people/{lname}:
get:
# ...
put:
# ...
delete:
tags:
- People
operationId: "people.delete"
summary: "Delete a person"
parameters:
- $ref: "#/components/parameters/lname"
responses:
"204":
description: "Successfully deleted person"
# ...
def delete(lname):
if lname in PEOPLE:
del PEOPLE[lname]
return make_response(
f"{lname} successfully deleted", 200
)
else:
abort(
404,
f"Person with last name {lname} not found"
)
Les fichiers people.py et swagger.yml sont complets pour cette partie du tutoriel.
Vous pouvez télécharger les fichiers complets en cliquant sur le lien ci-dessous :
Avec tous les points de terminaison pour gérer les personnes en place, il est
temps d'essayer votre API. Puisque vous avez utilisé Connexion pour connecter
votre projet Flask avec Swagger, la documentation de votre API est prête pour
vous lorsque vous redémarrez votre serveur.
Une fois que vous avez mis à jour les fichiers swagger.yml et people.py pour
compléter la fonctionnalité de l'API de personnes, le système d'interface
utilisateur Swagger sera mis à jour en conséquence et ressemblera à ceci :
Cette interface utilisateur vous permet de voir toute la documentation que vous
avez incluse dans le fichier swagger.yml et d'interagir avec tous les points
d'extrémité URL qui constituent la fonctionnalité CRUD de l'interface
utilisateur.
Dans la deuxième partie de cette série, vous apprendrez à utiliser une base de
données appropriée pour stocker vos données de façon permanente au lieu de
vous fier au stockage en mémoire comme vous l'avez fait ici.
API REST en Python avec Flask, Connexion et
SQLAlchemy - Partie 2
Démo
Mise en route
Conclusion
La plupart des applications Web modernes sont alimentées par une API REST
sous le capot. Ainsi, les développeurs peuvent séparer le code frontal de la
logique dorsale, et les utilisateurs peuvent interagir avec l'interface de manière
dynamique. Dans cette série de didacticiels en trois parties, vous construisez une
API REST à l'aide du framework Web Flask.
Vous avez créé une base avec un projet Flask de base et ajouté des points de
terminaison, que vous connecterez à une base de données SQLite. Vous testez
également votre API avec la documentation Swagger UI API que vous
construisez en cours de route.
Dans la première partie, vous avez utilisé Flask et Connexion pour créer une
API REST fournissant des opérations CRUD à une structure en mémoire
appelée PEOPLE. Ce faisant, vous avez appris comment le module Connexion
vous aide à construire une API REST agréable et une documentation interactive.
Utiliser SQLAlchemy pour enregistrer des objets Python dans votre base
de données
Démo
Dans cette série de tutoriels en trois parties, vous allez créer une API REST pour
conserver la trace des notes des personnes susceptibles de vous rendre visite tout
au long de l'année. Vous allez créer des personnes comme la fée des dents, le
lapin de Pâques et Knecht Ruprecht.
Idéalement, vous voulez être en bons termes avec ces trois personnes. C'est
pourquoi vous leur enverrez des notes, afin d'augmenter vos chances d'obtenir
des cadeaux de valeur de leur part.
Vous pouvez interagir avec votre application en vous appuyant sur la
documentation de l'API. En cours de route, vous construisez également un
frontal de base qui reflète le contenu de votre base de données :
Dans la deuxième partie de cette série, vous allez améliorer le back-end de votre
application en ajoutant une base de données appropriée. De cette façon, vous
ferez persister vos données même lorsque vous redémarrerez votre application :
PEOPLE = {
"Fairy": {
"fname": "Tooth",
"lname": "Fairy",
"timestamp": "2022-10-08 09:15:10",
},
"Ruprecht": {
"fname": "Knecht",
"lname": "Ruprecht",
"timestamp": "2022-10-08 09:15:13",
},
"Bunny": {
"fname": "Easter",
"lname": "Bunny",
"timestamp": "2022-10-08 09:15:27",
}
}
Cette structure de données était pratique pour mettre votre projet en route.
Cependant, toutes les données que vous avez ajoutées avec votre API REST à
PEOPLE ont été perdues lorsque vous avez redémarré votre application.
Dans cette partie, vous allez traduire votre structure de données PEOPLE en une
table de base de données qui ressemblera à ceci :
Ce tutoriel ne vous permettra pas de modifier les points d'extrémité de votre API
REST. Mais les changements que vous ferez dans le back-end seront
significatifs, et vous vous retrouverez avec une base de code beaucoup plus
polyvalente pour vous aider à faire évoluer votre projet Flask à l'avenir.
Pour commencer
Dans cette section, vous allez vérifier le projet d'API REST Flask sur lequel
vous travaillez. Vous voulez vous assurer qu'il est prêt pour les prochaines
étapes de cette série de didacticiels (Flask-Marshmallow).
Pour convertir des types de données complexes à partir de et vers des types de
données Python, vous avez besoin d'un sérialiseur. Pour ce tutoriel, vous
utiliserez Flask-Marshmallow. Flask-Marshmallow étend la librairie
Marshmallow et fournit des fonctionnalités supplémentaires lorsque vous
travaillez avec Flask (Marshmallow).
Idéalement, vous avez suivi la première partie de cette série de tutoriels avant de
poursuivre avec la deuxième partie, que vous lisez en ce moment même. Sinon,
vous pouvez également télécharger le code source de la première partie en
cliquant sur le lien ci-dessous :
rp_flask_api/
│
├── templates/
│ └── home.html
│
├── app.py
├── people.py
└── swagger.yml
Une fois que vous avez mis en place la structure de dossiers de l'API REST de
Flask, vous pouvez poursuivre l'installation des dépendances dont vous aurez
besoin dans cette partie de la série de tutoriels.
Avant de continuer à travailler sur votre projet Flask, c'est une bonne idée de
créer et d'activer un environnement virtuel. De cette façon, vous installez toutes
les dépendances du projet non pas sur l'ensemble du système mais uniquement
dans l'environnement virtuel de votre projet.
Windows
PS> python -m venv venv
PS> .\venv\Scripts\activate
(venv) PS>
Linux
$ python -m venv venv
$ source venv/bin/activate
(venv) $
Remarque : si vous n'avez pas encore étudié la première partie de cette série de
tutoriels, assurez-vous de télécharger le code source en cliquant sur le lien ci-
dessous :
En utilisant l'option sqlalchemy, vous installez également des paquets qui aident
votre application Flask à tirer parti des pouvoirs de SQLAlchemy ( object-
relational model (ORM)).
Lorsque vous exécutez cette application, un serveur web démarre sur le port
8000, qui est le port par défaut utilisé par Flask. Si vous ouvrez un navigateur et
naviguez vers http://localhost:8000
Dans cette section, vous allez ajouter une base de données appropriée à votre
projet Flask pour corriger ces défauts.
# people.py
# ...
PEOPLE = {
"Fairy": {
"fname": "Tooth",
"lname": "Fairy",
"timestamp": get_timestamp(),
},
"Ruprecht": {
"fname": "Knecht",
"lname": "Ruprecht",
"timestamp": get_timestamp(),
},
"Bunny": {
"fname": "Easter",
"lname": "Bunny",
"timestamp": get_timestamp(),
}
}
# ...
Les tables de base de données ont généralement une valeur entière auto-
incrémentée comme clé de recherche des lignes. C'est ce qu'on appelle la clé
primaire. Chaque enregistrement de la table possède une clé primaire dont la
valeur est unique pour l'ensemble de la table. Le fait de disposer d'une clé
primaire indépendante des données stockées dans la table vous donne la liberté
de modifier tout autre champ de la ligne.
Contrairement aux autres moteurs de base de données SQL (other SQL database
engines), SQLite fonctionne avec un seul fichier pour maintenir toutes les
fonctionnalités de la base de données. Par conséquent, pour utiliser la base de
données, un programme doit simplement savoir comment lire et écrire dans un
fichier SQLite.
Le module sqlite3 ( sqlite3 ) intégré à Python vous permet d'interagir avec les
bases de données SQLite sans paquetage externe. Cela rend SQLite
particulièrement utile lors du lancement de nouveaux projets Python.
Après avoir importé le module sqlite3 (sqlite3 module), vous pouvez créer une
nouvelle base de données avec. connect(). Si vous jetez un coup d'oeil à votre
système de fichiers après avoir défini la variable conn, vous remarquerez que
Python a immédiatement créé le fichier de base de données people.db.
Avec conn.execute(), vous exécutez la commande SQL pour créer une table
people avec les colonnes id, lname, fname et timestamp.
Notez que vous incluez une contrainte UNIQUE pour lname. C'est important car
vous utilisez le nom de famille dans votre API REST pour identifier une
personne. Par conséquent, votre base de données doit garantir l'unicité de lname
pour éviter les incohérences dans vos données.
Maintenant que votre base de données existe, vous pouvez y ajouter des données
:
>>> conn.commit()
Une fois que vous êtes connecté à la base de données people.db, vous déclarez
une transaction pour insérer les données people_data dans la table person. La
commande conn.execute() crée des objets sqlite3.Cursor en mémoire. Ce n'est
que lorsque vous exécutez conn.commit() que la transaction se réalise.
Interagir avec la base de données
Contrairement aux langages de programmation comme Python, SQL ne définit
pas comment obtenir les données. SQL décrit les données souhaitées et laisse le
comment au moteur de la base de données.
Une requête SQL permettant d'obtenir toutes les données de votre table de
personnes ressemblerait à ceci :
La ligne 4 utilise le curseur pour exécuter une requête SQL exprimée sous
forme de chaîne.
Cela signifie que votre API attend une variable, lname, dans le chemin du point
de terminaison de l'URL qu'elle utilise pour trouver une seule personne. La
modification du code Python SQLite ci-dessus pour effectuer cette opération
ressemblerait à ceci :
lname = "Fairy"
cur.execute(f"SELECT * FROM person WHERE lname =
'{lname}'")
Image: xkcd.com
Par exemple, imaginez qu'un utilisateur malveillant appelle votre API REST de
cette manière :
L'instruction SQL ci-dessus est valide, et lorsqu'elle est exécutée par la base de
données, elle trouve un enregistrement où lname correspond à 'Fairy'. Ensuite,
elle trouvera le caractère de délimitation de l'instruction SQL ; et ira de l'avant et
abandonnera la table entière. Cela aurait pour effet de détruire votre application.
Vous pouvez protéger votre programme en désinfectant toutes les données que
vous recevez des utilisateurs de votre application. Dans ce contexte, la
désinfection des données signifie que votre programme doit examiner les
données fournies par l'utilisateur pour s'assurer qu'elles ne contiennent rien de
dangereux pour le programme. Cette opération peut être délicate à réaliser
correctement et doit être effectuée partout où les données utilisateur
interagissent avec la base de données.
Il serait bien mieux que ce que vous obteniez en retour pour la personne soit un
objet Python, où chacun des champs est un attribut de l'objet. De cette façon,
vous vous assurez que les objets contiennent les types de valeurs attendus et non
des commandes malveillantes.
Lorsque vous interagissez avec une base de données dans votre code Python,
vous pouvez réfléchir à deux fois avant d'écrire des commandes SQL pures.
Comme vous l'avez appris plus haut, écrire du SQL peut non seulement sembler
peu pratique, mais aussi poser des problèmes de sécurité. Si vous ne voulez pas
trop vous soucier de l'interaction avec la base de données, un paquetage comme
SQLAlchemy peut vous aider.
Dans cette section, vous allez également créer deux modules Python, config.py
et models.py :
2. models.py est le module dans lequel vous allez créer les définitions de
classe de SQLAlchemy et Marshmallow.
# config.py
2
3import pathlib
4import connexion
5from flask_sqlalchemy import SQLAlchemy
6from flask_marshmallow import Marshmallow
7
8basedir = pathlib.Path(__file__).parent.resolve()
9connex_app = connexion.App(__name__,
specification_dir=basedir)
10
11app = connex_app.app
12app.config["SQLALCHEMY_DATABASE_URI"] =
f"sqlite:///{basedir / 'people.db'}"
13app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
14
15db = SQLAlchemy(app)
ma = Marshmallow(app)
La ligne 8 crée la variable basedir qui pointe vers le répertoire dans lequel
le programme est exécuté.
La ligne 9 utilise la variable basedir pour créer l'instance de l'application
Connexion et lui donner le chemin d'accès au répertoire qui contient votre
fichier de spécification.
La ligne 11 crée une variable, app, qui est l'instance Flask initialisée par
Connexion.
Créez un fichier models.py avec une définition de classe SQLAlchemy pour les
données de la table de la base de données des personnes :
# models.py
class Person(db.Model):
__tablename__ = "person"
id = db.Column(db.Integer, primary_key=True)
lname = db.Column(db.String(32), unique=True)
fname = db.Column(db.String(32))
timestamp = db.Column(
db.DateTime, default=datetime.utcnow,
onupdate=datetime.utcnow
)
La ligne 9 définit le champ last name avec une valeur de type chaîne. Ce
champ doit être unique car vous utilisez lname comme identifiant d'une
personne dans une URL d'API REST.
La source, ou temps zéro, est une ligne allant du pôle nord au pôle sud de la
Terre en passant par le Royaume-Uni. Il s'agit du fuseau horaire zéro à partir
duquel tous les autres fuseaux horaires sont décalés. En utilisant cette source
comme temps zéro, vos horodateurs sont décalés par rapport à ce point de
référence standard.
Si vous deviez utiliser des fuseaux horaires locaux comme source d'horodatage,
vous ne pourriez pas effectuer de calculs de date et d'heure sans informations sur
le décalage d'un fuseau horaire local par rapport au temps zéro. Sans les
informations sur la source de l'horodatage, vous ne pourriez pas effectuer de
comparaisons de date et d'heure, ni aucun calcul.
Travailler avec un horodatage basé sur l'UTC est une bonne norme à suivre.
Voici un site d'outils à utiliser pour mieux comprendre ces horodatages ( tool
kit).
L'utilisation de SQLAlchemy vous permet de penser en termes d'objets ayant un
comportement plutôt que de traiter du SQL brut. Cela devient encore plus
bénéfique lorsque les tables de votre base de données deviennent plus grandes et
les interactions plus complexes.
À titre d'exemple, votre classe Person contient un timestamp, qui est une classe
DateTime de Python. Il n'y a pas de définition de DateTime dans JSON, donc
l'horodatage doit être converti en chaîne de caractères pour exister dans une
structure JSON.
Vous utilisez une base de données pour stocker des données persistantes. Avec
SQLAlchemy, vous pouvez aisément communiquer avec votre base de données
depuis votre programme Python. Cependant, vous devez résoudre deux
problèmes :
2. Vous devez vous assurer que les données que vous ajoutez à la base de
données sont valides.
# models.py
class Person(db.Model):
__tablename__ = "person"
id = db.Column(db.Integer, primary_key=True)
lname = db.Column(db.String(32), unique=True)
fname = db.Column(db.String(32))
timestamp = db.Column(
db.DateTime, default=datetime.utcnow,
onupdate=datetime.utcnow
)
class PersonSchema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Person
load_instance = True
sqla_session = db.session
person_schema = PersonSchema()
people_schema = PersonSchema(many=True)
Faites le ménage
Il est maintenant temps de se débarrasser de l'ancienne structure de données
PEOPLE. Cela permettra de s'assurer que toutes les modifications que vous
apportez aux données des personnes sont effectuées sur la base de données
plutôt que sur le dictionnaire obsolète PEOPLE.
# people.py
# ...
Votre base de données est connectée à votre projet Flask mais pas encore à l'API
REST. Potentiellement, vous pourriez utiliser le shell interactif Python pour
ajouter plus de personnes à votre base de données. Mais il sera beaucoup plus
amusant d'améliorer votre API REST et d'utiliser les points de terminaison
existants pour ajouter des données !
Dans cette section, vous allez connecter votre API à la base de données, afin
d'utiliser vos points de terminaison existants avec la base de données pour gérer
les personnes. Si vous voulez récapituler la façon dont vous avez construit les
points de terminaison de l'API, vous pouvez vous rendre dans la première partie
de cette série de tutoriels.
Ensuite, vous allez mettre à jour les fonctions existantes connectées aux points
de terminaison listés ci-dessus afin qu'elles puissent travailler avec la base de
données people.db.
# people.py
# ...
def read_all():
people = Person.query.all()
return people_schema.dump(people)
# ...
Enfin, vous sérialisez vos objets Python avec .dump() et renvoyez les données
de toutes les personnes comme réponse à l'appel API REST.
L'autre fonction de people.py qui ne reçoit que des données est read_one() :
# people.py
# ...
def read_one(lname):
person = Person.query.filter(Person.lname ==
lname).one_or_none()
# ...
Vous utilisez lname dans la méthode .filter() de la requête. Plutôt que d'utiliser
la méthode .all(), vous utilisez la méthode .one_or_none() pour obtenir une
personne ou renvoyer None si aucune correspondance n'est trouvée.
Si une personne est trouvée, alors person contient un objet Person et vous
retournez l'objet sérialisé. Sinon, vous appelez abort() avec une erreur.
Une autre modification de people.py consiste à créer une nouvelle personne dans
la base de données. Cela vous donne l'occasion d'utiliser le PersonSchema de
Marshmallow pour désérialiser une structure JSON envoyée avec la requête
HTTP pour créer un objet Person de SQLAlchemy. Voici une partie du module
people.py mis à jour montrant le gestionnaire pour le point de terminaison URL
REST POST /api/people :
# people.py
# ...
def create(person):
lname = person.get("lname")
existing_person = Person.query.filter(Person.lname ==
lname).one_or_none()
if existing_person is None:
new_person = person_schema.load(person,
session=db.session)
db.session.add(new_person)
db.session.commit()
return person_schema.dump(new_person), 201
else:
abort(406, f"Person with last name {lname} already
exists")
# ...
Au lieu de recevoir seulement un nom de famille comme dans read_one(),
create() reçoit un objet person. Cet objet doit contenir lname, qui ne doit pas
déjà exister dans la base de données. La valeur lname est votre identifiant pour
votre personne, donc vous ne pouvez pas avoir une personne avec le même nom
de famille plusieurs fois dans votre base de données.
Si le nom de famille est unique, vous désérialisez l'objet person en tant que
new_person et l'ajoutez à db.session. Lorsque vous livrez new_person à la base
de données, votre moteur de base de données attribue une nouvelle valeur de clé
primaire et un horodatage basé sur UTC à l'objet. Plus tard, vous verrez le jeu de
données créé dans la réponse de l'API.
Ajustez update() et delete() de la même manière que vous avez ajusté les autres
fonctions :
# people.py
# ...
if existing_person:
update_person = person_schema.load(person,
session=db.session)
existing_person.fname = update_person.fname
db.session.merge(existing_person)
db.session.commit()
return person_schema.dump(existing_person), 201
else:
abort(404, f"Person with last name {lname} not
found")
def delete(lname):
existing_person = Person.query.filter(Person.lname ==
lname).one_or_none()
if existing_person:
db.session.delete(existing_person)
db.session.commit()
return make_response(f"{lname} successfully
deleted", 200)
else:
abort(404, f"Person with last name {lname} not
found")
Avec tous ces changements en place, il est temps de mettre à jour votre code
frontal et d'utiliser Swagger UI pour vérifier si votre base de données fonctionne
comme prévu.
Maintenant que vous avez ajouté la configuration SQLite et défini votre modèle
Person, votre projet Flask contient toutes les informations nécessaires pour
travailler avec votre base de données. Avant de pouvoir afficher les données
dans le front-end, vous devez faire quelques ajustements à app.py :
# app.py
2
3from flask import render_template
4# Remove: import connexion
5import config
6from models import Person
7
8app = config.connex_app
9app.add_api(config.basedir / "swagger.yml")
10
[email protected]("/")
12def home():
13 people = Person.query.all()
14 return render_template("home.html", people=people)
15
16if __name__ == "__main__":
17 app.run(host="0.0.0.0", port=8000, debug=True)
Vous travaillez maintenant avec config.py et models.py. Vous supprimez donc
l'importation à la ligne 4 et ajoutez les importations pour config à la ligne 5 et
Person à la ligne 6.
À la ligne 13, vous interrogez le modèle Person pour obtenir toutes les données
de la table person et les transmettre à render_template() à la ligne 14.
Pour afficher les données des personnes dans le front-end, vous devez ajuster le
modèle home.html :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>RP Flask REST API</title>
</head>
<body>
<h1>
Hello, People!
</h1>
<ul>
{% for person in people %}
<li>{{ person.fname }} {{ person.lname }}</li>
{% endfor %}
</ul>
</body>
</html>
Vous pouvez exécuter votre application avec cette commande dans le répertoire
contenant le fichier app.py :
Lorsque vous exécutez cette application, un serveur Web démarre sur le port
8000, qui est le port que vous avez défini dans app.py. Si vous ouvrez un
navigateur et naviguez vers http://localhost:8000, vous verrez les données de
votre base de données :
Génial ! Votre page d'accueil répertorie les trois personnes qui se trouvent
actuellement dans votre base de données. Enfin, vous pouvez utiliser Swagger
UI pour créer, mettre à jour et supprimer des personnes et voir les changements
se refléter sur la page d'accueil.
Explorez la documentation de votre API
Avec les changements ci-dessus en place, votre base de données est maintenant
fonctionnelle et persiste les données même lorsque vous redémarrez votre
application :
Vous pouvez tirer parti de votre API pour ajouter, mettre à jour et supprimer des
personnes. Grâce aux modifications que vous avez apportées au front-end, vous
êtes en mesure de voir toutes les personnes qui sont actuellement stockées dans
votre base de données.
Lorsque vous redémarrez votre application Flask, vous ne réinitialisez plus les
données. Puisque vous avez maintenant une base de données attachée à votre
projet Flask, vos données sont sauvegardées.
Conclusion
Félicitations, vous avez abordé de nombreux sujets dans ce tutoriel et ajouté des
outils utiles à votre arsenal !
Les compétences que vous avez acquises sont certainement plus complexes que
l'API REST de la première partie, mais cette étape vous a donné des outils
puissants à utiliser pour créer des applications plus complexes. Leur utilisation
vous donnera une longueur d'avance pour créer vos propres applications Web
soutenues par une base de données.
Code source : Cliquez ici pour télécharger le code source gratuit que vous
utiliserez pour continuer à construire une API REST avec le framework web
Flask.
Dans la prochaine partie de cette série, vous allez étendre votre API REST afin
de pouvoir créer, lire, mettre à jour et supprimer des notes. Les notes seront
stockées dans une nouvelle table de base de données. Chaque note sera liée à
une personne, vous ajouterez donc des relations entre les notes et les personnes
dans votre base de données.
La troisième partie sera la dernière de cette série de tutoriels. À la fin, vous
disposerez d'une API REST Flask à part entière avec des tables de base de
données associées en arrière-plan.
Commencer à travailler
Conclusion
La plupart des applications Web modernes sont alimentées par une API REST
sous le capot. Ainsi, les développeurs peuvent séparer le code frontal de la
logique dorsale, et les utilisateurs peuvent interagir avec l'interface de manière
dynamique. Dans cette série de didacticiels en trois parties, vous construisez une
API REST à l'aide du framework Web Flask.
Vous avez créé une base avec un projet Flask de base et ajouté des points de
terminaison, que vous avez connectés à une base de données SQLite. Vous
testez également votre API à l'aide de la documentation Swagger UI API que
vous construisez en cours de route.
Créer des champs "un vers plusieurs" dans votre base de données
Démo
Dans cette série de tutoriels en trois parties, vous construisez une API REST
pour conserver la trace des notes des personnes qui peuvent vous rendre visite
tout au long de l'année. Vous allez créer des personnes comme la fée des dents
(Tooth Fairy,), le lapin de Pâques (Easter Bunny) et Knecht Ruprecht (Knecht
Ruprecht).
Idéalement, vous voulez être en bons termes avec ces trois personnes. C'est
pourquoi vous leur enverrez des notes, afin d'augmenter vos chances d'obtenir
des cadeaux de valeur de leur part.
Actuellement, la base de données people.db ne contient que des données sur les
personnes. Dans cette partie de la série, vous allez ajouter une nouvelle table
pour stocker les notes. Pour relier les notes à une personne, vous allez créer des
relations entre les entrées de la table person et la table note de votre base de
données.
Vous allez amorcer people.db avec un script build_database.py qui contient les
données nécessaires sur les personnes et les notes. Voici un extrait de l'ensemble
de données avec lequel vous allez travailler :
PEOPLE_NOTES = [
{
"lname": "Fairy",
"fname": "Tooth",
"notes": [
("I brush my teeth after each meal.", "2022-
01-06 17:10:24"),
("The other day a friend said I have big
teeth.", "2022-03-05 22:17:54"),
("Do you pay per gram?", "2022-03-05
22:18:10"),
],
},
# ...
]
Vous apprendrez comment ajuster votre base de données SQLite pour mettre en
œuvre les relations. Ensuite, vous serez en mesure de traduire le dictionnaire
PEOPLE_NOTES en données conformes à la structure de votre base de
données.
Enfin, vous afficherez le contenu de votre base de données sur la page d'accueil
de votre application et utiliserez votre API REST Flask pour ajouter, mettre à
jour et supprimer les notes que vous rédigez pour les personnes.
Pour commencer
Idéalement, vous avez suivi la première partie et la deuxième partie de cette
série de tutoriels avant de poursuivre avec la troisième partie, que vous lisez en
ce moment. Sinon, vous pouvez également télécharger le code source de la
deuxième partie en cliquant sur le lien ci-dessous :
rp_flask_api/
│
├── templates/
│ └── home.html
│
├── app.py
├── config.py
├── models.py
├── people.py
└── swagger.yml
Une fois que vous avez mis en place la structure de dossiers de l'API REST de
Flask, vous pouvez vérifier si votre projet Flask fonctionne comme prévu.
Avant de continuer à travailler sur votre projet Flask, c'est une bonne idée de
créer et d'activer un environnement virtuel (virtual environment). De cette façon,
vous installez toutes les dépendances du projet non pas sur l'ensemble du
système mais uniquement dans l'environnement virtuel de votre projet.
Windows PowerShell
PS> python -m venv venv
PS> .\venv\Scripts\activate
(venv) PS>
shell
$ python -m venv venv
$ source venv/bin/activate
(venv) $
Note : Si vous n'avez pas encore travaillé sur la deuxième partie de cette série de
tutoriels, assurez-vous de télécharger le code source en cliquant sur le lien ci-
dessous :
Code source : Cliquez ici pour télécharger le code source gratuit que vous
utiliserez pour continuer à construire une API REST avec le framework web
Flask.
Vous pouvez maintenant vérifier que votre application Flask fonctionne sans
erreur. Exécutez la commande suivante dans le répertoire contenant le fichier
app.py :
Lorsque vous exécutez cette application, un serveur Web démarre sur le port
8000. Si vous ouvrez un navigateur et naviguez vers http://localhost:8000, vous
devriez voir une page avec le titre Hello, People ! affiché :
Parfait, votre application fonctionne parfaitement ! Il est maintenant temps de
penser à la nouvelle structure de la base de données.
PEOPLE_NOTES = [
{
"lname": "Fairy",
"fname": "Tooth",
"notes": [
("I brush my teeth after each meal.", "2022-
01-06 17:10:24"),
("The other day a friend said, I have big
teeth.", "2022-03-05 22:17:54"),
("Do you pay per gram?", "2022-03-05
22:18:10"),
],
},
{
"lname": "Ruprecht",
"fname": "Knecht",
"notes": [
("I swear, I'll do better this year.", "2022-
01-01 09:15:03"),
("Really! Only good deeds from now on!",
"2022-02-06 13:09:21"),
],
},
{
"lname": "Bunny",
"fname": "Easter",
"notes": [
("Please keep the current inflation rate in
mind!", "2022-01-07 22:47:54"),
("No need to hide the eggs this time.", "2022-
04-06 13:03:17"),
],
},
]
Notez que les valeurs de lname dans PEOPLE_NOTES correspondent au
contenu de votre colonne lname dans la table person de votre base de données
people.db.
Chaque personne est associée à plusieurs notes, et chaque note est associée à une
seule personne. Cette hiérarchie de données est connue sous le nom de relation
un-à-plusieurs (one-to-many), où un seul objet parent est lié à plusieurs objets
enfants. Vous verrez plus loin dans ce tutoriel comment cette relation est gérée
dans la base de données avec SQLAlchemy.
Alors que id est la clé primaire de la table, person_id est ce que l'on appelle une
clé étrangère. La clé étrangère donne à chaque entrée de la table des notes la clé
primaire de l'enregistrement de la personne à laquelle elle est associée. Grâce à
cela, SQLAlchemy peut rassembler toutes les notes associées à chaque personne
en reliant la clé primaire person.id à la clé étrangère note.person_id, créant ainsi
une relation.
Le plus grand avantage des tables liées est qu'il n'y a pas de données
redondantes dans la base de données. Il n'y a qu'une seule entrée pour chaque
personne que vous voulez stocker dans la base de données.
Si le lapin de Pâques veut toujours changer les noms, il suffit de modifier une
seule ligne dans la table des personnes, et tout ce qui est lié à cette ligne
profitera immédiatement du changement.
Mais assez parlé de théorie ! Dans la section suivante, vous allez créer les
modèles qui représentent les relations entre les tables de la base de données que
vous avez imaginées.
class Person(db.Model):
__tablename__ = "person"
person_id = db.Column(db.Integer, primary_key=True)
lname = db.Column(db.String(32), unique=True)
fname = db.Column(db.String(32))
timestamp = db.Column(
db.DateTime, default=datetime.utcnow,
onupdate=datetime.utcnow
)
notes = db.relationship(
Note,
backref="person",
cascade="all, delete, delete-orphan",
single_parent=True,
order_by="desc(Note.timestamp)"
)
# ...
Aux lignes 14 à 20, vous créez un nouvel attribut dans la classe Personne
appelé .notes. Ce nouvel attribut .notes est défini dans les lignes de code
suivantes :
Ligne 14 : comme vous l'avez fait pour les autres attributs de la classe,
vous créez ici un nouvel attribut appelé .notes et le rendez égal à une
instance d'un objet appelé db.relationship. Cet objet crée la relation que
vous ajoutez à la classe Person, et il est créé avec tous les paramètres
définis dans les lignes qui suivent.
Maintenant que votre modèle Person possède le nouvel attribut. notes, et que
celui-ci représente la relation un-à-plusieurs avec les objets Note, vous devez
définir un modèle SQLAlchemy pour un objet Note. Puisque vous faites
référence à Note à partir de Person, ajoutez la nouvelle classe Note juste avant la
définition de la classe Person :
# models.py
2
3from datetime import datetime
4from config import db, ma
5
6class Note(db.Model):
7 __tablename__ = "note"
8 id = db.Column(db.Integer, primary_key=True)
9 person_id = db.Column(db.Integer,
db.ForeignKey("person.id"))
10 content = db.Column(db.String, nullable=False)
11 timestamp = db.Column(
12 db.DateTime, default=datetime.utcnow,
onupdate=datetime.utcnow
13 )
14
15class Person(db.Model):
16 # ...
17
18# ...
La classe Note définit les attributs qui composent une note, comme vous
l'avez appris dans votre exemple de table de base de données de notes ci-
dessus. Avec ce code, vous définissez les attributs :
Maintenant que vous avez mis à jour la classe Personne et créé le modèle de
Note, passez à la mise à jour de la base de données.
Maintenant que vous avez mis à jour Person et créé le modèle Note, vous allez
les utiliser pour reconstruire la base de données people.db. Pour ce faire, créez
un script Python d'aide nommé build_database.py :
# build_database.py
PEOPLE_NOTES = [
{
"lname": "Fairy",
"fname": "Tooth",
"notes": [
("I brush my teeth after each meal.", "2022-
01-06 17:10:24"),
("The other day a friend said, I have big
teeth.", "2022-03-05 22:17:54"),
("Do you pay per gram?", "2022-03-05
22:18:10"),
],
},
{
"lname": "Ruprecht",
"fname": "Knecht",
"notes": [
("I swear, I'll do better this year.", "2022-
01-01 09:15:03"),
("Really! Only good deeds from now on!",
"2022-02-06 13:09:21"),
],
},
{
"lname": "Bunny",
"fname": "Easter",
"notes": [
("Please keep the current inflation rate in
mind!", "2022-01-07 22:47:54"),
("No need to hide the eggs this time.", "2022-
04-06 13:03:17"),
],
},
]
with app.app_context():
db.drop_all()
db.create_all()
for data in PEOPLE_NOTES:
new_person = Person(lname=data.get("lname"),
fname=data.get("fname"))
for content, timestamp in data.get("notes", []):
new_person.notes.append(
Note(
content=content,
timestamp=datetime.strptime(timestamp,
"%Y-%m-%d %H:%M:%S"),
)
)
db.session.add(new_person)
db.session.commit()
Dans le code ci-dessus, vous alimentez la base de données de votre projet avec
le contenu de PEOPLE_NOTES. Vous utilisez db dans votre module de
configuration afin que Python sache comment traiter les données et les
transmettre aux tables et cellules correspondantes de la base de données.
Maintenant que votre base de données contient des données avec lesquelles vous
pouvez travailler, vous pouvez commencer à afficher les données à la fois dans
le front-end et dans votre API REST.
Mettez à jour le fichier home.html dans votre dossier templates/ pour accéder
aux notes d'une personne :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>RP Flask REST API</title>
</head>
<body>
<h1>
Hello, People!
</h1>
{% for person in people %}
<h2>{{ person.fname }} {{ person.lname }}</h2>
<ul>
{% for note in person.notes %}
<li>
{{ note.content }}
</li>
{% endfor %}
</ul>
{% endfor %}
</body>
</html>
http://localhost:8000/api/people :
Vous recevez la collection de personnes sans aucune erreur. Cependant, il n'y a
pas de notes dans les données que vous recevez.
# people.py
2
3# ...
4
5def read_all():
6 people = Person.query.all()
7 person_schema = PersonSchema(many=True)
8 return person_schema.dump(people)
9
10# ...
Person.query.all()
Cet appel a fonctionné avec succès dans le front-end pour montrer les notes pour
chaque personne. Cela montre que PersonSchema est le coupable le plus
probable.
# ...
class PersonSchema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Person
load_instance = True
sqla_session = db.session
include_relationships = True
# ...
class Note(db.Model):
# ...
class NoteSchema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Note
load_instance = True
sqla_session = db.session
include_fk = True
class Person(db.Model):
# ...
class PersonSchema(ma.SQLAlchemyAutoSchema):
# ...
note_schema = NoteSchema()
# ...
Vous faites référence à Note à partir de NoteSchema, vous devez donc placer
NoteSchema sous la définition de votre classe Note pour éviter les erreurs. Vous
instanciez également NoteSchema pour créer un objet auquel vous ferez
référence ultérieurement.
Comme votre modèle Note contient une clé étrangère, vous devez définir
include_fk sur True. Sinon, Marshmallow ne reconnaîtrait pas person_id
pendant le processus de sérialisation.
# models.py
# ...
class PersonSchema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Person
load_instance = True
sqla_session = db.session
include_relationships = True
Dans la section suivante, vous allez étendre votre API REST Flask pour créer,
lire, mettre à jour et supprimer une seule note.
Vous avez mis à jour les modèles SQLAlchemy et les avez utilisés pour lire la
base de données people.db. Vos notes sont disponibles en tant que schéma
imbriqué dans People. Vous recevez la liste des notes lorsque vous demandez
une collection de personnes ou une personne particulière :
Action HTTP Verb URL Path Description
Read GET /api/people Read a collection of people.
Read GET /api/people/<lname> Read a particular person.
Bien que vous puissiez lire les notes sur les points de terminaison indiqués dans
le tableau ci-dessus, il n'y a actuellement aucun moyen de lire une seule note ou
de gérer toutes les notes dans votre API REST.
Vous pouvez passer à la première partie pour récapituler comment vous avez
construit les points de terminaison existants de votre API REST. Dans cette
section du tutoriel, vous allez ajouter des points d'accès supplémentaires pour
fournir des fonctionnalités de création, de lecture, de mise à jour et de
suppression des notes :
Vous allez commencer par ajouter la fonctionnalité de lecture d'une seule note.
Pour ce faire, vous allez ajuster votre fichier de configuration Swagger qui
contient vos définitions d'API.
Lire une seule note
Actuellement, vous êtes en mesure de recevoir toutes les notes d'une personne
lorsque vous demandez des données sur cette personne en particulier. Pour
obtenir des informations sur une note, vous ajouterez un autre point de
terminaison.
# swagger.yml
# ...
components:
schemas:
# ...
parameters:
lname:
# ...
note_id:
name: "note_id"
description: "ID of the note"
in: path
required: true
schema:
type: "integer"
# ...
Le note_id dans les paramètres fera partie de vos endpoints pour identifier quelle
note vous voulez traiter.
Continuez à éditer swagger.yml et ajoutez les données pour le point final pour
lire une seule note :
# swagger.yml
# ...
paths:
/people:
# ...
/people/{lname}:
# ...
/notes/{note_id}:
get:
operationId: "notes.read_one"
tags:
- Notes
summary: "Read one note"
parameters:
- $ref: "#/components/parameters/note_id"
responses:
"200":
description: "Successfully read one note"
# notes.py
def read_one(note_id):
note = Note.query.get(note_id)
Bien que vous n'utilisiez pas encore make_response() et db, vous pouvez aller de
l'avant et les ajouter à vos importations. Vous les utiliserez plus tard lorsque
vous écrirez dans la base de données.
Cette fois, vous commencez par créer les fonctions dans notes.py, avant de créer
les opérations dans swagger.yml.
# notes.py
# ...
if existing_note:
update_note = note_schema.load(note,
session=db.session)
existing_note.content = update_note.content
db.session.merge(existing_note)
db.session.commit()
return note_schema.dump(existing_note), 201
else:
abort(404, f"Note with ID {note_id} not found")
def delete(note_id):
existing_note = Note.query.get(note_id)
if existing_note:
db.session.delete(existing_note)
db.session.commit()
return make_response(f"{note_id} successfully
deleted", 204)
else:
abort(404, f"Note with ID {note_id} not found")
En revanche, vous devez seulement connaître l'ID de la note dont vous voulez
vous débarrasser lorsque vous appelez delete().
Ensuite, créez deux opérations dans swagger.yml qui font référence à
notes.update et notes.delete :
# swagger.yml
# ...
paths:
/people:
# ...
/people/{lname}:
# ...
/notes/{note_id}:
get:
# ...
put:
tags:
- Notes
operationId: "notes.update"
summary: "Update a note"
parameters:
- $ref: "#/components/parameters/note_id"
responses:
"200":
description: "Successfully updated note"
requestBody:
content:
application/json:
schema:
x-body-name: "note"
type: "object"
properties:
content:
type: "string"
delete:
tags:
- Notes
operationId: "notes.delete"
summary: "Delete a note"
parameters:
- $ref: "#/components/parameters/note_id"
responses:
"204":
description: "Successfully deleted note"
Vous avez maintenant créé les points de terminaison pour travailler avec des
notes existantes. Ensuite, vous allez ajouter le point final pour créer une note.
Créer une note pour une personne
Jusqu'à présent, vous pouvez lire, mettre à jour et supprimer une seule note. Ce
sont des actions que vous pouvez effectuer sur des notes existantes. Il est
maintenant temps d'ajouter la fonctionnalité à votre API REST pour créer
également une nouvelle note.
# notes.py
# ...
def create(note):
person_id = note.get("person_id")
person = Person.query.get(person_id)
if person:
new_note = note_schema.load(note,
session=db.session)
person.notes.append(new_note)
db.session.commit()
return note_schema.dump(new_note), 201
else:
abort(
404,
f"Person not found for ID: {person_id}"
)
Une note a toujours besoin d'une personne à qui elle appartient. C'est pourquoi
vous devez travailler avec le modèle Person lorsque vous créez une nouvelle
note.
Bien que vous travailliez dans ce cas avec la table de la base de données des
personnes, SQLAlchemy se chargera d'ajouter la note à la table note.
# swagger.yml
# ...
paths:
/people:
# ...
/people/{lname}:
# ...
/notes:
post:
operationId: "notes.create"
tags:
- Notes
summary: "Create a note associated with a person"
requestBody:
description: "Note to create"
required: True
content:
application/json:
schema:
x-body-name: "note"
type: "object"
properties:
person_id:
type: "integer"
content:
type: "string"
responses:
"201":
description: "Successfully created a note"
/notes/{note_id}:
# ...
Vous pouvez également remarquer que tous les champs du modèle Note ne sont
pas présents dans le schéma du composant. Ce n'est pas grave, car vous
n'utiliserez ce schéma que pour enregistrer de nouvelles notes. Pour chaque note,
l'identifiant et l'horodatage seront définis automatiquement.
Maintenant que tous les points de terminaison pour la gestion des notes sont en
place, il est temps de jeter un coup d'oeil à la documentation de votre API.
Dans ce tutoriel, vous avez ajusté votre base de données SQLite pour mettre en
œuvre des relations. Ensuite, vous avez traduit le dictionnaire PEOPLE_NOTES
en données conformes à la structure de votre base de données, et vous avez
transformé votre API REST Flask en une application Web de prise de notes.
Savoir comment construire et utiliser les relations dans une base de données
vous donne un outil puissant pour résoudre de nombreux problèmes difficiles. Il
existe d'autres relations que l'exemple one-to-many de ce tutoriel. Les autres
relations courantes sont de type un à un, plusieurs à plusieurs et plusieurs à un.
Toutes ont leur place dans votre ceinture d'outils, et SQLAlchemy peut vous
aider à les aborder toutes !
Vous avez construit avec succès une API REST pour garder la trace des notes
des personnes qui peuvent vous rendre visite tout au long de l'année. Votre base
de données contient des personnes comme la fée des dents, le lapin de Pâques et
Knecht Ruprecht. En ajoutant des notes, vous pouvez garder une trace de vos
bonnes actions et espérer recevoir des cadeaux de valeur de leur part.
Code source : Cliquez ici pour télécharger le code source gratuit que vous
utiliserez pour finir de construire une API REST avec le framework web Flask.
Avez-vous ajouté une personne ou une note spéciale à votre projet d'API REST
Flask ? Faites-le savoir à la communauté Real Python dans les commentaires ci-
dessous.