Protobuf から Go への変換ツール
.proto スキーマを貼り付けてください。適切な型、struct タグ、ネストされたメッセージ用のポインタを備えた Go の struct が手に入ります — リポジトリにそのまま貼れます。
入力(.proto スキーマ)
出力(Go)
このツールの役割
Go は protobuf にとってネイティブな言語です — 本番の gRPC サービスのほとんどは Go で書かれています。通常は protoc-gen-go や buf を使って .proto から Go を生成します。つまりツールチェインのインストール、ジェネレーターの設定、ビルドステップの実行が必要です。このコンバーターはブラウザ上で同じ仕事をこなします — 貼って、コピーして、リポジトリに入れるだけです。
型のマッピングは protoc-gen-go が出力するものに従います: string → string、bool → bool、bytes → []byte、整数型はそれぞれ int32/int64/uint32/uint64 へマッピング(JavaScript のような精度ロスはありません)、double → float64、float → float32。単数形のメッセージフィールドはポインタ(公式の Go protobuf バインディングの慣習に合わせています)、repeated T は []T、map<K, V> は map[K]V になります。
フィールド名は Go の標準である PascalCase 化が施され、よく使われる頭字語は大文字化されます(order_id → OrderID、api_url → APIURL)— これは Go のレビュースタイルに従っています。各フィールドには貼り付けてすぐ使える struct タグが付きます: ワイヤーフォーマット用の protobuf:"varint,3,opt,name=status,proto3" と JSON マーシャリング用の json:"status,omitempty"。変換はローカル処理 — あなたの .proto がブラウザを離れることはありません。本番コードでは、メソッド・ディスクリプタ・リフレクション周辺を得るために本物のコード生成も必要ですが、スケッチ・レビュー・使い捨てスクリプト用途ならこちらの方が早いです。
使い方
3 ステップです。出力は標準ライブラリだけでそのままコンパイルできる、貼り付け即利用の Go です。
.proto スキーマを貼り付ける
左側のエディタにスキーマを入れてください。先頭の syntax = "proto3"; はあっても無くても OK です。パーサーはネストされた message ブロック、enum 宣言、oneof、map<K, V>、フィールドオプションを処理します。import は認識されますがスキップされます。
フィールド名は snake_case から PascalCase に自動変換されます。よくある頭字語サフィックス(Id → ID、Url → URL)も大文字化されるので、出力は revive / golint に文句を言われずに通ります。
出力を読む
右側: メッセージごとに type X struct、enum ごとに type X int32 と const ブロックの Go コード。先頭の package proto はプレースホルダなので、実際のパッケージ名に変えてください。
プロジェクトに組み込む
ファイルをプロジェクトに入れて、package 宣言を直し、import します。本物の gRPC コードでは marshal/unmarshal メソッドを得るために結局 protoc-gen-go を実行することになります。この出力は型付き JSON ハンドリング・struct スケッチ・レビュー向けで、protobuf のワイヤーフォーマットメソッドはここでは生成されません。
本当に時間を節約できる場面
既存の .proto から Go サービスを下書きする
別チームの Protobuf メッセージを消費する Go サービスを立ち上げているところ。ハンドラのシグネチャや JSON レスポンス用に struct の形が欲しいけれど、コード生成パイプライン全体を組むほどではない。貼って types.go に落とせば型は揃います。
Go コンシューマー向けに Protobuf API 変更をレビューする
バックエンドのチームメイトがメッセージにフィールドを追加した。新しい .proto を貼って、Go 出力と現在の types.go を diff し、的を絞ったレビューを残す。変更を見るためだけにツールチェインを立ち上げるより速いです。
言語間の動作確認
Go と TypeScript の両クライアントから消費される .proto がある。Protobuf から TypeScript コンバーターと並べて使えば、JSON エンコード後に両言語が見るフィールド名と型が揃っているかを確認できます。
使い捨ての連携スクリプト
gRPC-gateway のエンドポイントを叩く 50 行の Go スクリプトを書いている。1 つのスクリプトのために protoc・buf・ジェネレーター設定を整えるのはやり過ぎです。ここで struct を生成してそのまま貼り、スクリプトを出荷しましょう。
よくある質問
これは protoc-gen-go の代わりになりますか?
なりません。protoc-gen-go はバイナリの marshal/unmarshal メソッド、ファイルディスクリプタ、本物の gRPC に必要なリフレクション周辺を出力します。このコンバーターは struct の形とタグだけを出力します。本物の gRPC サービスを書くなら公式のコード生成を実行してください。JSON レスポンス・手書きスクリプト・スケッチ用に型だけ欲しいなら、こちらが速いです。
なぜメッセージ型のフィールドはポインタなのですか?
これは proto3 のメッセージフィールドに対して protoc-gen-go がやることをそのまま反映したものです。ポインタなのでゼロ値は nil になり、空のまま存在するメッセージと区別できます。スカラーフィールドはゼロ値(空文字列、0、false)自体が有効なので値型のままです。何らかの理由で非ポインタにしたければ、出力中のアスタリスクを find-replace してください。
enum はどう出力されますか?
protoc-gen-go の慣習に合わせて、Go の int32 typedef と const ブロックとして出力します。各 enum 値はその型の PascalCase な Go 定数になります。数値の割り当ては .proto からそのまま取られます。
protobuf の struct タグはどうなっていますか?
各フィールドにはワイヤータイプ(varint、fixed32、fixed64、bytes)、フィールド番号、ラベル(opt/rep)、名前、proto3 マーカーを含む protobuf:"..." タグが付きます。さらに元の snake_case 名を使った json:"name,omitempty" タグも。map<K, V> のタグは簡略化されているので、ワイヤーフォーマットを厳密に合わせたい場合は本物のコード生成を実行してください。
フィールド名はどのように変換されますか?
snake_case → PascalCase で、よく使われる頭字語サフィックスは大文字化されます: order_id → OrderID、api_url → APIURL、data_json → DataJSON。Go のレビュースタイル慣習に揃っているので、出力は手作業のクリーンアップなしで lint を通ります。
スキーマが別の .proto を import している場合は?
import 文は認識されますがスキップされます。ファイル間のメッセージ型はリーフ名(foo.Bar → Bar)で出力されるため、その型が同じパッケージに存在しなければ Go は解決できません。import 先のメッセージをインラインで貼るか、出力中の参照を直すかのどちらかが必要です。
関連ツール
Protobuf・JSON・Go を扱うなら、これらが組み合わせやすいです: