- Shared types : ajout isCurrent sur ApiEntry et ApiEntryListItem - Backend entity : colonne is_current (boolean, default true) - Backend service : isCurrent calculé à la création, setCurrent() marque une version comme courante (siblings → false) - Backend controller : POST /api/apis/:id/set-current - Frontend ApiService : méthode setCurrent() - Browse/upload : affichage badge "Courante" via isCurrent - Seeder : données de démo mises à jour - Documentation : api-reference, architecture, local-setup, CLAUDE.md Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
11 KiB
Référence API — Datacat
Base URL en développement : http://localhost:3010
Toutes les routes JSON retournent Content-Type: application/json.
Health
GET /health
Vérifie que le serveur est opérationnel.
Réponse 200
{ "status": "ok" }
APIs (/api/apis)
GET /api/apis
Liste les entrées avec filtres optionnels et pagination.
Query parameters
| Paramètre | Type | Défaut | Description |
|---|---|---|---|
search |
string | — | Recherche dans name, provider, description, contacts (case-insensitive) |
type |
ASYNCAPI | OPENAPI |
— | Filtre par type |
categoryId |
UUID | — | Filtre par catégorie |
page |
number | 1 |
Page (min 1) |
limit |
number | 20 |
Taille de page (min 1, max 100) |
Réponse 200
{
"items": [
{
"id": "uuid",
"title": "Consulter Petstore",
"name": "Petstore",
"convention": "CONSULTER",
"version": "1.0.0",
"description": "...",
"type": "OPENAPI",
"provider": "Équipe Produit",
"status": "GENERATED",
"categoryId": "uuid-or-null",
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-01-01T00:00:00.000Z"
}
],
"total": 42,
"page": 1,
"limit": 20
}
itemscontient desApiEntryListItem(sansyamlContent,htmlPath, contacts niversionMajor/Minor/Patch).
GET /api/apis/:id
Retourne le détail complet d'une entrée.
Réponse 200
{
"id": "uuid",
"title": "Consulter Petstore",
"name": "Petstore",
"convention": "CONSULTER",
"version": "1.0.0",
"versionMajor": 1,
"versionMinor": 0,
"versionPatch": 0,
"description": "...",
"type": "OPENAPI",
"provider": "Équipe Produit",
"yamlContent": "openapi: '3.0.0'\n...",
"htmlPath": "/app/docs-output/uuid/index.html",
"status": "GENERATED",
"errorMessage": null,
"categoryId": "uuid-or-null",
"contactFunctionalName": "Alice Martin",
"contactFunctionalEntity": "DSI",
"contactFunctionalEmail": "alice@example.com",
"contactTechnicalName": "Bob Dupont",
"contactTechnicalEntity": "Équipe Backend",
"contactTechnicalEmail": "bob@example.com",
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-01-01T00:00:00.000Z"
}
Réponse 404 — entrée introuvable
PATCH /api/apis/:id
Met à jour les métadonnées d'une entrée (champs éditables par l'utilisateur).
Body JSON (tous les champs sont optionnels)
{
"convention": "CONSULTER",
"name": "Nouveau nom",
"provider": "Équipe X",
"versionMajor": 2,
"versionMinor": 0,
"versionPatch": 0,
"description": "Description mise à jour",
"categoryId": "uuid-or-null",
"contactFunctionalName": "...",
"contactFunctionalEntity": "...",
"contactFunctionalEmail": "...",
"contactTechnicalName": "...",
"contactTechnicalEntity": "...",
"contactTechnicalEmail": "..."
}
Réponse 200 — ApiEntry complet mis à jour
Réponse 404 — entrée introuvable
DELETE /api/apis/:id
Supprime une entrée.
Réponse 204 — succès (pas de corps)
Réponse 404 — entrée introuvable
POST /api/apis/:id/regenerate
Relance la génération de documentation pour une entrée existante.
Remet le statut à PENDING et déclenche DocsGenerationService.generate() en arrière-plan.
Réponse 200 — ApiEntry avec status: "PENDING"
Réponse 404 — entrée introuvable
GET /api/apis/:id/docs
Retourne le fichier HTML de documentation généré.
Réponse 200 — text/html (fichier statique servi via res.sendFile)
Réponse 404
- Entrée introuvable
- Documentation pas encore générée (
htmlPathest null)
GET /api/apis/:id/yaml
Télécharge le fichier YAML source.
Réponse 200
Content-Type: application/x-yamlContent-Disposition: attachment; filename="<name>.yaml"- Corps : contenu YAML brut
Réponse 404 — entrée introuvable
Upload (/api/uploads)
POST /api/uploads/validate
Valide 1 à 20 fichiers YAML sans créer d'entrée en base. Utilisé pour la validation en temps réel lors de l'upload.
Content-Type : multipart/form-data
Champs du formulaire
| Champ | Type | Requis | Description |
|---|---|---|---|
files |
file (1 à 20) | Oui | Fichiers YAML (.yaml ou .yml) |
Réponse 200
{
"valid": true,
"type": "OPENAPI",
"mainFile": "petstore.yaml",
"name": "Petstore",
"versionMajor": 1,
"versionMinor": 0,
"versionPatch": 0,
"description": "A sample API",
"errors": []
}
En cas d'erreur :
{
"valid": false,
"type": null,
"mainFile": null,
"name": null,
"versionMajor": null,
"versionMinor": null,
"versionPatch": null,
"description": null,
"errors": [
{ "file": "api.yaml", "message": "erreur de syntaxe YAML — unexpected token" }
]
}
POST /api/uploads
Crée une nouvelle entrée à partir d'un ou plusieurs fichiers YAML. Lance la génération de documentation en arrière-plan (fire-and-forget).
Content-Type : multipart/form-data
Champs du formulaire
| Champ | Type | Requis | Description |
|---|---|---|---|
files |
file (1 à 20) | Oui | Fichiers YAML (.yaml ou .yml) |
convention |
CONSULTER | ENREGISTRER | ETRE_NOTIFIE |
Oui | Convention d'échange |
name |
string | Oui | Nom de l'API |
provider |
string | Oui | Fournisseur / équipe responsable |
versionMajor |
string (number) | Non | Version majeure (défaut: 0) |
versionMinor |
string (number) | Non | Version mineure (défaut: 0) |
versionPatch |
string (number) | Non | Version patch (défaut: 0) |
description |
string | Non | Description libre |
type |
ASYNCAPI | OPENAPI |
Non | Type (détecté automatiquement si absent) |
categoryId |
UUID | Non | Catégorie parente |
contactFunctionalName |
string | Non | Contact métier — nom |
contactFunctionalEntity |
string | Non | Contact métier — entité |
contactFunctionalEmail |
string | Non | Contact métier — email |
contactTechnicalName |
string | Non | Contact technique — nom |
contactTechnicalEntity |
string | Non | Contact technique — entité |
contactTechnicalEmail |
string | Non | Contact technique — email |
Détection automatique du type
Le type est détecté à partir du contenu YAML :
- Présence de
openapi:en début de ligne →OPENAPI - Présence de
asyncapi:en début de ligne →ASYNCAPI
Si plusieurs fichiers sont fournis, le fichier contenant la clé racine est considéré comme le fichier principal.
Les autres sont bundlés via redocly bundle (OpenAPI) ou @asyncapi/bundler (AsyncAPI).
Réponse 201 — ApiEntry créé avec status: "PENDING"
Réponse 400
- Aucun fichier fourni
nameouconventionmanquant- Fichier non YAML
- Type non détectable et non fourni
- Aucun fichier principal trouvé dans un upload multi-fichiers
Catégories (/api/categories)
GET /api/categories
Retourne toutes les catégories, triées par order_index puis name.
Réponse 200
{
"items": [
{
"id": "uuid",
"name": "Infrastructure",
"description": "...",
"parentId": null,
"orderIndex": 0,
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-01-01T00:00:00.000Z"
}
]
}
GET /api/categories/browse
Navigation à la racine : retourne les catégories de premier niveau et les APIs sans catégorie.
Réponse 200 — CategoryBrowseResponse
{
"category": null,
"breadcrumb": [],
"subcategories": [
{
"id": "uuid",
"name": "Infrastructure",
"description": "...",
"parentId": null,
"orderIndex": 0,
"subcategoryCount": 2,
"apiCount": 5,
"createdAt": "...",
"updatedAt": "..."
}
],
"apis": [
{
"id": "uuid",
"title": "Consulter API sans catégorie",
"name": "API sans catégorie",
"convention": "CONSULTER",
"version": "1.0.0",
"provider": "...",
"status": "GENERATED",
"categoryId": null,
"..."
}
]
}
GET /api/categories/browse/:id
Navigation dans une catégorie : retourne ses sous-catégories et ses APIs directes.
Réponse 200 — CategoryBrowseResponse
{
"category": { "id": "uuid", "name": "Infrastructure", ... },
"breadcrumb": [
{ "id": "parent-uuid", "name": "Catégorie parente", ... },
{ "id": "uuid", "name": "Infrastructure", ... }
],
"subcategories": [ ... ],
"apis": [ ... ]
}
Réponse 404 — catégorie introuvable
GET /api/categories/:id
Retourne le détail d'une catégorie.
Réponse 200 — Category
Réponse 404 — catégorie introuvable
POST /api/categories
Crée une nouvelle catégorie.
Body JSON
{
"name": "Infrastructure",
"description": "APIs d'infrastructure",
"parentId": "uuid-or-null",
"orderIndex": 0
}
| Champ | Type | Requis |
|---|---|---|
name |
string | Oui |
description |
string | Non |
parentId |
UUID | Non |
orderIndex |
number | Non (défaut: 0) |
Réponse 201 — Category créée
PATCH /api/categories/:id
Met à jour une catégorie.
Body JSON (tous les champs sont optionnels)
{
"name": "Nouveau nom",
"description": "...",
"parentId": "uuid-or-null",
"orderIndex": 1
}
Réponse 200 — Category mise à jour
Réponse 404 — catégorie introuvable
DELETE /api/categories/:id
Supprime une catégorie.
Réponse 204 — succès (pas de corps)
Réponse 400 — le dossier contient des APIs ou des sous-dossiers (vérification applicative avant suppression)
Réponse 404 — catégorie introuvable
Codes d'erreur communs
| Code | Description |
|---|---|
| 400 | Requête invalide (champ manquant, format incorrect, suppression non vide) |
| 404 | Ressource introuvable |
| 500 | Erreur interne serveur |
Format d'erreur
{
"statusCode": 404,
"message": "API entry <uuid> not found",
"error": "Not Found"
}
Statuts d'une entrée API
| Statut | Description |
|---|---|
PENDING |
Entrée créée, génération de doc en cours |
GENERATED |
Documentation HTML disponible |
ERROR |
La génération a échoué (voir errorMessage) |
Conventions d'échange
| Convention | Label affiché |
|---|---|
CONSULTER |
Consulter |
ENREGISTRER |
Enregistrer |
ETRE_NOTIFIE |
Être notifié |