Entrée (schéma .proto)

Sortie (OpenAPI YAML)

Ce que fait cet outil

Tu as un schéma Protocol Buffers et une équipe frontend, partenaire ou QA qui veut un document OpenAPI pour les mêmes formes — généralement parce que le service gRPC est aussi exposé en HTTP via quelque chose comme grpc-gateway. Mettre en place protoc-gen-openapiv2 dans ton build est la bonne réponse en prod, mais c'est démesuré quand tu veux juste un spec rapide à partager ou à coller dans une Swagger UI. Ce convertisseur fait la moitié schéma du boulot dans ton navigateur — colle le .proto, copie le YAML, tu as des components OpenAPI valides.

La sortie est un document OpenAPI 3.1.0 minimal mais valide, avec un paths: {} vide et une entrée par message ou enum Protobuf sous components.schemas. On choisit OpenAPI 3.1 spécifiquement parce que son modèle de données s'aligne avec JSON Schema 2020-12 — c'est la version où les formats comme int64, date-time et duration sont des citoyens de première classe et où $ref peut cohabiter avec d'autres keywords sans les hacks de réécriture qu'il fallait en 3.0.

Le mapping de types suit le mapping JSON proto3 : les entiers 32 bits deviennent type: integer, format: int32, les 64 bits deviennent type: string, format: int64 avec un pattern numérique (parce que les nombres JSON au-delà de 2^53 perdent en précision), repeated T devient un array, map<K, V> devient un objet avec additionalProperties, et les noms de champs restent en snake_case pour que le schéma colle à ce que ton serveur sérialise vraiment. Les enums sortent en type: string avec une liste enum des noms de valeurs — pareil que pour le JSON proto3. Le convertisseur tourne entièrement dans ton navigateur ; rien de ton schéma ne quitte la page.

Comment l'utiliser

Trois étapes. La sortie est un document YAML que tu peux coller dans une Swagger UI ou fusionner avec un spec existant.

1

Colle ton schéma .proto

Dépose le schéma dans l'éditeur de gauche. syntax = "proto3"; en haut est OK mais facultatif. Le parser gère les blocs message imbriqués, les déclarations enum, oneof, map<K, V> et les options de champs. Les import entre fichiers sont reconnus mais ignorés — colle les types importés en ligne si tes schémas se référencent entre eux.

Les noms de champs restent en snake_case dans la sortie, ce qui correspond au comportement par défaut de l'encoder JSON de proto3. Si ton gateway est configuré en camelCase, fais un rechercher-remplacer dans la sortie ou change le réglage côté gateway.

2

Lis la sortie OpenAPI

À droite : un document YAML avec openapi: 3.1.0, un bloc info, un paths: {} vide et tes messages et enums sous components.schemas. Les références aux messages imbriqués utilisent $ref: '#/components/schemas/MessageName' sur le nom feuille, donc les références à plat fonctionnent même quand ton .proto déclare des types imbriqués.

3

Branche-le

Dépose le fichier dans une instance de Swagger UI ou Redoc pour voir comment les schémas s'affichent. Pour en faire un spec complet, ajoute de vraies entrées paths qui pointent vers tes routes grpc-gateway (ou écris-les à la main) — référence-les avec $ref sur #/components/schemas/Order et c'est parti.

Quand ça fait vraiment gagner du temps

Partager un schéma avec une équipe frontend ou partenaire

Une équipe frontend consomme ton service transcodé gRPC. Ils demandent un doc OpenAPI pour le brancher dans leur générateur de types ou leur explorateur d'API. Colle le .proto, copie le YAML, envoie. Ils reçoivent le schéma dans un format que leur tooling comprend déjà.

Bootstrapper le spec d'une nouvelle API HTTP transcodée

Tu démarres un nouveau service qui tournera à la fois en gRPC et HTTP via grpc-gateway avec buf. La section components/schemas est mécanique — génère-la avec cet outil, puis écris à la main les paths avec les bons templates de routes. Plus rapide que de tout monter à la main.

Garder une Swagger UI synchrone avec les changements .proto

Ton équipe utilise Swagger UI pour le doc d'API lisible, mais la source de vérité vit dans des fichiers .proto. Un collègue backend ajoute shipping_address à Order ; tu régénères la section schemas ici, tu la recolles dans le spec, tu pousses la mise à jour du doc.

Vérifier la sortie d'un codegen

Tu as lancé protoc-gen-openapiv2 dans ton build et obtenu un YAML de 4000 lignes. Pour vérifier qu'un message précis a la bonne forme, colle juste ce .proto ici et compare. Référence rapide pour voir à quoi ressemble un mapping OpenAPI 3.1 propre.

Questions fréquentes

Pourquoi OpenAPI 3.1 et pas 3.0 ?

OpenAPI 3.1 aligne son modèle de données sur JSON Schema 2020-12, ce qui veut dire que les formats comme int64, date-time et duration sont bien définis et que tu peux mettre $ref à côté d'autres keywords sans les contournements gênants qu'il fallait en 3.0. La plupart des outils modernes (Redoc, Swagger UI 5, Stoplight, Spectral) parlent 3.1 sans souci. Si tu as vraiment besoin de la sortie 3.0 pour du tooling legacy, change openapi: 3.1.0 en haut du document — le reste est suffisamment compatible pour que ça valide quand même la plupart du temps.

Pourquoi int64 sort en string et pas en number ?

Les nombres JSON sont des doubles IEEE-754 en pratique — ils perdent en précision au-delà de 2^53. Le mapping JSON proto3 officiel impose que int64, uint64, fixed64, sfixed64 et sint64 soient encodés comme des strings JSON. Donc le schéma OpenAPI utilise type: string, format: int64, pattern: "^-?[0-9]+$" pour coller à ce que le serveur envoie réellement. Si tu veux supposer des petites valeurs et utiliser type: integer, fais un rechercher-remplacer dans la sortie.

Pourquoi paths est vide ?

Les fichiers .proto décrivent des messages et des services, pas des routes HTTP. La transcodification HTTP (chemin, méthode, query, body) se configure à part — généralement via des annotations google.api.http ou des options grpc-gateway. On ne les parse pas, donc on laisse paths: {} pour que tu remplisses. La partie components/schemas est la moitié réutilisable et mécanique — c'est ce que cet outil te donne.

Pourquoi les noms de champs sont en snake_case ?

Parce que c'est ce qu'encode le JSON proto3 par défaut. order_id dans le .proto se sérialise en "order_id" dans le format JSON sauf si tu actives l'option camelCase (preserve_proto_field_names dans certains encoders, ou le flag côté gateway). Garder le schéma OpenAPI en snake_case veut dire qu'il colle au JSON que ton serveur envoie réellement. Si ta stack fait du camelCase, passe la sortie dans un rechercher-remplacer.

Comment sont gérés les messages imbriqués ?

Chaque message Protobuf devient une entrée de premier niveau sous components.schemas indexée par son nom feuille (Address, pas commerce.v1.Address). Les références utilisent $ref: '#/components/schemas/Address'. Si deux messages ont le même nom feuille dans des packages différents, le second écrasera le premier — sépare-les dans des documents distincts ou renomme dans le .proto.

Est-ce qu'il comprend bien les well-known types de google.protobuf ?

Quelques-uns. google.protobuf.Timestamp sort en type: string, format: date-time ; Duration en type: string, format: duration ; Empty en objet vide ; Any en objet générique ; Value en {} (n'importe quelle valeur JSON). Pour les autres well-known types Google, le convertisseur émet pour l'instant un $ref sur le nom feuille — tu peux soit définir ces schémas toi-même, soit remplacer les références par le bon type primitif.

Outils liés

Si tu jongles avec Protobuf et OpenAPI/JSON Schema, ceux-ci se complètent bien :