アルパカ三銃士

〜アルパカに酔いしれる獣たちへ捧げる〜

Go + gRPC でメタ情報も送れるファイルアップローダーを書いた

今回は Go + gRPC でファイルアップローダーを書いたので紹介します。しかも、ファイルのアップロードだけではなくメタデータも同時に送れるように作成しました。

イメージ

今回作成するにあたって、次のようなイメージで作成しました。

  1. 前提は stream 通信(ファイルのアップロードに必要不可欠)
  2. クライアントから送信したいファイルのメタ情報を送る
  3. ファイルデータを少しずつ送信
  4. 結果を受け取る

seq

アップロード周りの protobuf

これを実現するために oneof を用いました。

理由としては次の通りです。

If you have a message with many fields and where at most one field will be set at the same time, you can enforce this behavior and save memory by using the oneof feature.

要するに最大で一つのフィールドを扱うのでメモリを節約することができる利点があるのです。(C 言語でいう union のような機能)

定義は次の通りです。

service FileUploader {
    rpc Upload(stream FileRequestType) returns (ResultResponseType) {};
}

message ChunkType {
    bytes data = 1;
}

message FileHeaderType {
    string name = 1;
    int64 size = 2;
    message MIMEHeaderType {
        string key = 1;
        repeated string values = 2;
    }
    repeated MIMEHeaderType header = 3;
}

message FileRequestType {
    oneof File {
        ChunkType chunk = 1;
        FileHeaderType header = 2;
    }
}
  • ChunkType には bytes の型のフィールドを持たせています。これはファイルのアップロードのために利用されます
  • FileHeaderType にはファイルのメタ情報が含まれます。今回持たせているメタ情報は以下の通りです
    • ファイル名
    • ファイルサイズ
    • MIMEHeaderType という名前にしてますが、本来はリクエストヘッダと同じようにあるキーに対して値を持つことを想定しています。なので本当は型名を HeaderType とした方が良さそう
      • 今回は content-type をキーにしてファイルの拡張子に合わせた MIME を設定しています

所感

  • http リクエストと同じようにファイルアップロードする際にメタ情報を同時に送れるので gRPC でファイルアップローダーを作ろうと思えば作れることも分かった
  • multipart/form-data としての振る舞いも行うことができそう

ソースコードを公開してるので良かったらどうぞ

github.com

参考

ops.tips