Overview
protovalidate でリクエスト内に定義した時刻型の検証を書いたときに考えたことを備忘録としてメモっておきます。
1. そのまま prorovalidate を書く
string start_datetime = 3 [(buf.validate.field).string = {pattern: "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}[+-]\\d{2}:\\d{2}$"}];
そのままですね。こんな感じで都度検証したい時刻の書式(このサンプルは RFC 3339)を正規表現で書きます。
2. 外部の定義を利用する
google/protobuf/timestamp.proto を利用する
下記のブログを参考にしました。
型定義は以下。
これは Go だと google.golang.org/protobuf/types/known/timestamppb.Timestamp
型になって利用できます。
type Timestamp struct { // Represents seconds of UTC time since Unix epoch // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to // 9999-12-31T23:59:59Z inclusive. Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"` // Non-negative fractions of a second at nanosecond resolution. Negative // second values with fractions must still have non-negative nanos values // that count forward in time. Must be from 0 to 999,999,999 // inclusive. Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"` // contains filtered or unexported fields }
ref:https://pkg.go.dev/google.golang.org/protobuf@v1.36.7/types/known/timestamppb#Timestamp
アプリケーションの中で time.Time
型として扱いたいときは、 AsTime メソッドを利用します。
googleapis/googleapis/datetime.proto を利用する
自公の 外部定義としては buf.build/googleapis/googleapis
配下の datetime.proto
も利用できます。
これは timestamppb.Timestamp
と異なり Datetime
形式で時刻を定義、検証ができます。
実際の定義 は以下。
GoDoc は以下。
timestamppb
型に比べるとこちらの方が直感的で使いやすいんじゃないかなと思います。
その他
google/protobuf は外部の定義を確認したいときに確認する
以下に色んな型が定義されているので定期的に参照すると良さそう。
カスタムエラーメッセージを定義する
時刻型に限った話じゃないのですが、validation のエラーが発生したとき、そのエラーメッセージをそのまま返してしまうと、思わぬアプリケーション内部の情報をクライアントに伝えてしまうことになるので、 proto 内の validation の内部で定義して、それをクライアントに返すようにしたい場合、CEL 記法を使って validation を拡張できます。
string start_datetime = 1 [(buf.validate.field) = { cel: { id: "start_datetime.format" message: "開始日時はRFC3339形式(例: 2024-03-20T19:00:00+09:00)で入力してください" expression: "this.matches('^\\\\d{4}-\\\\d{2}-\\\\d{2}T\\\\d{2}:\\\\d{2}:\\\\d{2}[+-]\\\\d{2}:\\\\d{2}$')" } }];
デフォルトでは protovalidation の結果が返却されますが、上記の場合 message
に指定したメッセージが返されます。