API JSON protégée¶
Objectif : exposer le catalogue en JSON à des clients, derrière un jeton d'authentification.
Ce que vous allez apprendre : renvoyer du JSON avec Response.json, et protéger la route par un jeton Authorization: Bearer … lu via request.header(...). Sans jeton valide, l'API répond 401.
Le catalogue est complet côté navigateur : lister et créer.
Nous l'exposons maintenant à des clients (front JavaScript, script, autre service) sous forme d'API JSON protégée, en réutilisant la jointure du premier palier.
Documentations
Pour bien comprendre ce palier :
| Document | Ce qu'il apporte |
|---|---|
| API JSON légère | la façon canonique d'exposer du JSON dans Forge |
| L'objet Request | l'accesseur header(...), dont Authorization |
| L'objet Response | Response.json(data, status=…) : données et code HTTP |
Contrôleurs
Ajoutez le jeton et la méthode dans mvc/controllers/article_controller.py :
API_TOKEN = "forge-demo-token"
class ArticleController(BaseController):
# … index / create / store inchangés …
@staticmethod
def api_index(request: Request) -> Response:
authorization = request.header("Authorization") or ""
if authorization != f"Bearer {API_TOKEN}":
return Response.json({"error": "Jeton manquant ou invalide."}, status=401)
articles = fetch_all(SELECT_ARTICLES_WITH_CATEGORY)
return Response.json({"articles": articles})
| Élément | Rôle |
|---|---|
request.header("Authorization") |
Lit l'en-tête envoyé par le client ; on le compare à Bearer <jeton> (convention des API à jeton). |
Refus → status=401 |
Si le jeton ne correspond pas, on renvoie immédiatement : on ne lit même pas la base. La sécurité vient avant la donnée. |
fetch_all(SELECT_ARTICLES_WITH_CATEGORY) |
Réutilise la jointure du premier palier ; les dictionnaires sont directement sérialisables. |
Le jeton est ici une constante de démonstration.
Une vraie application le garderait secret (hors du code versionné) et le renouvellerait.
Routes
Déclarez la route /article/api-index dans mvc/routes.py :
# mvc/routes.py
from core.http.router import Router
from mvc.controllers.home_controller import HomeController
from mvc.controllers.article_controller import ArticleController
router = Router()
with router.group("", public=True) as public:
public.add("GET", "/", HomeController.index, name="home-index")
public.add("GET", "/article", ArticleController.index, name="article-index")
public.add("GET", "/article/create", ArticleController.create, name="article-create")
public.add("POST", "/article/store", ArticleController.store, name="article-store")
public.add("GET", "/article/api-index", ArticleController.api_index, name="article-api_index")
Tests
Sans jeton, la requête est refusée :
curl -k https://localhost:8000/article/api-index
# {"error": "Jeton manquant ou invalide."} (HTTP 401)
Avec le jeton de démonstration, l'API renvoie les données :
À retenir
Response.json(data, status=…)renvoie données et code HTTP.request.header(...)donne accès aux en-têtes, dontAuthorization.- On vérifie l'autorisation avant de produire la donnée ; un refus, c'est
401.
Vous avez parcouru les trois paliers du niveau avancé. Place au bilan.