Go言語でgRPCに入門してみた3 独自インターセプタ

2020/10/01に公開

以前の記事で、gRPCで認証処理を入れる実験をしてみました。
その時はこちら。
https://zenn.dev/miyazi777/articles/a560e691fcee0b6449e4

インターセプタには認証の他にもロギングなど、定型的な処理がすでに用意されていていて、便利そうです。
ただ、実際の業務では独自処理を差し挟むこともあるかと思い、この記事ではカスタムインターセプタのテストをやってみました。
railsのbefore、afterやjavaのSpringのinterceptorに慣れている人であれば、すぐにイメージがつくと思います。

この記事では前々回の名前を渡すとhello <name>を返却するだけのサンプルに以下のことをやるカスタムインターセプタを追加します。
前々回の記事はこちら。
https://zenn.dev/miyazi777/articles/dbed823239aa17a9c82b

  • 送信された名前を<<< >>>で囲みます
  • 返却したhelloを*** ***で囲みます

例:name: worldをサーバに送信すると"*** hello ***<<< world >>>"を返却

独自インターセプタを追加

server.goに以下のような関数を定義します。
これが独自インターセプタの処理内容となります。
関数の真ん中にあるhandler()がリクエストを受けて起動される本来の処理です。

func CustomInterceptor() grpc.UnaryServerInterceptor {
    return func(ctx context.Context, request interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHand
        fmt.Printf("before process")
        helloMessage, _ := request.(*hello.HelloMessage)
        helloMessage.Name = fmt.Sprintf("<<< %s >>>", helloMessage.Name)

        res, err := handler(ctx, request)
        if err != nil {
            return nil, err
        }

        fmt.Println("after process")
        helloResponse, _ := res.(*hello.HelloResponse)
        helloResponse.Msg = fmt.Sprintf("*** %s ***", helloResponse.Msg)
        return res, nil
    }
}

独自インターセプタを設定する

server.goの以下の部分を変更します。
リクエストの度に処理を行いたいインターセプタをこのように登録します。

    server := grpc.NewServer(
        grpc.UnaryInterceptor(CustomInterceptor()),
    )

コード全文

下がserver.goのコード全文となります。

package main

import (
	"context"
	"fmt"
	"log"
	"net"
	"test/hello"

	"google.golang.org/grpc"
)

func main() {
	listenPort, err := net.Listen("tcp", ":19003")
	if err != nil {
		log.Fatal(err)
	}
	server := grpc.NewServer(
		grpc.UnaryInterceptor(CustomInterceptor()),
	)
	hello.RegisterHelloServer(server, &Hello{})
	server.Serve(listenPort)
}

type Hello struct{}

func (h *Hello) Hello(cts context.Context, message *hello.HelloMessage) (*hello.HelloResponse, error) {
	res := hello.HelloResponse{Msg: fmt.Sprintf("hello %s", message.Name)}
	return &res, nil
}

func CustomInterceptor() grpc.UnaryServerInterceptor {
	return func(ctx context.Context, request interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
		fmt.Printf("before process")
		helloMessage, _ := request.(*hello.HelloMessage)
		helloMessage.Name = fmt.Sprintf("<<< %s >>>", helloMessage.Name)

		res, err := handler(ctx, request)
		if err != nil {
			return nil, err
		}

		fmt.Println("after process")
		helloResponse, _ := res.(*hello.HelloResponse)
		helloResponse.Msg = fmt.Sprintf("*** %s ***", helloResponse.Msg)
		return res, nil
	}
}

Discussion