20220224のGoに関する記事は3件です。

[Golang] [GCP] grpc-gatewayがbackend serverにX-Cloud-Trace-Contextヘッダーを渡す方法

やりたいこと grpc-gatewayがHTTP/1.1で受け取ったリクエストヘッダーX-Cloud-Trace-Contextの情報を BackendへgRPCで通信するときにも伝搬してBakend側で使用したい。 想定しているアーキテクチャ grpc-gateway側の設定 muxを作成する際に、http headerを伝播するオプションをセット。 runtime.WithIncomingHeaderMatcher()を設定しない場合、header情報は伝搬されない。 mux := runtime.NewServeMux(runtime.WithIncomingHeaderMatcher(matcher)) matcherで伝搬したいheaderのみ指定することもできる。 This matcher will be called with each header in http.Request. If matcher returns true, that header will be passed to gRPC context. To transform the header before passing to gRPC context, matcher should return modified header. https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/runtime#WithIncomingHeaderMatcher func matcher(key string) (string, bool) { if key == "X-Cloud-Trace-Context" { return key, true } return "", false } Backend側の設定 Backend側でX-Cloud-Trace-Contextを取得するためには Controller層などのgrpcのpb serverに登録している関数がcontextを受け取ったあとに、 metadataを取り出すことでHttp Headerを取り出せる。 import ( "context" "github.com/example/controller" "github.com/exmaple/pb" "google.golang.org/grpc/metadata" ) // Backend側のController実装の例 func (ec *ExampleController) HelloExample(ctx context.Context, req *pb.ExampleRequest) (res *pb.ExampleRequest, err error) { // grpc-gatewayからheader情報はmetadataとして伝搬される md, isExist := metadata.FromIncomingContext(ctx) // metadataが存在する場合はisExist=true // metadata.Get(key string) []string を使用してheader情報を取得する traceContext := "" if isExist && len(md.Get("X-Cloud-Trace-Context")) > 0 { // []stringなのでindex=0を指定して取得 traceContext = md.Get("X-Cloud-Trace-Context")[0] } .. return res, err } Sample TODO: そのうちにつくってgithubのurlを貼ります。。 参考した記事
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Go言語で配列・スライスをなんでも受け取れる関数を作る

はじめに []int でも []string でも、どのような型の配列でも、どのような型のスライスでも、引数として受け取れる関数を作りたいことがありました。 作ろうとしたら一筋縄ではいかなかったので、その方法を書き留めておきます。 環境 terminal % go version go version go1.17.6 darwin/amd64 失敗例 はじめに、引数の型に interface{} を使うとなんでも受け取れるので []interface{} を使えばどのような型の配列・スライスでも受け取れるだろうと思い、以下のコードを書きました。 main.go package main import ( "fmt" ) func printElements(array []interface{}) { // []int や []string など、配列・スライスならなんでも受け取りたい for _, e := range array { fmt.Println(e) } } func main() { numbers := []int{2, 3, 5, 7, 11} printElements(numbers) texts := []string{"foo", "bar", "baz", "qux", "quux"} printElements(texts) } 実行結果 ./main.go:15:15: cannot use numbers (type []int) as type []interface {} in argument to printElements ./main.go:18:15: cannot use texts (type []string) as type []interface {} in argument to printElements しかし、これを実行しようとするとコンパイルに失敗します。 どうやら []interface{} 型の引数は interface{} 型の配列・スライスしか受け取れないようです。 解決方法 やっていることの本質は同じですが、一応2パターンあるので分けて記載します。 引数の型に interface{} を使用する どのような型の配列・スライスでも受け取れるように、引数の型をなんでも受け取れる interface{} にします。 そして、リフレクションを使用して引数の値を判別し、配列またはスライスでない場合はエラーを返すようにします。 main.go package main import ( "fmt" "reflect" ) func printElements(array interface{}) error { arr := reflect.ValueOf(array) if arr.Kind() != reflect.Array && arr.Kind() != reflect.Slice { return fmt.Errorf(`"%#v" is not array`, array) } for i := 0; i < arr.Len(); i++ { fmt.Println(arr.Index(i)) } return nil } func main() { numbers := []int{2, 3, 5, 7, 11} _ = printElements(numbers) texts := []string{"foo", "bar", "baz", "qux", "quux"} _ = printElements(texts) } 実行結果 2 3 5 7 11 foo bar baz qux quux 配列・スライスを []interface{} 型に変換する まず、どのような型の配列・スライスでも []interface{} 型に変換する関数を用意します。 この関数はリフレクションを使用して引数の値を判別し、配列またはスライスでない場合にエラーを返します。 そうしたら、行いたい処理は []interface{} 型を引数にとる関数として実装します。 main.go package main import ( "fmt" "reflect" ) func convert(array interface{}) ([]interface{}, error) { arr := reflect.ValueOf(array) if arr.Kind() != reflect.Array && arr.Kind() != reflect.Slice { return nil, fmt.Errorf(`"%#v" is not array`, array) } res := make([]interface{}, arr.Len()) for i := 0; i < arr.Len(); i++ { res[i] = arr.Index(i).Interface() } return res, nil } func printElements(array []interface{}) { for _, e := range array { fmt.Println(e) } } func main() { numbers := []int{2, 3, 5, 7, 11} ns, _ := convert(numbers) printElements(ns) texts := []string{"foo", "bar", "baz", "qux", "quux"} ts, _ := convert(texts) printElements(ts) } 実行結果 2 3 5 7 11 foo bar baz qux quux おわりに これで便利にどんな配列・スライスでも扱えますね。 リフレクション様様です。 関連 golangのinterface{}の不思議 【Go言語】[]string, []int to []interface{} とかそういうの Go言語 スライスのchunk関数をつくる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

オブジェクト詰め替え対策の一つ -- interface利用(golang)

ORM層とdomain層とデータ受け渡しをする場合、オブジェクト詰め替えが頻繁に発生することで、以下のデメリット・不便が感じている: コーディング作業がめんどくさい 詰め替え漏れ故のバグ 詰め替え処理自体の処理コストはどうかとの心配 これで試した対策の一つは interface利用のことです。 詳細はあとで...
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む