23
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Protocol Buffers(protobuf)入門

Last updated at Posted at 2025-12-24

JSONとの違い・書き方・gRPCの仕組みまで完全解説!
本記事は、Proto / gRPC をこれから触る方、buf lint に苦しんでいる方を主な対象にしています。

はじめに

🎅 この記事は RetailAI Advent Calendar 2025 の25日目の記事です。
ちょうどクリスマスのタイミングということで、皆さん素敵な一日をお過ごしください🎄✨

@le_thi_hang (レーティハン)が担当させていただきます。

昨日は @fujihara_hideyuki さんの『Strategy Pattern』を用いてcleanにcodingするでした。Strategy Pattern を使う理由や適用タイミングが、サンプルコード付きでとても分かりやすかったです。実務でも参考になる良い記事でした。


近年、マイクロサービスや gRPC の普及により、Protocol Buffers(protobuf / proto) は急速に浸透しています。

しかし、初めて触れるとこんな疑問が出てきませんか?

  • JSON と何が違うの?
  • proto の書き方がわからない…
  • フィールド番号(tag)って何? なんで必要なの?
  • buf lint のエラー多すぎ…

私自身、最初はまったく理解できず、buf lint で大量のエラーに困った経験があります。

そこで本記事では、初心者向けに図解付きで Proto の基本をやさしく解説します。この記事を読み終えれば、proto の基礎理解は完全にクリアできます。


この記事でわかること

✔ Protocol Buffers の全体像
✔ JSON と Proto の違い
.proto ファイルの書き方
message / enum / repeated の使い方
✔ フィールド番号(tag)が“絶対に重要”な理由
✔ gRPC の仕組み
buf lint / buf generate の基本
✔ 実務で気をつける後方互換性のルール


1. Protocol Buffers とは?

Protocol Buffers(Protobuf)は Google が開発したデータ定義 & シリアライズ方式 です。

一言でいうと:

データの型を定義し、コンパクトなバイナリ形式で通信する仕組み

特に gRPC では、API のリクエスト & レスポンス定義を proto で書くことが必須 になります。


2. Protocol Buffers の全体イメージ

Proto の最大の特徴は、定義ファイルから各言語のコードを自動生成できる点です。

.proto → 自動生成 → 各言語のクラス or Struct

Go, Java, TypeScript などに対応したコードが生成されます。

👉 この仕組みにより、
バックエンド・フロントエンド間の型ズレを防げます。

スクリーンショット 2025-12-24 15.49.58.jpg


3. JSON と何が違うのか?

結論から言うと

  • JSON:人間向け(テキスト)

  • Proto:機械向け(バイナリ)

→ Proto は 高速・軽量・通信向き

比較項目 JSON Protocol Buffers
データ形式 テキスト バイナリ
読みやすさ 人間に読みやすい 機械向け(高速)
型定義 あいまい 厳密
データサイズ 大きい とても小さい
後方互換性 弱い 強い(tag管理)
gRPC 非推奨 必須

■ JSON vs Proto

Gemini_Generated_Image_ec9ousec9ousec9o.png

📌 JSON は「キー名」も送るためサイズが大きくなります。
Proto は フィールド番号(tag)だけを送るため、非常に軽量です。


4. .proto ファイルの基本構造

syntax = "proto3";
package example;

message User {
  int32 id = 1;  // tag(フィールド番号)
  string name = 2;
  string email = 3;
}

.proto ファイルは
データ構造と API 仕様を定義する設計書のような存在です。

  • syntax = "proto3"
    → 使用する Protobuf のバージョン

  • package
    → 名前空間(生成コードや import に影響)

  • message
    → データ構造(struct / class 相当)

Proto の本質は「最初に型を厳密に決めること」 にあります。


5. よく使う型一覧

説明
int32 / int64 整数
string 文字列
bool 真偽値
double / float 小数
bytes バイナリ

Proto の型は 言語に依存しない共通型 です。

例えば int32 は:

  • Go → int32

  • Java → int

  • TypeScript → number

のように、各言語に適した型へ 自動変換 されます。

この仕組みにより、
👉 「フロントとバックエンドで型がズレる」問題を根本的に防げます。


6. repeated(配列)

message UserList {
  repeated User users = 1;
}

repeated は 0 件以上の配列を表します。

  • 0 件 → 空配列

  • 1 件以上 → 通常の配列

という扱いになり、null は存在しません。

生成される型の例:

  • Go → []User

  • TypeScript → User[]

  • Java → List<User>

📌 ポイント
JSON では null / [] / 未定義 の違いで事故が起きがちですが、Proto では repeated により 配列の扱いが明確になります。


7. enum(列挙)

最初の値は必ず 0 にする必要があります。

enum Gender {
  GENDER_UNKNOWN = 0; // 必須
  MALE = 1;
  FEMALE = 2;
}

これは Proto の重要なルールで、未設定・不正な値を受け取った場合は 0 が使われる仕様になっています。

そのため、

  • UNKNOWN

  • UNSPECIFIED

  • NONE

といった 「不明・未指定」用の値を 0 番に置くのが定番です。


8. gRPC のサービス定義

service UserService {
  rpc GetUser (GetUserRequest) returns (GetUserResponse);
}

この定義から、

  • クライアント用 Stub

  • サーバー用インターフェース

自動生成 されます。

👉 通信処理は gRPC に任せて、ビジネスロジックに集中できるのが大きなメリットです。

Gemini_Generated_Image_x32o2dx32o2dx32o.png


9. フィールド番号(tag)は 最重要ポイント

⚠ tag 番号は絶対に変更してはいけません。

Proto が送っているのは、

✔ フィールド番号

❌ フィールド名

番号を変えるとデータ破壊が起こります。

Gemini_Generated_Image_tq3mcdtq3mcdtq3m.png


10. 後方互換性ルール(実務で超重要)

❌ やってはいけない

  • 既存フィールドの tag 番号変更
  • 削除した番号を再利用
  • enum の番号を変更

⭕ やっていい

  • 新しいフィールド追加(新しい番号)
  • enum の新規値追加
  • 廃止したフィールドを reserved に移動

11. reserved の使い方

message User {
  reserved 4;
  reserved "old_name", "old_age";
}

👉 削除したフィールドは必ず reserved に入れる
これが実務ではほぼ必須です。


12. buf を使った proto 管理

代表的なコマンド:

buf lint      # スタイルチェック
buf generate  # コード生成
buf breaking  # 破壊的変更チェック

特に buf breakingtag 番号変更の事故防止に超有効です。

Gemini_Generated_Image_ugdp5qugdp5qugdp.png


13. JSON と Proto のサイズ比較

JSON

{"id":123,"name":"Bob"}

→ 約 25 bytes

Proto(バイナリ)

08 7B 12 03 42 6F 62

→ 約 7 bytes

📌 1/3 以下のサイズ! 大量通信では大きく効きます。


14. よくあるエラーと解決方法

❌ フィールド番号の重複

string name = 1;
string email = 1;  // NG

❌ enum に 0 番が無い

enum Status {
  ACTIVE = 1; // NG
}

❌ package とフォルダ構造の不一致

buf lint が検知します。


まとめ

この記事で学べるポイント:

✔ Proto の役割 → 厳密な型定義 & 高速通信
✔ JSONとの違い → バイナリで軽量
✔ 最重要 → tag は絶対に変更禁止
✔ buf を使うと開発が快適に
✔ 実務では後方互換性の意識が必須

Proto は難しく見えますが、ルールが明確なので慣れるととても扱いやすい技術だと思います。


おわりに

RetailAI / TRIAL では一緒に働くエンジニアを募集しています。
興味がある方はご連絡ください!

23
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?