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
Hunting Vulnerabilities in Symfony with LLMs
vinceamstoutz
0
560
Honoでのサプライチェーン侵害対策 〜 3つのライブラリに学ぶ
yusukebe
7
1.5k
AI時代のUIはどこへ行く?その2!
yusukebe
22
7.5k
Hatena Engineer Seminar #37「言語モデルの活用に関する研究」
slashnephy
0
210
エンジニア向け会社紹介/Findy Company Profile
findyinc
6
350k
TSKaigi Night Talks 2026_TypeScriptでサプライチェーンの整合性を型に閉じ込める
geekplus_tech
0
410
Datadog LLM Observabilityで実現する 安全なLLM Usage 管理
3150
0
120
スマートグラスで並列バイブコーディング
hyshu
0
260
技術記事、 専門家としてのプログラマ、 言語化
mizchi
13
6.6k
JavaDoc 再入門
nagise
1
420
キャリア迷子上等 ─ "ない道"は自分で作ればいい
16bitidol
3
2.3k
作って学ぶ、 JSX (TSX) ランタイムの基本
syumai
7
1.7k
Featured
See All Featured
Claude Code のすすめ
schroneko
67
230k
A designer walks into a library…
pauljervisheath
211
24k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
49
10k
What does AI have to do with Human Rights?
axbom
PRO
1
2.2k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
Speed Design
sergeychernyshev
33
1.9k
Rails Girls Zürich Keynote
gr2m
96
14k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
Building Flexible Design Systems
yeseniaperezcruz
330
40k
The Cult of Friendly URLs
andyhume
79
6.9k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2.1k
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