Skip to content

Document OpenAPI ​

Chaque instance décrit sa propre API dans un document OpenAPI 3.1, servi à l’adresse :

GET <PUBLIC_BASE_URL>/api/v1/openapi.json
GET <PUBLIC_BASE_URL>/api/v1/openapi.json?lang=fr

La route est publique : ni session ni clé ne sont nécessaires pour la lire. Les textes (résumés, descriptions) sont en anglais par défaut et en français avec ?lang=fr. L’instance met le document en cache cinq minutes.

La référence de cette documentation est générée depuis ce même document : les deux ne divergent jamais.

D’où il est généré ​

Le document n’est pas écrit à la main. L’instance tient un registre de ses routes ; pour chacune, le registre désigne les schémas de validation que la route utilise réellement pour lire ses paramètres, son corps et ses réponses. Le document en est dérivé au démarrage, dans le dialecte qu’OpenAPI 3.1 parle nativement, JSON Schema 2020-12.

Conséquences :

  • un champ qui figure dans le document est un champ que la route accepte ou renvoie, avec ses vraies contraintes (minimum, maxLength, enum…) ;
  • les schémas sont inclus en ligne dans chaque opération, et non partagés sous components/schemas : le même objet (un workflow, une exécution) apparaît en entier partout où il sert. Les générateurs de code s’en accommodent ; les types produits sont seulement plus longs ;
  • info.title porte la marque de l’instance et info.version sa version logicielle ;
  • servers[0].url est l’adresse publique de l’instance quand elle est configurée, / sinon (relative à l’endroit d’où vous avez lu le document) ;
  • quelques routes servies par l’instance sont volontairement absentes : le WebSocket de l’interface et les redirections OAuth, qu’aucun client HTTP n’appelle directement.

L’authentification dans le document ​

Deux schémas de sécurité sont déclarés sous components.securitySchemes :

SchémaTypeSens
sessionCookieapiKey dans le cookie sessionLa session posée par POST /api/v1/auth/login
apiKeyoauth2Une clé d’API envoyée en Authorization: Bearer mk_…

La clé d’API est déclarée en oauth2 uniquement parce que c’est ainsi qu’OpenAPI nomme des portées : la table scopes du schéma liste toutes les portées qu’une clé peut porter, et chaque opération indique celle qu’elle exige. Il n’y a ni point de terminaison de jeton ni flux d’autorisation : la clé est le jeton. Un client qui suivrait le schéma oauth2 à la lettre ne fonctionnera pas ; configurez-le plutôt pour envoyer un jeton porteur.

Le security de chaque opération dit qui peut l’appeler : [{ "sessionCookie": [] }, { "apiKey": ["workflows:read"] }] pour une route ouverte aux clés, [{ "sessionCookie": [] }] pour une route réservée à la session, [] pour une route publique ou autorisée par un jeton dans son URL.

Les extensions ​

Trois extensions x- portent ce qu’OpenAPI standard n’a pas de mot pour dire :

ExtensionOùSens
x-required-scopeOpérationLa portée qu’une clé d’API doit couvrir, par exemple "workflows:write". Absente sur les routes réservées à la session, publiques ou à jeton. Voir Portées.
x-idempotency-keyOpérationtrue quand l’opération accepte un en-tête Idempotency-Key. L’en-tête est aussi déclaré parmi les paramètres de l’opération. Voir Idempotence.
x-error-codesOpérationLes codes d’erreur propres à l’opération, par exemple ["workflow.not_found", "workflow.not_publishable"]. Les codes communs (request.bad_request, auth.unauthenticated, api_key.*) sont implicites. Voir Erreurs.

Chaque opération a aussi un operationId stable, dérivé de sa méthode et de son chemin : GET /api/v1/workflows/{id} est getWorkflowsById, POST /api/v1/workflows est postWorkflows. Les générateurs de code s’en servent pour nommer les méthodes.

Quand une opération a un exemple, il est attaché au corps de requête (requestBody.content.*.example) et à sa première réponse de succès.

Importer le document ​

Dans un client d’API (Postman, Insomnia, Bruno, Hoppscotch…) : importez depuis l’URL <PUBLIC_BASE_URL>/api/v1/openapi.json. Réglez ensuite l’authentification de la collection sur Bearer token avec votre clé ; ignorez le flux OAuth 2 que le client peut proposer d’après le schéma apiKey. Réimportez après une mise à jour de l’instance pour récupérer les nouvelles routes.

Avec un générateur de code (openapi-generator, openapi-typescript, oapi-codegen, NSwag…) : pointez le générateur vers l’URL ou vers une copie enregistrée. Les schémas en ligne produisent un type par opération ; si votre générateur le permet, activez sa déduplication de schémas. Exemple avec openapi-typescript :

sh
curl -s <PUBLIC_BASE_URL>/api/v1/openapi.json -o openapi.json
npx openapi-typescript openapi.json -o api.d.ts

Pour valider : le document déclare jsonSchemaDialect: https://json-schema.org/draft/2020-12/schema. N’importe quel validateur JSON Schema 2020-12 peut vérifier un corps contre paths["/api/v1/workflows"].post.requestBody.content["application/json"].schema avant de l’envoyer.

Pour comparer deux versions : enregistrez le document avant et après une mise à jour et comparez-les. Une nouvelle route, un nouveau champ ou un nouveau code d’erreur apparaît comme une différence dans le document, qui est le contrat de l’instance.