Upgrade to Pro — share decks privately, control downloads, hide ads and more …

gRPCミドルウェアを作ってみよう

 gRPCミドルウェアを作ってみよう

C1fa08401c6fbea820048f1cec5c4e67?s=128

Shintaro Kanno

August 03, 2022
Tweet

More Decks by Shintaro Kanno

Other Decks in Programming

Transcript

  1. gRPCミドルウェアを作ってみよう

  2. 名前 : 官野 慎太朗 業務 : 都内のIT事業会社にて勤務 技術経験: - JavaScript/TypeScript,

    Go - MySQL, PostgreSQL - Docker, Kubernetes - Azure, Aws - Git, RestfulAPI, gRPC, etc… @shinshin8 @doctorkanno572
  3. gRPCのミドルウェアを使ったこ とはありますか? ?

  4. go-grpc-middleware(github.com/grpc-ecosystem/go-grpc-middleware) • gRPC開発に必要なインターセプ ター、ヘルパー、ユーティリティなどを 提供 • 認証、ロギング、リカバリ、リトライなど の機能を実現

  5. 提供されている以外の機能が欲しい・・・

  6. ! 自前でgRPCミドルウェアを 作ってみよう

  7. 1. 4つのRPCについて 2. Unary Server Interceptorの基本構造 3. Google Maps APIを使ったgRPCミドルウェアの実装

    Agenda
  8. 1. 4つのRPCについて

  9. • Unary RPC ◦ クライアントからの1つのリクエストに対し、サーバーが1つのレスポンスをクライアントに返す。 • Server streaming RPC ◦

    クライアントからの1つのリクエストに対し、サーバーが複数のレスポンスをクライアントに返す。 • Client streaming RPC ◦ クライアントからの複数のリクエストに対し、サーバーが1つのレスポンスをクライアントに返す。 • Bidirectional RPC ◦ 通信が確立後、クライアントとサーバー間で任意のタイミングでのやりとりを行う。
  10. 1. 2. Unary Server Interceptor の基本構造

  11. Unary Server Interceptorの基本的な構成 func UnaryInterceptor() grpc.UnaryServerInterceptor { return func (

    ctx context.Context, req interface {}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler ) ( resp interface {}, err error ) { // ~~~ implementation ~~~~ return handler(ctx, req) } }
  12. Unary Server Interceptorの基本的な構成 func UnaryInterceptor() grpc.UnaryServerInterceptor { return func (

    ctx context.Context, req interface {}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler ) ( resp interface {}, err error ) { // ~~~ implementation ~~~~ return handler(ctx, req) } } • grpc.UnaryServerInterceptor ◦ ミドルウェアの戻り値 ◦ 戻り値で関数を返す
  13. 4つのパラメータ func UnaryInterceptor() grpc.UnaryServerInterceptor { return func ( ctx context.Context,

    ← ★ req interface {}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler ) ( resp interface {}, err error ) { // ~~~ implementation ~~~~ return handler(ctx, req) } } • ctx : コンテキスト
  14. 4つのパラメータ func UnaryInterceptor() grpc.UnaryServerInterceptor { return func ( ctx context.Context,

    req interface {}, ← ★ info *grpc.UnaryServerInfo, handler grpc.UnaryHandler ) ( resp interface {}, err error ) { // ~~~ implementation ~~~~ return handler(ctx, req) } } • ctx : コンテキスト • req : クライアントから受け取 るリクエスト
  15. 4つのパラメータ func UnaryInterceptor() grpc.UnaryServerInterceptor { return func ( ctx context.Context,

    req interface {}, info *grpc.UnaryServerInfo, ← ★ handler grpc.UnaryHandler ) ( resp interface {}, err error ) { // ~~~ implementation ~~~~ return handler(ctx, req) } } • ctx : コンテキスト • req : クライアントから受け取 るリクエスト • info : サーバー情報
  16. 4つのパラメータ func UnaryInterceptor() grpc.UnaryServerInterceptor { return func ( ctx context.Context,

    req interface {}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler ← ★ ) ( resp interface {}, err error ) { // ~~~ implementation ~~~~ return handler(ctx, req) } } • ctx : コンテキスト • req : クライアントから受け取 るリクエスト • info : サーバー情報 • handler : 後続の処理
  17. 意識したい処理の流れ func ( ~~~~~~~~~ ) ( ~~~~~~~~~ ) { //

    ミドルウェアで行いたい処理を実装 return handler(ctx, req) } 処理結果を後続の処理に受け渡す 後続の処理結果を扱う func ( ~~~~~~~~~ ) ( ~~~~~~~~~ ) { resp, err := handler(ctx, req) if err != nil { // エラーハンドリング } // 後続の処理結果をもとに実装 }
  18. 3. Google Maps APIを使った gRPCミドルウェアの実装

  19. 今回作ったもの • Google Maps APIを使ってcontextに緯度経度を追加するミドルウェア • Google Maps Geocode及びGeolocation APIの操作を可能にするパッケージを使用

    ◦ https://github.com/martinlindhe/google-geolocate • クライアントからのリクエストcontextに位置情報が追加されている前提 • 実際に作ったもの ◦ https://github.com/shinshin8/golang-grpc-middleware
  20. func GeocodeUnaryServerInterceptor(apiKey string) grpc.UnaryServerInterceptor { return func(ctx context.Context, req interface{},

    info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { client := geo.NewGoogleGeo(apiKey) geocode := geoctx.GetGeoInfo(ctx) res, _ := client.Geocode(geocode) if err != nil { geoctx.SetGeoLocate(ctx, 0, 0) } else { geoctx.SetGeoLocate(ctx, res.Lng, res.Lat) } return handler(ctx, err) } } 実際に作ったミドルウェア
  21. func GeocodeUnaryServerInterceptor(apiKey string) grpc.UnaryServerInterceptor { return func(ctx context.Context, req interface{},

    info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { client := geo.NewGoogleGeo(apiKey) ←★ 引数で受け取った Google Maps API Keyかクライアントを作成 geocode := geoctx.GetGeoInfo(ctx) res, _ := client.Geocode(geocode) if err != nil { geoctx.SetGeoLocate(ctx, 0, 0) } else { geoctx.SetGeoLocate(ctx, res.Lng, res.Lat) } return handler(ctx, err) } } 実際に作ったミドルウェア
  22. func GeocodeUnaryServerInterceptor(apiKey string) grpc.UnaryServerInterceptor { return func(ctx context.Context, req interface{},

    info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { client := geo.NewGoogleGeo(apiKey) geocode := geoctx.GetGeoInfo(ctx) ←★ contextから位置情報を取得 ※geoctx.GetGeoInfoは今回作った機能 res, _ := client.Geocode(geocode) if err != nil { geoctx.SetGeoLocate(ctx, 0, 0) } else { geoctx.SetGeoLocate(ctx, res.Lng, res.Lat) } return handler(ctx, err) } } 実際に作ったミドルウェア
  23. func GeocodeUnaryServerInterceptor(apiKey string) grpc.UnaryServerInterceptor { return func(ctx context.Context, req interface{},

    info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { client := geo.NewGoogleGeo(apiKey) geocode := geoctx.GetGeoInfo(ctx) res, _ := client.Geocode(geocode) ← ★ 取得した位置情報から Geocodeし、緯度経度を取得 if err != nil { geoctx.SetGeoLocate(ctx, 0, 0) } else { geoctx.SetGeoLocate(ctx, res.Lng, res.Lat) } return handler(ctx, err) } } 実際に作ったミドルウェア
  24. func GeocodeUnaryServerInterceptor(apiKey string) grpc.UnaryServerInterceptor { return func(ctx context.Context, req interface{},

    info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { client := geo.NewGoogleGeo(apiKey) geocode := geoctx.GetGeoInfo(ctx) res, _ := client.Geocode(geocode) if err != nil { geoctx.SetGeoLocate(ctx, 0, 0) } else { geoctx.SetGeoLocate(ctx, res.Lng, res.Lat) ← ★ 緯度経度をcontextに付与 ※geoctx.SetGeoLocateは今回作った機能 } return handler(ctx, err) } } 実際に作ったミドルウェア
  25. Thank you!