0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

Protocol Buffersは、スキーマの中にはMin/MaxなどのValidationを標準ではサポートしていません。

最近、protovalidateというものが立ち上がってきています。
Goで使えるproto-gen-validateの後継とのことですが、protovalidateはGo, C++, Java, Python, TypeScript(coming soonとのこと)で使えるようになっていて、複雑なValidationもサポートしているとのです。

全体の解説は、こちらに素晴らしい記事がありますので
ここではPython版を使ってみようと思います。

環境準備

protovalidateを利用するために、buf cliをインストールします。
Dockerfileに下記を記載します。

buf cliは、サーバーにスキーマを送ってコード生成することもできるのですが、
セキュリティ上 問題になることもあるため、今回はprotocもインストールしてLocalでコード生成します。

ARG PROTOC_VERSION=27.2
ARG BUF_CLI_VERSION=1.34.0

# Install buf cli 
RUN curl -LO https://github.com/bufbuild/buf/releases/download/v${BUF_CLI_VERSION}/buf-Linux-x86_64.tar.gz \
    && tar -zxvf buf-Linux-x86_64.tar.gz \
    && cp -rf buf/bin/* /usr/bin  \
    && rm -rf ./*    
# Install protoc
RUN curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip \
    && unzip protoc-${PROTOC_VERSION}-linux-x86_64.zip  -d /usr/  \
    && rm  -rf ./*

buf cliの準備

buf.yamlを以下のように作成します。

version: v2
deps:
  - buf.build/bufbuild/protovalidate
lint:
  use:
    - DEFAULT
breaking:
  use:
    - FILE

buf.gen.yamlを以下のように作成します。今回はpythonとpyiを生成します。
pluginsの要素を追加すれば他の言語のコードも生成できます。

version: v2
plugins:
  - protoc_builtin: python
    out: gen
    include_imports: true
  - protoc_builtin: pyi
    out: gen
    include_imports: true

protocのコマンドより便利ですね。

スキーマ作成

例としてroi.protoを作成します。4000 x 3000の画像をCropするときの設定です。

VS codeで作業をする場合は、Bufを拡張機能としてインストールすると良いです。

syntax = "proto3";
package roi;

import "buf/validate/validate.proto";

message Roi {
  uint32 top = 1;
  uint32 left = 2;
  uint32 height = 3 [(buf.validate.field).uint32 = {gte: 1}];
  uint32 width = 4 [(buf.validate.field).uint32 = {gte: 1}];
  option (buf.validate.message).cel = {
    id: "roi.width_sum"
    message: "left + width <=  4000"
    expression: "this.left + this.width <= 4000"
  };
  option (buf.validate.message).cel = {
    id: "roi.height_sum"
    message: "top + height <=  3000"
    expression: "this.top + this.height <= 3000"
  };
}

package roi;の部分で警告が出ますが、今回は無視します。

コード生成

下記のコマンドで依存関係を取得します。buf.lockが生成されます。

buf dep update

下記のコマンドでコード生成を行います。

buf generate

genディレクトリ以下にroi_pb2.pyとその他のファイルが生成されます。

テスト

下記のコードでテストができます。
sys.path.appendは無理矢理感ありますが、とりあえずこれで動きます。

import sys
sys.path.append("gen")
import protovalidate
from gen.roi_pb2 import Roi

def validate_roi(roi):
    print(roi.top, roi.left,roi.height,roi.width)
    try:
        protovalidate.validate(roi)
        print("Validation Success")
    except protovalidate.ValidationError as e:
        print("Validation Failed")
        print(e.violations)
    
if __name__ == "__main__":
    validate_roi(Roi(left=0,top=0,width=4000,height=3000))
    validate_roi(Roi(left=10,top=10,width=0,height=0))
    validate_roi(Roi(left=0,top=1,width=4000,height=3000))

出力は下記です。Validationのどこで失敗したかもわかっていいですね。

0 0 3000 4000
Validation Success
10 10 0 0
Validation Failed
violations {
  field_path: "height"
  constraint_id: "uint32.gte"
  message: "value must be greater than or equal to 1"
}
violations {
  field_path: "width"
  constraint_id: "uint32.gte"
  message: "value must be greater than or equal to 1"
}

1 0 3000 4000
Validation Failed
violations {
  constraint_id: "roi.height_sum"
  message: "top + height <=  3000"
}

まとめ

protovalidateのpython版を使ってみました。

まだ、ベータ版とのことですが企業としてはSchema管理のSaaSもやっているようで、
既に複数の言語に対応しているため将来有望に思えます。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?