痒いところに手が届くprotocol buffersの書き方

最近swaggerをprotoに移植する作業をしたので、その過程で調べたことをメモする。
主にprotocol buffersからprotoc-gen-swaggerを使ってswaggerをgenerateする人向け。

### descriptionやexampleの文字列を改行する
```
message IdName {
    option (grpc.gateway.protoc_gen_swagger.options.openapiv2_schema) = {
        json_schema: {
            description: "情報"
                         "テスト"
            required: [
                "id",
                "name"
            ]
        }
        example: { 
            value: "{" 
                        '"id": "1",'
                        '"name": "田中 太郎"'
                    "}"
        }
    };

    int32 id = 1 [(grpc.gateway.protoc_gen_swagger.options.openapiv2_field) = {
        description: "primary key"
    }];

    string name = 2 [(grpc.gateway.protoc_gen_swagger.options.openapiv2_field) = {
        description: "name"
    }];
}
```


### response_bodyのトップレベルをobjectではなく配列にする
```
{
  "users": [
    {
      "id": "1",
      "name": "test"
    },
    {
      "id": "2",
      "name": "test2"
    }
  ]
}
```

ではなく、

```
[
  {
    "id": "1",
    "name": "test"
  },
  {
    "id": "2",
    "name": "test2"
  }
]
```

にしたい
その場合はresponse_bodyに指定する

```
message IdNameResponse {
    repeated IdName id_names = 1 [(grpc.gateway.protoc_gen_swagger.options.openapiv2_field) = {
        description: "id name array"
    }];
}

rpc GetIdName(google.protobuf.Empty) returns (user.IdNameResponse) {
    option (google.api.http) = {
        get: "/user/id_name"
        response_body: "id_names"
    };
}
```
protoc-gen-swaggerを実行する際に、以下のoptionをつける必要がある

```
allow_repeated_fields_in_body=true
```

### headersの定義
IDはreserveされているものの、未実装
なのでextensionを使って表現する
参考: https://github.com/grpc-ecosystem/grpc-gateway/blob/e1a127c6f7cf2006c77a16dbc0face2a43f2094a/protoc-gen-swagger/options/openapiv2.proto#L85

```
rpc GetIdName(google.protobuf.Empty) returns (user.IdName) {
    option (google.api.http) = {
        get: "/user/id_name"
    };
    option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = {
    description: "Get user's id and name"
    extensions: {
		key: "x-hoge";
		value {
			string_value: "integer";
		}
    };
}
```

### 200以外のresponseの追加
どうやら現状では200を201にするとかはできないらしい
参考: https://github.com/grpc-ecosystem/grpc-gateway/issues/517#issuecomment-536180156
なので、200レスポンスも出てしまうが、201も併記する

```
rpc CreateIdName(user.IdName) returns (user.IdName) {
    option (google.api.http) = {
        post: "/user/id_name"
        body : "*"
    };
    option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = {
        description: "Create user"
        responses: {
            key: "201";
            value: {
                description: "Successful response"
                schema: {
                    json_schema: {
                        ref: ".user.IdName";
                    }
                }
            }
        };
        responses: {
            key: "401";
            value: {
                description: "Unauthorized"
                schema: {
                    json_schema: {
                        ref: ".error.Error";
                    }
                }
            }
        };
    };
}
```


### defaultの入れ方
```
int32 id = 1 [(grpc.gateway.protoc_gen_swagger.options.openapiv2_field) = {
    description: "primary key"
    default: "1"
}];
```

defaultはstringなのでintegerであっても文字列で入れてやる必要がある

### その他tips
#### IDを自動で振り直す
- https://github.com/ripwu/vscode-ext-protobuf-helper
VScodeなら↑の拡張を入れると、自動でIDを振り直してくれる