Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
【encraft#2】Protobufスキーマによる明確なAPI定義
Search
hiro
April 25, 2023
Programming
1.1k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
【encraft#2】Protobufスキーマによる明確なAPI定義
hiro
April 25, 2023
More Decks by hiro
See All by hiro
Go1.20 リリースパーティ 統合テストのカバレッジ計測
parsely1231
0
580
Other Decks in Programming
See All in Programming
FDEが実現するAI駆動経営の現在地
gonta
2
260
yield再入門 #phpcon
o0h
PRO
0
930
【やさしく解説 設計編・中級 #6】良いアーキテクチャとは ~ 一本の登り道の、行き先 ~
panda728
PRO
0
200
仕様書を書く前にハーネスを作る - Agent Native開発は「探索を速く、判定を固く」
gotalab555
4
1.5k
ITヒヤリハットを整理してみた ~ライフサイクルと原因から考える再発防止策~
koukimiura
1
140
Prismを使った型安全な暗号化_関数型まつり2026
_fhhmm
0
170
Claude CodeとAgentCore Gatewayを繋ぐ際の認証認可 / Authentication and authorization when connecting Claude Code with AgentCore Gateway
har1101
0
140
Claude Team Plan導入・ガイド
tk3fftk
0
250
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
470
変わらないものが、変わるものを決める — 意図駆動開発 × イベントソーシング × イミュータブル | What Doesn't Change Decides What Can — IDD × Event Sourcing × Immutability
tomohisa
0
1.1k
Built Our Own Background Agent at LayerX #aidevex_findy
layerx
PRO
9
4.8k
【SRE NEXT 2026 Lunch Session】一人目専任SREの立ち上げを加速する ― AIと進めたオンボーディングで2分を0.04秒にした話
pkshadeck
PRO
0
3.5k
Featured
See All Featured
ラッコキーワード サービス紹介資料
rakko
1
4.2M
Prompt Engineering for Job Search
mfonobong
0
390
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
450
GraphQLとの向き合い方2022年版
quramy
50
15k
Accessibility Awareness
sabderemane
1
170
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.5k
How to make the Groovebox
asonas
2
2.3k
A better future with KSS
kneath
240
18k
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
72
41k
[SF Ruby Conf 2025] Rails X
palkan
2
1.2k
Chasing Engaging Ingredients in Design
codingconduct
0
260
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
250
Transcript
~コミュニケーションを支える技術~ Protobufスキーマによる明確なAPI定義 Encraft #2 サーバーとクライアントを結ぶ技術 2023/04/25(Tue) @IT_parsely / 樋口 陽介(hiro)
© Know ledge Work Inc. 自己紹介 樋口 陽介(hiro) @IT_parsely •
株式会社ナレッジワーク • バックエンドエンジニア • 今年のテーマの一つは「がんばって登壇してみる」 ◦ Go1.20リリースパーティ ◦ つきなみGo ◦ Go Conferenceは落ちました
© Know ledge Work Inc. • backendとfrontendを型安全に連携できる • シンプルにスキーマが書ける •
自動生成の文化があり、周辺ツールがそろっている • RESTで開発できる(ESPでHTTP↔️gRPC変換) 3 protobuf採用の背景
© Know ledge Work Inc. 4 セッション概要 コミュニケーションツールとしてのprotobuf .protoファイルを起点としてどのように開発しているか 話すこと
データ通信に関すること 話さないこと protobuf駆動の開発例をもとに嬉しさ・辛さを知ってもらう 今日のゴール
© Know ledge Work Inc. • protobuf駆動の開発紹介 ◦ Frontend ◦
Backend • 権限管理の拡張 • エラーハンドリング • 今後検討したいこと 5 Agenda
© Know ledge Work Inc. protobuf駆動の開発紹介
© Know ledge Work Inc. 7 protobuf駆動の開発 全体像 DesignDoc API定義(protobuf)
DesignDocでAPI定義を含む 全体設計についてやりとり protobuf から自動生成された インタフェースを基準に実装 開発の最初に .protoを作成 backend 今日のトピック frontend
© Know ledge Work Inc. 8 protobuf駆動で開発をすすめるにあたって 自然とprotobuf駆動になるような仕組み作り .protoファイルの利便性・重要性を高める とにかく型安全に
自動生成を最大限に活かす 重要な情報は.protoファイルに明示
© Know ledge Work Inc. 型定義の生成はts-protoを採用 EnumはTypeScriptのstring unionで出力できるように実装 をOSS Contribute
--ts_proto_opt=enumsAsLiterals=true https://github.com/stephenh/ts-proto/pull/450 @otofu-square 9 protobuf駆動の開発 Frontend message DividerData { enum DividerType { DOUBLE = 0; SINGLE = 1; DASHED = 2; DOTTED = 3; } DividerType type = 1; } export const DividerData_DividerType = { DOUBLE: 'DOUBLE', SINGLE: 'SINGLE', DASHED: 'DASHED', DOTTED: 'DOTTED', UNRECOGNIZED: 'UNRECOGNIZED', } as const; export type DividerData_DividerType = typeof DividerData_DividerType[keyof typeof DividerData_DividerType]; 型の強みを最大限活かす
© Know ledge Work Inc. google.api.httpオプションでREST対応 REST通信用のAPI Clientを自作pluginで生成 10 protobuf駆動の開発
Frontend async getUser(req: GetUserRequest): Promise<{ data: GetUserResponse, resHeaders: { [key: string]: string }, }> { const response = await requester.request( "GET", "user", "/v1/users/$id", "application/json", GetUserRequest.toJSON(req) as{ [key: string]: string | string[] }, "", ) if (response.ok) { return { data: GetUserResponse.fromJSON(awaitresponse.json()), resHeaders: headersToMap(response.headers), } } RESTの通信部分は自動生成 service UserService { rpc GetUser(GetUserRequest) returns (GetUserResponse) { option (google.api.http) = {get: "/v1/users/{id}"}; } }
© Know ledge Work Inc. 基本的なコード群はprotocで生成 ServiceのImplementsを自作pluginで生成 Service共通の処理 認証処理(詳細後述) 11
protobuf駆動の開発 Backend type UserServiceServer interface { GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error) } func (s *userServiceServer) GetUser( ctx context.Context, req *appservice.GetUserRequest, ) (*appservice.GetUserResponse, error) { userID, err := idtype.UserIDFromString(req.Id) if err != nil { return nil, status.Errorf(codes.InvalidArgument, "invalid user id (%s)", req.Id) } a, err := s.authorizer.Authorize( ctx, userID, roleactionmodel.UsersGet.ID, ) if err != nil { return nil, err } return s.getUser(ctx, a, req) } Serverの共通処理を自動生成
© Know ledge Work Inc. protoファイルの変更を検知 CIで自動生成を実行してPR作成 12 protobuf駆動の開発 CI
コード生成も自動化
© Know ledge Work Inc. 13 小括(protobuf駆動の開発紹介) 開発者間のAPIに関する認識ずれ API変更時のフィールド修正漏れなど、 単純な実装ミスに対するレビューのやり
とり 実現する状態 明確なAPI定義による共通認識 単純な実装ミスは型の力をかりてコンパイ ル時に検出でレビューコスト低減 よくある課題
© Know ledge Work Inc. 権限管理の拡張
© Know ledge Work Inc. 認証処理を自動生成することで実装ミスによるセキュリティインシデントを防ぐ 15 権限仕様をprotoで明示する嬉しさ Frontend、Backend間でAPI実行権限に共通認識を持ち、不具合を減らす セキュアな実装
API実行権限の共通認識
© Know ledge Work Inc. 16 具体的な方法 service UserService {
rpc GetUser(GetUserRequest) returns (GetUserResponse) { option (google.api.http) = { get: "/v1/users/{id}" }; option (kw.auth_options) = { auth_type: AUTH_TYPE_USER action_name: "users.get" }; } } protobufのメソッド定義に認証用のオプション を追加 リソースとアクションを明示 extensionsによる拡張
© Know ledge Work Inc. 17 Backendでの活用 func (s *userServiceServer)
GetUser( ctx context.Context, req *appservice.GetUserRequest, ) (*appservice.GetUserResponse, error) { userID, err := idtype.UserIDFromString(req.Id) if err != nil { return nil, status.Errorf(codes.InvalidArgument, "invalid user id (%s)", req.Id) } a, err := s.authorizer.AuthorizeUserRole( ctx, userID, roleactionmodel.UsersGet.ID, ) if err != nil { return nil, err } return s.getUser(ctx, a, req) } 認証処理を行うpublicメソッドを自動生成 開発者は認証以降の処理を実装する 認証処理の自動生成
© Know ledge Work Inc. 18 Frontendでの活用 権限に合わせたUIの出し分けに活用 ユーザーに権限のあるaction一覧をserverから取得 protobufの情報と合わせてAPIの実行権限を確認
API実行権限とUI
© Know ledge Work Inc. 19 小括(権限管理の拡張) 詳しい人に聞かないとAPIの実行権限が わからない 実現する状態
protoファイルをみるだけで実行権限が わかる protoに明示された権限情報を参照して UIをコントロールできる よくある課題
© Know ledge Work Inc. エラーハンドリング
© Know ledge Work Inc. 特定のエラーが起きた時にユーザーに復旧方法をフィードバックしたい エラー情報のやりとりも型安全に行いたい 21 エラーハンドリングの背景 エラーのフィードバック
gRPCのカスタムエラーの辛み type Status struct { Code int32 `json:"code,omitempty"` Message string `json:"message,omitempty"` Details []*anypb.Any `json:"details,omitempty"` } Detailsに任意のmessage型を詰め込む仕様 型安全にエラーを連携するのが難しい
© Know ledge Work Inc. 22 カスタムエラーのハンドリング エラー用の型を定義して、型安全に通信できる Detailsの中身をエラー用のmessage型にパースするコード を自作pluginで生成
import type { AppServiceError } from './appservice_error_type' import { ServiceLinkageError, } from './appservice_error'; export const parseAppServiceErrorBody = (body: { details?: any[] }): AppServiceError[] => { const { details } = body if (!details || !Array.isArray(details)) { return [] } return details.map(parseAppServiceError).filter((error): error is AppServiceError => !!error) } 型安全なエラーのやり取り message ServiceLinkageError { ServiceLinkageErrorType type = 1; string service_name = 2; google.protobuf.StringValue cause_detail = 3; }
© Know ledge Work Inc. 23 小括(エラーハンドリング) 実現する状態 どんなエラーが返ってくるかわからない エラーハンドリングが煩雑
エラーの型も明確に定義されている エラーレスポンスも正常系と同じように パースできる よくある課題
© Know ledge Work Inc. 24 エラーハンドリングでできていないこと • APIごとにどのようなエラーを返すのかprotoに明示 •
Serverからエラーを返す時に、Detailsに含めるmessage型を制限
© Know ledge Work Inc. 今後検討したいこと
© Know ledge Work Inc. 26 今後検討したいこと • protoc-gen-validateの導入 •
より型安全なエラーハンドリング • gRPC-Web
None