Files
datacat/documentation/api-reference.md
z3n 921a6e652b feat: initial scaffold — MVP catalogue de données d'API
- Backend NestJS : CRUD api_entries + categories, upload YAML multi-fichiers,
  génération docs AsyncAPI (@asyncapi/cli@6.0.0) et OpenAPI (redocly)
- Fix: route wildcard GET /api/apis/:id/*path pour servir les assets statiques
  (CSS/JS) générés par AsyncAPI HTML template (contournement bug path-to-regexp v8)
- Frontend Angular 19 : pages catalog, browse, api-detail, doc-viewer, upload (DSFR)
- Seeder de données de démo (idempotent)
- Docker Compose dev + Dockerfiles + manifests K8s
- Documentation : README, architecture, référence API REST

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>
2026-05-22 08:42:54 +00:00

7.6 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 le titre et la description (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": "My API",
      "version": "1.0.0",
      "description": "...",
      "type": "OPENAPI",
      "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 ni htmlPath).


GET /api/apis/:id

Retourne le détail complet d'une entrée.

Réponse 200

{
  "id": "uuid",
  "title": "My API",
  "version": "1.0.0",
  "description": "...",
  "type": "OPENAPI",
  "yamlContent": "openapi: '3.0.0'\n...",
  "htmlPath": "/app/docs-output/uuid/index.html",
  "status": "GENERATED",
  "errorMessage": null,
  "categoryId": "uuid-or-null",
  "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)

{
  "title": "New title",
  "version": "2.0.0",
  "description": "Updated description",
  "categoryId": "uuid-or-null"
}

Réponse 200ApiEntry 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 200ApiEntry 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 200text/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="<title>.yaml"
  • Corps : contenu YAML brut

Réponse 404 — entrée introuvable


Upload (/api/uploads)

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)
title string Oui Titre de l'API
version string Oui Version (ex: 1.0.0)
description string Non Description libre
type ASYNCAPI | OPENAPI Non Type (détecté automatiquement si absent)
categoryId UUID Non Catégorie parente

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 bundle (AsyncAPI).

Réponse 201ApiEntry créé avec status: "PENDING"

Réponse 400

  • Aucun fichier fourni
  • title ou version 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

{
  "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 200CategoryBrowseResponse

{
  "category": null,
  "breadcrumb": [],
  "subcategories": [
    {
      "id": "uuid",
      "name": "Infrastructure",
      "description": "...",
      "parentId": null,
      "orderIndex": 0,
      "subcategoryCount": 2,
      "apiCount": 5,
      "createdAt": "...",
      "updatedAt": "..."
    }
  ],
  "apis": [
    {
      "id": "uuid",
      "title": "API sans catégorie",
      ...
    }
  ]
}

GET /api/categories/browse/:id

Navigation dans une catégorie : retourne ses sous-catégories et ses APIs directes.

Réponse 200CategoryBrowseResponse

{
  "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 200Category

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 201Category 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 200Category mise à jour

Réponse 404 — catégorie introuvable


DELETE /api/categories/:id

Supprime une catégorie. Les APIs et sous-catégories enfants sont désassociées (categoryId/parentId mis à null).

Réponse 204 — succès (pas de corps)

Réponse 404 — catégorie introuvable


Codes d'erreur communs

Code Description
400 Requête invalide (champ manquant, format incorrect)
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)