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

Dive into Go Protocol Buffers API v2 with the new reflection features

Dive into Go Protocol Buffers API v2 with the new reflection features

About
2020年にリリースされたGo Protocol Buffers API v2のリリースされた背景や概要について解説しています。
特に、目玉機能のReflectionに焦点をあてて、実際の使用例とともに解説しています。
Go Conference Tokyo 2021 Springの登壇資料になります。

資料内のリンク
・使用例のコード
https://github.com/sryoya/protoreflect-go-examples

・The Go Blog A new Go API for Protocol Buffers https://blog.golang.org/protobuf-apiv2

・protobuf
https://github.com/protocolbuffers/protobuf

・protoreflect https://pkg.go.dev/google.golang.org/protobuf/reflect/protoreflect

・dynamicpb
https://pkg.go.dev/google.golang.org/protobuf/types/dynamicpb

・protoc-gen-go
https://pkg.go.dev/google.golang.org/protobuf/cmd/protoc-gen-go

・protoc-gen-go-grpc
http:/pkg.go.dev/google.golang.org/grpc/cmd/protoc-gen-go-grpc

・protocmp
https://pkg.go.dev/google.golang.org/protobuf/testing/protocmp

・protojson
https://pkg.go.dev/google.golang.org/protobuf/encoding/protojson

・protogen
https://pkg.go.dev/google.golang.org/protobuf/compiler/protogen

・採用ページ
https://corporatecard.up-sider.jp/career

Ryoya Sekino

April 24, 2021
Tweet

More Decks by Ryoya Sekino

Other Decks in Programming

Transcript

  1. Dive into Go Protocol
    Buffers API v2
    With the new reflection features
    Ryoya Sekino
    @Go Conference 2021 Spring

    View full-size slide

  2. 2
    セッションの背景とゴール
    背景
    ゴール
    ● Go Protocol Buffers API v2が2020年にリリース
    ● v1のリリースから10年ぶりのメジャーアップデート
    ● 充実したreflection機能が公式に提供されるようになった
    ● Go Protocol Buffers API v2の概要やリリース背景を理解する
    ● 新しいreflection機能の使い方や使い道を理解する

    View full-size slide

  3. Agenda
    1. Introduction
    2. What’s Protocol Buffers?
    3. What’s Go Protocol Buffers API v2?
    1. Faults in v1
    2. What v2 provides
    4. Examples using protoreflect
    1. Custom regulations for String
    2. Random message struct generator
    3

    View full-size slide

  4. $whoami
    ● Ryoya Sekino /関野 涼也
    ● Software Engineer at UPSIDER, inc., leading Card Processing
    team
    ● Writing Go for 2 years as a main language
    ● Loves music, DJ’ing
    4
    1. Introduction
    sekino_pii sryoya

    View full-size slide

  5. Briefly about UPSIDER
    ● 成長企業向けの法人カードを提供しているスタートアップです ⭐
    ● 金融SaaSとして企業のお金周りの課題を解決することを目指してい
    ます 🏢
    5
    1. Introduction

    View full-size slide

  6. 成長フェーズにつき、絶賛採用中です!!
    ● 成長企業向けの法人カードを提供しているスタートアップです ⭐
    ● 金融SaaSとして企業のお金周りの課題を解決することを目指してい
    ます 🏢
    ● Tech Stacks: Go, Kotlin, k8s, Istio, microservices
    ● Working Styles: フルリモート、フルフレックス、業務委託可、副業可
    6
    1. Introduction
    問い合わせはこちらまで
    https://corporatecard.up-sider.jp/career
    Gopherの原著作者は Renée Frenchさんです。

    View full-size slide

  7. Agenda
    1. Introduction
    2. What’s Protocol Buffers?
    3. What’s Go Protocol Buffers API v2?
    1. Faults in v1
    2. What v2 provides
    4. Examples using protoreflect
    1. Custom regulations for String
    2. Random message struct generator
    7

    View full-size slide

  8. 8
    2.What’s Protocol Buffers?
    ● IDL (インターフェース定義言語) で構造を定義し、データを
    Serialize/Deserializeする仕組み
    ● 高速でシンプルなのが特徴
    ● 言語や環境に依存しないで使用できる  メッセージが各言語の形にコンパイル
    するツールが提供されている
    ● RPC(gRPC含む)で利用されている
    Protocol Buffers (a.k.a., protobuf, pb) は構造化データを
    Serializeする仕組み & そのインターフェース定義言語

    View full-size slide

  9. message Person {
    string name = 1;
    string phone_number = 2;
    int32 age = 3;
    bool is_alive = 4;
    }
    このようなデータ形式のものを”.proto”という拡張子のファイルに定義する
    9
    2.What’s Protocol Buffers?
    基本のデータ構造はmessageという単位で表現する
    右端のタグ番号は、 Serializing用のフィールド識別子

    View full-size slide

  10. protobufには、各言語から操作できるようなAPIが用意されて
    いる
    ● protoc コンパイラが各言語の表現形式に変換する
    https://github.com/protocolbuffers/protobuf
    ● 対応言語はたくさん
    Go, C#, C++, Dart, Java, Kotlin, Node, Objective-C, PHP, Python, Ruby
    ● Goでは、コンパイルすると、pb.goというファイルに変換される
    10
    2.What’s Protocol Buffers?
    .proto .pb.go
    コンパイル

    View full-size slide

  11. 11
    2.What’s Protocol Buffers?
    Goにコンパイルするとmessageがstructとして表現される
    message Person {
    string name = 1;
    string phone_number = 2;
    int32 age = 3;
    bool is_alive = 4;
    }
    type Person struct {
    Name   string
    PhoneNumber string
    Age    int32
    IsAlive bool
    }
    コンパイル
    .pb.go
    コンパイル
    .proto

    View full-size slide

  12. 12
    2.What’s Protocol Buffers?
    protobufをGoの表現形式で操作するAPIが今回のお題
    Gopherの原著作者は Renée Frenchさんです。
    message Person {
    string name = 1;
    string phone_number = 2;
    int32 age = 3;
    bool is_alive = 4;
    }

    View full-size slide

  13. 13
    2.What’s Protocol Buffers?
    このセッションでのProtocol Buffers関連の言葉の使い方
    Protocol Buffers (protobuf, pb) : Serializingフォーマット、またはそのIDLのこと。
    (protobufの) Message: protobufのIDLで定義されたメッセージ、またはそれの具
    体的なデータのこと
    Proto File: protobufのIDLを定義したファイル(.proto)のこと
    Note: これらは必ずしも厳密な言葉の定義とは一致しません。

    View full-size slide

  14. Agenda
    1. Introduction
    2. What’s Protocol Buffers?
    3. What’s Go Protocol Buffers API v2?
    1. Faults in v1
    2. What v2 provides
    4. Examples using protoreflect
    1. Custom regulations for String
    2. Random message struct generator
    14

    View full-size slide

  15. ● Goのreflect packageがGoのデータ形式に従ったreflectionを提供するように、
    protobufのデータ形式に沿ったreflectionを提供
    ● Interfaceを介して、protobufのデータ操作の手段を共通化・充実化
    15
    3. What’s Go Protocol Buffers API v2?
    Go Protocol Buffers API v2は、interfaceの実装を充実さ
    せ、protobufのデータ形式の沿ったreflection機能を提供

    View full-size slide

  16. Agenda
    1. Introduction
    2. What’s Protocol Buffers?
    3. What’s Go Protocol Buffers API v2?
    1. Faults in v1
    2. What v2 provides
    4. Examples using protoreflect
    1. Custom regulations for String
    2. Random message struct generator
    16

    View full-size slide

  17. 1. Messageに対して、protobuf Messageとしてのreflectionが実行しづらい
    2. Messageのinterfaceが簡素なため、Messageに対する共通の処理を実行し
    づらい
    3. デフォルトのコンパイラ以外で生成した
    protobufのGoの表現形式も共通の処
    理ができるようにしたい
    17
    3-1. What’s Go Protocol Buffers API v2? - Faults in v1
    v1には、Messageの情報操作やinterfaceに課題があった

    View full-size slide

  18. ● Goのreflect パッケージはあくまで、GoのTypeとしてしか扱えないので、
    protobufのMessageをprotobufの文法に則って扱いたい
    ● Messageの情報を取得する方法はあるが、簡単に操作するような方法が公式
    で与えられていない
    18
    3-1. What’s Go Protocol Buffers API v2? - Faults in v1
    v1の課題1/3: Messageに対して、protobuf Messageとして
    のreflectionが実行しづらい
    func (*DoResponse) Descriptor() ([]byte, []int) {
    // ...
    }
    Byteで返ってくる

    View full-size slide

  19. Messageのinterface自体は特になにもしてない。。。
    19
    3-1. What’s Go Protocol Buffers API v2? - Faults in v1
    v1の課題2/3: Messageのinterfaceが簡素で、Messageに
    対する共通の処理を実行しづらい
    生成されたstructでも、特に何もしてない
    type Message interface {
    Reset()
    String() string
    ProtoMessage()
    }
    func (*DoRequest) ProtoMessage() {}

    View full-size slide

  20. ● protocで生成したメッセージはあくまで、
    protobufのGoでの表現形式の一つに
    すぎないので、独自のcompiler等を使用した独自の表現形式でも
    reflectionを
    したい
    ● CLIなどでGoにコンパイルされたコードが手に入らない状況でも
    Protocol
    Buffersのメッセージを扱いたい
    20
    3-1. What’s Go Protocol Buffers API v2? - Faults in v1
    v1の課題3/3: デフォルトのコンパイラ以外で生成した
    protobufのGoの表現形式も共通の処理ができるようにしたい

    View full-size slide

  21. Agenda
    1. Introduction
    2. What’s Protocol Buffers?
    3. What’s Go Protocol Buffers API v2?
    1. Faults in v1
    2. What v2 provides
    4. Examples using protoreflect
    1. Custom regulations for String
    2. Random message struct generator
    21

    View full-size slide

  22. ● Messageのinterfaceが、明示的に、reflection用のinterfaceを返すような関数
    を宣言するようになった
    ● protoreflect packageがprotobufに対して共通のreflectionを実装している
    22
    3-2. What’s Go Protocol Buffers API v2? - What v2 provides
    v2では、interfaceを充実させて、interfaceに対するreflection
    を提供することで、v1の課題を解決した

    View full-size slide

  23. package “google.golang.org/protobuf/proto”
    package “google.golang.org/protobuf/reflect/protoreflect”
    type ProtoMessage interface{ ProtoReflect() Message }
    23
    3-2. What’s Go Protocol Buffers API v2? - What v2 provides
    v2のproto.Message interfaceは明示的にprotoreflectの
    interfaceを返す関数を宣言している
    リフレクション用のinterfaceをを返す
    type Message = protoreflect.ProtoMessage

    View full-size slide

  24. package “google.golang.org/protobuf/proto”
    package “google.golang.org/protobuf/reflect/protoreflect”
    func (x *DoRequest) ProtoReflect() protoreflect.Message {
    // … omitted ...
    }
    24
    3-2. What’s Go Protocol Buffers API v2? - What v2 provides
    protobufから生成されたmessage structから、reflection用
    のinterfaceを実装したtypeを取得できる
    type ProtoMessage interface{ ProtoReflect() Message }
    type Message = protoreflect.ProtoMessage

    View full-size slide

  25. 25
    3-2. What’s Go Protocol Buffers API v2? - What v2 provides
    protoreflect.MessageがReflection用のメソッドを定義してい

    View full-size slide

  26. .proto ファイルに定義される情報をDescriptorというinterfaceで抽象的に表現して、
    共通の動的な操作を可能にしている
    26
    3-2. What’s Go Protocol Buffers API v2? - What v2 provides
    protoreflect packageは、Messageに対する共通の
    reflection処理を規定している

    View full-size slide

  27. 27
    3-2. What’s Go Protocol Buffers API v2? - What v2 provides
    protoファイルのデータ単位ごとにDescriptorが存在している
    ● FileDescriptor
    ● ServiceDescriptor
    ● MethodDescriptor
    ● MessageDescriptor
    ● FieldDescriptor
    ● OneOfDescriptor
    ● EnumDescriptor
    ● EnumValueDescriptor

    View full-size slide

  28. 28
    3-2. What’s Go Protocol Buffers API v2? - What v2 provides
    Message DescriptorがMessageに対する操作を提供する

    View full-size slide

  29. 29
    3-2. What’s Go Protocol Buffers API v2? - What v2 provides
    Field DescriptorがFieldに対する操作を提供する

    View full-size slide

  30. 30
    3-2. What’s Go Protocol Buffers API v2? - What v2 provides
    FileDescriptorがファイル全体に対する操作を提供する

    View full-size slide

  31. 31
    3-2. What’s Go Protocol Buffers API v2? - What v2 provides
    同様にその他のデータ単位のDescriptorがある

    View full-size slide

  32. 32
    3-2. What’s Go Protocol Buffers API v2? - What v2 provides
    データ単位同士の関係に則って、Descriptorを行ったり来たり
    できる
    File
    Descriptor
    Service
    Descriptor Method
    Descriptor
    Message
    Descriptor Field
    Descriptor
    Enum
    Descriptor
    OneOf
    Descriptor
    Enum
    Value
    Descriptor

    View full-size slide

  33. 33
    3-2. What’s Go Protocol Buffers API v2? - What v2 provides
    GoのMessage Structがあれば、MessageDescriptorを始点
    にすべてのDescriptorにアクセスできる
    File
    Descriptor
    Service
    Descriptor Method
    Descriptor
    Message
    Descriptor Field
    Descriptor
    Enum
    Descriptor
    OneOf
    Descriptor
    Enum
    Value
    Descriptor
    Message
    type Person struct {
    Name   string
    PhoneNumber string
    Age    int32
    IsAlive bool
    }
    Proto
    Message

    View full-size slide

  34. Agenda
    1. Introduction
    2. What’s Protocol Buffers?
    3. What’s Go Protocol Buffers API v2?
    4. Examples using protoreflect
    1. Custom regulations for String
    2. Random message struct generator
    34

    View full-size slide

  35. 1. Custom regulations for String
    protoreflectを使ったデータ構造や値の取り出し方の雰囲気
    2. Random message struct generator
    protoreflectを使ったデータの作成・値の書き込み方法の雰囲気
    最終形はGitHubに置いてます
    https://github.com/sryoya/protoreflect-go-examples
    35
    4. Examples using protoreflect
    Exampleを通して理解すること

    View full-size slide

  36. Agenda
    1. Introduction
    2. What’s Protocol Buffers?
    3. What’s Go Protocol Buffers API v2?
    4. Examples using protoreflect
    1. Custom regulations for String
    2. Random message struct generator
    36

    View full-size slide

  37. 概要
    ● protobufのStringのフィールドに長さ・形式等の制約をかけられるようにしたい
    ○ 文字数が6-12文字の値のみ有効なString
    ○ アルファベットと数字のみ有効な
    String
    ● protobufに制約を定義し、具体的なGoのメッセージの値が形式に沿っているか
    どうかのバリデーション関数を用意する
    使い道の例
    ● gRPC Serverがいちいち(内部のロジック的に)想定外の値に対するバリデーショ
    ンを書かなくてよくする
    ● gRPC Clientがサーバー側の内情を知らなくても、送ろうとしているメッセージが
    正しいか判断できるようにする
    37
    4-1. Examples using protoreflect - Custom regulations for String
    作るもの: Custom regulations for String

    View full-size slide

  38. 1. Stringのフィールドに長さのルールをOptionで付加する
    2. Optionで指定した制約に準拠した値かをバリデーションできる
    38
    4-1. Examples using protoreflect - Custom regulations for String
    使い方のイメージ: String with the custom regulations
    message UpdateAccountIDRequest {
    string iD = 1 [ (stroptpb.opts) = {min_len : 6, max_len: 12} ];
    }
    msg = &testproto.UpdateAccountIDRequest{
    ID: "12345",
    }
    err = stropt.Validate(msg)
    fmt.Println(err)
    // Output: Field: ID, invalid length, the value must be longer than or equal to 6, but actual: 5
    Optionを指定

    View full-size slide

  39. 1. Protocol Buffersに共通のField Optionを定義する
    2. 関数を作る
    1. 関数のIOを定義する
    2. Messageの情報を取り出す
    3. 各フィールドの情報を取り出す
    4. フィールドのOptionをチェックして取り出す
    5. フィールドの値をチェックして取り出す
    6. 取り出したOptionと値を利用してバリデーションする
    39
    4-1. Examples using protoreflect - Custom regulations for String
    ステップ: Custom regulations for String

    View full-size slide

  40. Note: proto3には存在しなかった ”optional”は、Protocol Buffers v.3.12.0で試験的に導入され
    ました
    40
    4-1. Examples using protoreflect - Custom regulations for String
    1. Protocol Buffersに共通のField Optionを定義する
    extend google.protobuf.FieldOptions {
    StringOpts opts = 50000;
    }
    message StringOpts {
    optional int32 len = 1;
    optional int32 max_len = 2;
    optional int32 min_len = 3;
    optional string regexp = 4;
    }
    message UpdateAccountIDRequest {
    string iD = 1 [ (stroptpb.opts) = {len : 10} ];
    }
    定義する 実際に埋め込める
    Optionの識別子は50000-99999でないと
    いけない

    View full-size slide

  41. Inputは、protobuf Messageから生成されたStructならどんな値でも投げ込めるよう
    にする
    41
    4-1. Examples using protoreflect - Custom regulations for String
    2-1 関数のIOを定義する
    Messageから生成されたGoのStructに共通のinterface
    func Validate(pb proto.Message) error {
    return validate(pb.ProtoReflect())
    }

    View full-size slide

  42. func Validate(pb proto.Message) error {
    return validate(pb.ProtoReflect())
    }
    proto.Messageからreflection用のinterfaceを実装した値を取り出す
    42
    4-1. Examples using protoreflect - Custom regulations for String
    2-2 Messageの情報を取り出す
    reflection用のinterfaceを実装した情報を取り出す

    View full-size slide

  43. MessageからField Descriptorを取り出して各フィールドを見ていく
    func validate(m protoreflect.Message) error {
    md := m.Descriptor()
    fds := md.Fields()
    var errs error
    for k := 0; k < fds.Len(); k++ {
    fd := fds.Get(k)
    // validation for each filed
    }
    return errs
    }
    43
    4-1. Examples using protoreflect - Custom regulations for String
    2-3 各フィールドの情報を取り出す
    この中に具体的なvalidationを書いていく
    MessageDescriptorを取り出す
    FieldDescriptorsを取り出す

    View full-size slide

  44. StrOptsがついているフィールドか確認して、ついていれば
    Optionの中身を取り出す
    opts := fd.Options().(*descriptorpb.FieldOptions)
    so, ok := proto.GetExtension(opts, stroptpb.E_Opts).(*stroptpb.StringOpts)
    if !ok || so == nil {
    continue
    }
    44
    4-1. Examples using protoreflect - Custom regulations for String
    2-4: フィールドのOptionをチェックして取り出す
    Messageから生成されたStruct

    View full-size slide

  45. 1. Stringのフィールドか確認
    if fd.Kind() != protoreflect.StringKind {
    continue
    }
    2. protorefect.Messageから具体的な値を取得する (FieldDescriptorはあくまでデータ構造
    を取得するものなので、具体的なフィールドの値は得られない
    )
    strVal := m.Get(fd).Interface().(string)
    45
    4-1. Examples using protoreflect - Custom regulations for String
    2-5: フィールドの値をチェックして取り出す
    Proto用の型リストと比較
    protoreflect.Message

    View full-size slide

  46. func validateValue(fieldName protoreflect.Name, opts *stroptpb.StringOpts, v string) error {
    err = validateLength(opts, v)
    If err != nil {
    // error handling
    }
    // other validations...
    return errs
    }
    46
    4-1. Examples using protoreflect - Custom regulations for String
    2-6: 取り出したOptionと値を利用してバリデーションする
    func validateLength(opts *stroptpb.StringOpts, v string) error {
    }
    内容ごとのバリデーションの関数に、 Optionと値を渡す

    View full-size slide

  47. ● Message: フィールドのtypeがまたMessageだったときに対応させる
    ● List: StringのListに対応させる
    ● Map: ValueにStringを持つMapに対応させる
    47
    4-1. Examples using protoreflect - Custom regulations for String
    応用: Composite TypeのFieldに対応させる

    View full-size slide

  48. ● Message: フィールドのtypeがまたMessageだったときに対応させる
    -> フィールドの型で判定し、再帰処理を実行する
    ● List: StringのListに対応させる
      -> 専用のメソッドで判定し、List用のinterfaceに変換して処理する
    ● Map: ValueにStringを持つMapに対応させる
    -> 専用のメソッドで判定し、Map用のinterfaceに変換して処理する
    48
    4-1. Examples using protoreflect - Custom regulations for String
    応用: Composite Typeに対応させる

    View full-size slide

  49. フィールドのTypeを見て再帰呼び出しするだけでOK
    49
    4-1. Examples using protoreflect - Custom regulations for String
    Message: フィールドのTypeが別のMessageだったときに対
    応させる
    if fd.Kind() == protoreflect.MessageKind {
    errs = appendErr(errs, validate(m.Get(fd).Message()))
    continue
    }

    View full-size slide

  50. 専用のメソッドでListかチェックして、List用のinterfaceに変換した上でfor-loopを回
    すだけ
    50
    4-1. Examples using protoreflect - Custom regulations for String
    List: StringのListに対応させる
    if fd.IsList() && fd.Kind() == protoreflect.StringKind {
    strList := m.Get(fd).List()
    for i := 0; i < strList.Len(); i++ {
    strVal := strList.Get(i).Interface().(string)
    errs = appendErr(errs, validateValue(fd.Name(), so, strVal))
    }
    continue
    }
    Note: 通常(primitive type)のString用の条件分岐に入らないように注意
    ListのTypeは、Listの中に入る値の
    Typeになる

    View full-size slide

  51. 基本的にListと同じだけど、Type判定とloopの回し型が違う
    51
    4-1. Examples using protoreflect - Custom regulations for String
    Map: ValueにStringを持つMapに対応させる
    if fd.IsMap() {
    strMap := m.Get(fd).Map()
    strMap.Range(func(mk protoreflect.MapKey, mv protoreflect.Value) bool {
    strVal, ok := mv.Interface().(string)
    if !ok {
    // error handling
    return false
    }
    errs = appendErr(errs, validateValue(fd.Name(), so, strVal))
    return true
    })
    continue
    }
    Note: Map自体はMessage型になるので、Message型用の条件分岐に入らないように注意
    ValueのTypeを確認しにいく
    Rangeでloopできる

    View full-size slide

  52. 52
    4-1. Examples using protoreflect - Custom regulations for String
    Custom regulations for String - Summary
    このようにProtocol Buffersのデータ定義を読み込んだ処理ができるようになりました
    最終形はGitHubにあります
    https://github.com/sryoya/protoreflect-go-examples/blob/master/stropt/valid
    ate.go

    View full-size slide

  53. Agenda
    1. Introduction
    2. What’s Protocol Buffers?
    3. What’s Go Protocol Buffers API v2?
    4. Examples using protoreflect
    1. Custom regulations for String
    2. Random message struct generator
    53

    View full-size slide

  54. 54
    4-2. Examples using protoreflect - Random message struct generator
    作るもの: Random message struct generator
    概要
    ● Proto MessageのStructを受け取って、ランダムな値を埋め込んで返す
    ● Proto MessageのStructならなんでも扱えるようにする
    使い道の例
    Fuzzing, Performance Test

    View full-size slide

  55. 基本: 元のMessageの値にアクセスして書き換える
    protoreflect.Message Interfaceは値を直接書き換える共通のメソッドを提供してい

    応用: 別のMessage Structを用意して値を設定し、最後に、元の
    Structマージする
    dynamicpbという、proto.Messageのinterfaceを実装した動的なtypeを生成できるパッ
    ケージがある。dynamicpbで生成したMessageは、同じproto.Messageのstructとマージ
    して値を書き込むことができる。
    55
    4-2. Examples using protoreflect - Random message struct generator
    要点: protoreflectは、Message Structに値を直接書き込む
    手段も提供している

    View full-size slide

  56. func EmbedValue(msg proto.Message) error {
    pm := msg.ProtoReflect()
    fds := pm.Descriptor().Fields()
    for k := 0; k < fds.Len(); k++ {
    fd := fds.Get(k)
    // need handling for List and Map
    switch fd.Kind() {
    case protoreflect.StringKind:
    // write value
      // other types including recursion
    default:
    return fmt.Errorf("unexpected type: %v", fd.Kind())
    }
    }
    // ...
    }
    56
    4-2. Examples using protoreflect - Random message struct generator
    読み込みは前の例と同じ要領

    View full-size slide

  57. protoreflect.Message interfaceを介して、MessageのStructに書き込める
    switch fd.Kind() {
    case protoreflect.Int32Kind:
    pm.Set(fd, protoreflect.ValueOfInt32(rand.Int31()))
    // ...
    default:
    return fmt.Errorf("unexpected type: %v", fd.Kind())
    }
    57
    4-2. Examples using protoreflect - Random message struct generator
    基本: 元のMessageの値にアクセスして値を書き換える
    Protoreflectの型定義に変換
    Fieldに値をセットできる

    View full-size slide

  58. switch fd.Kind() {
    case protoreflect.MessageKind:
    // generate its child message
    pm.Set(fd, protoreflect.ValueofMessage(XXX)))
    default:
    return fmt.Errorf("unexpected type: %v", fd.Kind())
    }
    58
    4-2. Examples using protoreflect - Random message struct generator
    ただし、この方法だと再帰処理などで元のMessageに辿るこ
    とが面倒な場合がある
    親のMessageにセットするために、フィールドの
    Messageの値を用意しないといけない

    View full-size slide

  59. ● dynamicpbは、DescriptorからProtocol BuffersのMessageのStructを作成す
    るパッケージ
    https://pkg.go.dev/google.golang.org/protobuf/types/dynamicpb
    ● dynamicpbで生成した値を、protocコンパイラが生成したMessage Structに
    マージして値を書き換えることができる
    59
    4-2. Examples using protoreflect - Random message struct generator
    応用: dynamicpbを使えば、Messageの情報から、新規
    MessageのTypeを生成できる

    View full-size slide

  60. ● Goのコンパイル時点で具体的なGoのStructが手に入らない状況でも、
    Protocol Buffersのメッセージを作成できる
    ○ ex) Protocol Buffersに対する汎用のCLI, カスタムのCompilerなど
    ● 再帰処理とかで元のMessageのStructを取り出して書き込むのが面倒なときに
    も、dynamicpbで具体的な値を作って、元のMessageにマージできる
    ○ 今回のケース(ただし、dynamicpbを使わなくてもやる方法自体はある )
    60
    4-2. Examples using protoreflect - Random message struct generator
    応用: dynamicpbは、具体的なGoのMessage Structが手に
    入らない状況でも、Messageの値が用意できる

    View full-size slide

  61. 1. MessageDescriptorを渡すと、Messageの情報を持ったdynamicなMessage
    Structが作成できる
    dm := dynamicpb.NewMessage(m.ProtoReflect().Descriptor())
    2. dynamicpbのMessageにも、Proto.Messageと同じように値をセットできる
    dm.Set(fd, value)
    61
    4-2. Examples using protoreflect - Random message struct generator
    応用: dynamicpbに、Messageの情報を渡して、値を生成さ
    せる
    引数にいれる値は下記の通り
    1. フィールドの情報(FieldDescriptor)
    2. セットする値

    View full-size slide

  62. これで具体的な値が対象の Structにセットされる
    proto.Merge(msg, dm)
    62
    4-2. Examples using protoreflect - Random message struct generator
    応用: dynamicpbで生成したStructをProcol Buffersから生
    成されたMessage Structにマージする
    引数にいれる値は下記の通り
    1. セット先のMessage Struct
    2. セット元のMessage Struct(dynamic pbが生成した値)

    View full-size slide

  63. 最終形はGitHubへ
    https://github.com/sryoya/protoreflect-go-examples/tree/master/protorand
    63
    4-2. Examples using protoreflect - Random message struct generator
    Random message struct generator - Summary

    View full-size slide

  64. ● Go Protocol Buffers API v2では、MessageのInterfaceが充実され、
    reflectionの機能が提供された
    ● protoreflectパッケージを利用して、Protocol Buffersのデータ形式に沿った
    データの読み書きができる
    64
    まとめ

    View full-size slide

  65. 65
    Appendix - Go Protocol Buffers API v2のimport path
    ● google.golang.org/protobuf
    ○ ちなみにv1はgithub.com/golang/protobuf
    ● versionはv1.20.0から始まる
    ○ まだ提供されているv1(2021年4月現在でv1.5.2)がv1.20まで到達するこ
    とはないだろうかららしい

    View full-size slide

  66. 66
    Appendix - v2からのGoコード生成ツールと使用例
    ● protobufのGoコード生成
    ○ google.golang.org/protobuf/cmd/protoc-gen-go
    ● gRPCのGoコード生成
    ○ google.golang.org/grpc/cmd/protoc-gen-go-grpc
    ● コマンド例
    $ find . -name '*.proto' -exec protoc --experimental_allow_proto3_optional
    -I ./ --go_out . --go_opt paths=source_relative --go-grpc_out . --go-grpc_opt
    paths=source_relative {}

    View full-size slide

  67. 67
    Appendix - その他関連パッケージ
    ● protocmp
    ○ google.golang.org/protobuf/testing/protocmp
    ○ go-cmpを内包したテスト用のツール
    ● protojson
    ○ google.golang.org/protobuf/encoding/protojson
    ○ Jsonとprotobufの変換(v1の改良版)
    ● protogen
    ○ google.golang.org/protobuf/compiler/protogen
    ○ protobuf compilerの作成用のヘルパーツール

    View full-size slide

  68. 68
    Reference
    ● The Go Blog A new Go API for Protocol Buffers
    https://blog.golang.org/protobuf-apiv2
    ● protoreflect
    https://pkg.go.dev/google.golang.org/protobuf/reflect/protoreflect
    ● dynamicpb
    https://pkg.go.dev/google.golang.org/protobuf/types/dynamicpb

    View full-size slide

  69. EoF
    Gopherの原著作者は Renée Frenchさんです。
    69

    View full-size slide