Migrate from protoc-gen-validate
Migrating from protoc-gen-validate
to Protovalidate should be safe, incremental, and relatively painless.
We recommend migrating to Protovalidate using the migration tool, but there may be cases where manual migration is required or preferred.
Each workflow is outlined below.
Note
Protovalidate doesn't require any code generation.
The protoc-gen-validate
plugin is no longer needed, and shouldn't be used with Protovalidate.
Using the migration tool
Prerequisites
-
Clone the
protovalidate
repo: -
Navigate to its directory:
Migration workflow
-
(Optional) Format Protobuf files
Though the migration tool does a best-effort attempt to preserve the formatting of the original file, it may produce valid but ill-formatted code. To reduce noise related to reformatting, run a formatter (such as
buf format
) over the corpus of.proto
files and commit its changes before proceeding. -
Run the migration tool
This first run adds matching Protovalidate annotations alongside any existing
protoc-gen-validate
annotations. Optionally, run the formatter again after the migration tool to clean up any strange output. -
Use Protovalidate
Update code that uses
protoc-gen-validate
code generation to consume the Protovalidate library instead (or simultaneously). -
(Optional) Update pre-existing Protovalidate annotations
Rerunning the migration tool is a no-op for any
.proto
files that already import Protovalidate. Replace any pre-existing annotations by running the tool with the--replace-protovalidate
flag. This ensures that these annotations matchprotoc-gen-validate
annotations. -
Remove
protoc-gen-validate
annotationsOnce you're ready to make the switch and have removed references to the
protoc-gen-validate
generated code, run the migration tool again with the--remove-legacy
flag to remove legacy annotations from.proto
files.
Usage and flags
-v
, --verbose
Enables verbose logging. Defaults to false
.
-w
, --write
Overwrites target files in-place. Defaults to false
.
-o
, --output
Writes output to the given path.
If omitted, and -w
isn't specified, modified Protobuf is emitted to stdout.
--legacy-import
Specifies a protoc-gen-validate
Protobuf import path. Defaults to validate/validate.proto
.
--protovalidate-import
Specifies a Protovalidate Protobuf import path. Defaults to buf/validate/validate.proto
.
--remove-legacy
Allows the program to remove protoc-gen-validate
options. Defaults to false
.
--replace-protovalidate
Replaces Protovalidate options to match protoc-gen-validate
options (only if present).
Defaults to false
.
Note
If neither -w
nor -o
is specified, modified Protobuf is emitted to stdout.
Migrating manually
-
Understand the changes
The first step to manual migration is understanding the changes between
protoc-gen-validate
and Protovalidate. Review the Standard constraint changes section of this guide to understand how constraints have changed. -
Update imports
Replace any imports of
validate/validate.proto
withbuf/validate/validate.proto
in your.proto
files. -
Update message-level constraints
Replace
(validate.ignored)
and(validate.disabled)
with the new(buf.validate.message)
option as described in the Message constraints section. -
Update oneof constraints
Replace
(validate.required)
for oneof fields with the new(buf.validate.oneof)
option as described in the Oneof constraints section. -
Update field-level constraints
Replace all field-level constraints, including
(validate.rules).<TYPE>.required
,(validate.rules).message.skip
, and(validate.rules).<TYPE>.ignore_empty
, with the new(buf.validate.field)
option as described in the Field constraints section. -
Remove unnecessary constraints
Remove the
(validate.rules).map.no_sparse
constraint, as it's not supported in Protovalidate. -
Test and validate
After performing the above steps, test your Protobuf code to ensure it's functioning as expected. Review any warnings or errors, making corrections as necessary.
Standard constraint changes
As part of the migration process, note the following changes to the
standard constraints between protoc-gen-validate
and Protovalidate:
Message constraints
-
All message-level constraints have moved into a single option:
(buf.validate.message)
. -
(validate.ignored)
has been removed. Protovalidate doesn't generate code, so generation doesn't need to be skipped. -
(validate.disabled)
has moved to(buf.validate.message).disabled
.
Oneof constraints
-
All oneof-level constraints have moved into a single option:
(buf.validate.oneof)
. -
(validate.required)
has moved to(buf.validate.oneof).required
.
Field constraints
-
All field-level constraints have moved into a single option:
(buf.validate.field)
. -
(validate.rules).<TYPE>.required
has moved to(buf.validate.field).required
. The semantics of "required" have changed and been clarified. Consult the field constraints API definition to ensure they match expectations compared to their behavior inprotoc-gen-validate
. -
(validate.rules).message.skip
has been replaced by setting(buf.validate.field).ignore
toIGNORE_ALWAYS
. Consult the ignore API definition to see which semantics match expectations. -
(validate.rules).<TYPE>.ignore_empty
has been replaced by setting(buf.validate.field).ignore
toIGNORE_IF_UNPOPULATED
. Consult the ignore API definition to see which semantics match expectations. -
(validate.rules).map.no_sparse
has been removed. The original rule accommodated for a situation that was exclusively possible in Go code generation. Protovalidate now treats a sparse map value as an empty value, matching the semantics of the Go Protobuf runtime.