Eingabe (.proto-Schema)

Ausgabe (OpenAPI YAML)

Was dieses Tool tut

Du hast ein Protocol-Buffers-Schema und ein Frontend-, Partner- oder QA-Team, das ein OpenAPI-Dokument für dieselben Strukturen will — meistens, weil der gRPC-Service über etwas wie grpc-gateway zusätzlich per HTTP exponiert wird. protoc-gen-openapiv2 in den Build einzubauen ist die richtige Antwort für die Produktion, aber Overkill, wenn du nur ein schnelles Spec zum Teilen oder für die Swagger UI brauchst. Dieser Konverter erledigt die Schema-Hälfte der Arbeit direkt im Browser — füge das .proto ein, kopiere das YAML, und du hast valide OpenAPI-Components.

Die Ausgabe ist ein minimales, aber valides OpenAPI 3.1.0-Dokument mit leerem paths: {} und einem Eintrag pro Protobuf-Message oder -Enum unter components.schemas. Wir nehmen explizit OpenAPI 3.1, weil dessen Datenmodell zu JSON Schema 2020-12 passt — das ist die Version, in der Formate wie int64, date-time und duration erstklassig sind und in der $ref neben anderen Keywords stehen darf, ohne die alten 3.0-Umschreibetricks.

Das Type-Mapping folgt dem proto3-JSON-Mapping: 32-Bit-Ints werden zu type: integer, format: int32, 64-Bit-Ints zu type: string, format: int64 mit numerischem Pattern (weil JSON-Zahlen oberhalb von 2^53 an Präzision verlieren), repeated T wird zu einem Array, map<K, V> zu einem Objekt mit additionalProperties, und Feldnamen bleiben in snake_case, damit das Schema zu dem passt, was dein Server tatsächlich serialisiert. Enums kommen als type: string mit einer enum-Liste der Wertenamen heraus — wie im proto3-JSON. Der Konverter läuft komplett im Browser; nichts von deinem Schema verlässt die Seite.

So nutzt du es

Drei Schritte. Die Ausgabe ist ein YAML-Dokument, das du in eine Swagger UI laden oder in ein bestehendes Spec mergen kannst.

1

Füge dein .proto-Schema ein

Schmeiß das Schema in den linken Editor. Das syntax = "proto3"; oben ist OK, aber optional. Der Parser kommt mit verschachtelten message-Blöcken, enum-Deklarationen, oneof, map<K, V> und Feld-Options klar. Datei-übergreifende import-Statements werden erkannt, aber übersprungen — füge importierte Typen inline ein, wenn deine Schemas sich gegenseitig referenzieren.

Feldnamen bleiben in der Ausgabe snake_case, passend zum Default des proto3-JSON-Encoders. Wenn dein Gateway auf camelCase-JSON-Namen konfiguriert ist, mach in der Ausgabe ein Suchen/Ersetzen oder ändere die Gateway-Einstellung.

2

Lies die OpenAPI-Ausgabe

Rechts: ein YAML-Dokument mit openapi: 3.1.0, einem info-Block, einem leeren paths: {} und deinen Messages und Enums unter components.schemas. Verweise auf verschachtelte Messages nutzen $ref: '#/components/schemas/MessageName' auf den Blattnamen, sodass flache Referenzen auch dann funktionieren, wenn dein .proto verschachtelte Typen deklariert.

3

Verdrahte es

Schmeiß die Datei in eine Swagger UI- oder Redoc-Instanz, um zu sehen, wie die Schemas gerendert werden. Um daraus ein vollständiges Spec zu machen, ergänze echte paths-Einträge für deine grpc-gateway-Routen (oder schreib sie von Hand) — referenziere sie per $ref auf #/components/schemas/Order und du bist durch.

Wann es wirklich Zeit spart

Schema mit einem Frontend- oder Partner-Team teilen

Ein Frontend-Team konsumiert deinen gRPC-transcodierten Service. Sie wollen ein OpenAPI-Doc, um es in ihren Type-Generator oder API-Explorer zu stecken. Füge das .proto ein, kopiere das YAML, schick es rüber. Sie bekommen das Schema in einem Format, das ihre Tools sowieso schon verstehen.

Spec für eine neue HTTP-transcodierte API anstoßen

Du startest einen neuen Service, der sowohl als gRPC als auch als HTTP über grpc-gateway mit buf läuft. Der components/schemas-Teil ist mechanisch — generier ihn mit diesem Tool und schreib dann die paths mit den richtigen Route-Templates von Hand. Schneller, als alles selbst zu zimmern.

Swagger UI synchron zu .proto-Änderungen halten

Dein Team nutzt Swagger UI für die menschenlesbare API-Doku, aber die Source of Truth liegt in den .proto-Dateien. Ein Backend-Kollege fügt shipping_address zu Order hinzu; du regenerierst die schemas-Section hier, fügst sie ins Spec zurück und shippst das Doc-Update.

Codegen-Output prüfen

Du hast protoc-gen-openapiv2 als Teil deines Builds laufen lassen und ein 4000 Zeilen langes YAML bekommen. Um zu verifizieren, dass ein bestimmtes Message richtig geformt ist, füge nur diese eine .proto-Datei hier ein und vergleiche. Schnelle Referenz, wie ein sauberes OpenAPI-3.1-Mapping aussehen sollte.

Häufige Fragen

Warum OpenAPI 3.1 und nicht 3.0?

OpenAPI 3.1 richtet sein Datenmodell an JSON Schema 2020-12 aus, was bedeutet, dass Formate wie int64, date-time und duration sauber definiert sind und dass du $ref neben anderen Keywords setzen kannst, ohne die umständlichen Workarounds, die 3.0 brauchte. Die meisten modernen Tools (Redoc, Swagger UI 5, Stoplight, Spectral) sprechen 3.1 problemlos. Wenn du wirklich 3.0-Output für Legacy-Tooling brauchst, ändere openapi: 3.1.0 oben im Dokument — der Rest ist kompatibel genug, dass es meist trotzdem validiert.

Warum wird int64 als String, nicht als Zahl ausgegeben?

JSON-Zahlen sind in der Praxis IEEE-754-Doubles — sie verlieren Präzision oberhalb von 2^53. Das offizielle proto3-JSON-Mapping verlangt, dass int64, uint64, fixed64, sfixed64 und sint64 als JSON-Strings codiert werden. Deshalb verwendet das OpenAPI-Schema type: string, format: int64, pattern: "^-?[0-9]+$", damit es zu dem passt, was der Server tatsächlich sendet. Wenn du davon ausgehen willst, dass die Werte klein sind, und stattdessen type: integer nutzen möchtest, mach in der Ausgabe ein Suchen/Ersetzen.

Warum ist paths leer?

.proto-Dateien beschreiben Messages und Services, keine HTTP-Routen. Das HTTP-Transcoding (Pfad, Methode, Query, Body) wird separat konfiguriert — meist über google.api.http-Annotationen oder grpc-gateway-Optionen. Wir parsen die nicht, also lassen wir paths: {} leer, damit du es selbst füllst. Die components/schemas-Hälfte ist die wiederverwendbare, mechanische — und genau die liefert dieses Tool.

Warum sind die Feldnamen in snake_case?

Weil proto3-JSON sie standardmäßig so codiert. order_id im .proto wird im JSON-Wireformat als "order_id" serialisiert, sofern du nicht die camelCase-Option aktivierst (in manchen Encodern preserve_proto_field_names oder das Gateway-seitige Flag). Wenn das OpenAPI-Schema in snake_case bleibt, passt es zu dem JSON, das dein Server tatsächlich rausschickt. Wenn dein Stack camelCase macht, jag die Ausgabe einmal durch ein Suchen/Ersetzen.

Wie werden verschachtelte Messages behandelt?

Jedes Protobuf-Message wird zu einem Top-Level-Eintrag unter components.schemas, indiziert über seinen Blattnamen (Address, nicht commerce.v1.Address). Verweise nutzen $ref: '#/components/schemas/Address'. Wenn zwei Messages in unterschiedlichen Packages denselben Blattnamen haben, überschreibt das zweite das erste — splitte sie auf separate Dokumente oder benenne im .proto um.

Versteht es google.protobuf-Well-Known-Types ordentlich?

Einige davon. google.protobuf.Timestamp wird zu type: string, format: date-time; Duration zu type: string, format: duration; Empty zu einem leeren Objekt; Any zu einem generischen Objekt; Value zu {} (jeder JSON-Wert). Für andere Google-Well-Known-Types gibt der Konverter aktuell ein $ref auf den Blattnamen aus — du kannst diese Schemas selbst definieren oder die Verweise durch den passenden primitiven Typ ersetzen.

Verwandte Tools

Wenn du mit Protobuf und OpenAPI/JSON Schema arbeitest, passen diese gut dazu: