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

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

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

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

Avatar for Shintaro Kanno

Shintaro Kanno

August 03, 2022
Tweet

More Decks by Shintaro Kanno

Other Decks in Programming

Transcript

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

    Go - MySQL, PostgreSQL - Docker, Kubernetes - Azure, Aws - Git, RestfulAPI, gRPC, etc… @shinshin8 @doctorkanno572
  2. • Unary RPC ◦ クライアントからの1つのリクエストに対し、サーバーが1つのレスポンスをクライアントに返す。 • Server streaming RPC ◦

    クライアントからの1つのリクエストに対し、サーバーが複数のレスポンスをクライアントに返す。 • Client streaming RPC ◦ クライアントからの複数のリクエストに対し、サーバーが1つのレスポンスをクライアントに返す。 • Bidirectional RPC ◦ 通信が確立後、クライアントとサーバー間で任意のタイミングでのやりとりを行う。
  3. 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) } }
  4. 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 ◦ ミドルウェアの戻り値 ◦ 戻り値で関数を返す
  5. 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 : コンテキスト
  6. 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 : クライアントから受け取 るリクエスト
  7. 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 : サーバー情報
  8. 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 : 後続の処理
  9. 意識したい処理の流れ func ( ~~~~~~~~~ ) ( ~~~~~~~~~ ) { //

    ミドルウェアで行いたい処理を実装 return handler(ctx, req) } 処理結果を後続の処理に受け渡す 後続の処理結果を扱う func ( ~~~~~~~~~ ) ( ~~~~~~~~~ ) { resp, err := handler(ctx, req) if err != nil { // エラーハンドリング } // 後続の処理結果をもとに実装 }
  10. 今回作ったもの • Google Maps APIを使ってcontextに緯度経度を追加するミドルウェア • Google Maps Geocode及びGeolocation APIの操作を可能にするパッケージを使用

    ◦ https://github.com/martinlindhe/google-geolocate • クライアントからのリクエストcontextに位置情報が追加されている前提 • 実際に作ったもの ◦ https://github.com/shinshin8/golang-grpc-middleware
  11. 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) } } 実際に作ったミドルウェア
  12. 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) } } 実際に作ったミドルウェア
  13. 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) } } 実際に作ったミドルウェア
  14. 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) } } 実際に作ったミドルウェア
  15. 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) } } 実際に作ったミドルウェア