# 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** ```json { "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** ```json { "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 } ``` > `items` contient des `ApiEntryListItem` (sans `yamlContent`, `htmlPath`, contacts ni `versionMajor/Minor/Patch`). --- ### `GET /api/apis/:id` Retourne le détail complet d'une entrée. **Réponse 200** ```json { "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) ```json { "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 (`htmlPath` est null) --- ### `GET /api/apis/:id/yaml` Télécharge le fichier YAML source. **Réponse 200** - `Content-Type: application/x-yaml` - `Content-Disposition: attachment; filename=".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** ```json { "valid": true, "type": "OPENAPI", "mainFile": "petstore.yaml", "name": "Petstore", "versionMajor": 1, "versionMinor": 0, "versionPatch": 0, "description": "A sample API", "errors": [] } ``` En cas d'erreur : ```json { "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 - `name` ou `convention` manquant - 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** ```json { "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` ```json { "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` ```json { "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** ```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) ```json { "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** ```json { "statusCode": 404, "message": "API entry 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é |