|
1 | | - |
| 1 | + |
2 | 2 |
|
3 | | -# protovalidate |
| 3 | +# Protovalidate |
4 | 4 |
|
5 | 5 | [][ci] |
6 | 6 | [][slack] |
7 | 7 | [][buf-mod] |
8 | 8 |
|
9 | | -`protovalidate` is a series of libraries designed to validate Protobuf messages at |
10 | | -runtime based on user-defined validation rules. Powered by Google's Common |
11 | | -Expression Language ([CEL][cel-spec]), it provides a |
12 | | -flexible and efficient foundation for defining and evaluating custom validation |
13 | | -rules. The primary goal of `protovalidate` is to help developers ensure data |
14 | | -consistency and integrity across the network without requiring generated code. |
| 9 | +[Protovalidate][protovalidate] provides standard annotations to validate common constraints on messages and fields, as well as the ability to use [CEL][cel] to write custom constraints. It's the next generation of [protoc-gen-validate][protoc-gen-validate], the only widely used validation library for Protobuf. |
15 | 10 |
|
16 | | -> [!NOTE] |
17 | | -> If you are migrating from [protoc-gen-validate][pgv], read our [migration guide][migration-guide]. |
18 | | -
|
19 | | -## What is this repository? |
20 | | - |
21 | | -This repository is the core of the `protovalidate` project. It contains: |
22 | | - |
23 | | -- [The API definition][validate-proto]: used to describe validation constraints |
24 | | -- [Documentation][docs]: how to apply `protovalidate` effectively |
25 | | -- [Migration tooling][migrate]: incrementally migrate from `protoc-gen-validate` |
26 | | -- [Examples][examples]: example `.proto` files using `protovalidate` |
27 | | -- [Conformance testing utilities][conformance]: for acceptance testing of `protovalidate` implementations |
28 | | - |
29 | | -### Implementations |
30 | | - |
31 | | -Runtime implementations of `protovalidate` can be found in their own repositories: |
32 | | - |
33 | | -- Go: [`protovalidate-go`][pv-go] (beta release) |
34 | | -- C++: [`protovalidate-cc`][pv-cc] (beta release) |
35 | | -- Java: [`protovalidate-java`][pv-java] (beta release) |
36 | | -- Python: [`protovalidate-python`][pv-python] (beta release) |
37 | | -- TypeScript: `protovalidate-ts` (coming soon) |
38 | | - |
39 | | -Interested in adding support for another language? Check out our |
40 | | -[Contributing Guidelines][contributing]. |
41 | | - |
42 | | -## Usage |
43 | | - |
44 | | -### Import protovalidate |
45 | | - |
46 | | -To define constraints within your Protobuf messages, |
47 | | -import `buf/validate/validate.proto` into your `.proto` files: |
| 11 | +With Protovalidate, you can annotate your Protobuf messages with both standard and custom validation rules: |
48 | 12 |
|
49 | 13 | ```protobuf |
50 | 14 | syntax = "proto3"; |
51 | 15 |
|
52 | | -package my.package; |
| 16 | +package banking.v1; |
53 | 17 |
|
54 | 18 | import "buf/validate/validate.proto"; |
55 | | -``` |
56 | | - |
57 | | -#### Build with [`buf`][buf] |
58 | 19 |
|
59 | | -Add a dependency on [`buf.build/bufbuild/protovalidate`][buf-mod] to your |
60 | | -module's [`buf.yaml`][buf-deps]: |
61 | | - |
62 | | -```yaml |
63 | | -version: v1 |
64 | | -# <snip> |
65 | | -deps: |
66 | | - - buf.build/bufbuild/protovalidate |
67 | | -# <snip> |
| 20 | +message MoneyTransfer { |
| 21 | + string to_account_id = 1 [ |
| 22 | + // Standard rule: `to_account_id` must be a UUID |
| 23 | + (buf.validate.field).string.uuid = true |
| 24 | + ]; |
| 25 | +
|
| 26 | + string from_account_id = 2 [ |
| 27 | + // Standard rule: `from_account_id` must be a UUID |
| 28 | + (buf.validate.field).string.uuid = true |
| 29 | + ]; |
| 30 | +
|
| 31 | + // Custom rule: `to_account_id` and `from_account_id` can't be the same. |
| 32 | + option (buf.validate.message).cel = { |
| 33 | + id: "to_account_id.not.from_account_id" |
| 34 | + message: "to_account_id and from_account_id should not be the same value" |
| 35 | + expression: "this.to_account_id != this.from_account_id" |
| 36 | + }; |
| 37 | +} |
68 | 38 | ``` |
69 | 39 |
|
70 | | -After modifying your `buf.yaml`, don't forget to run `buf mod update` to ensure |
71 | | -your dependencies are up-to-date. |
72 | | - |
73 | | -#### Build with `protoc` |
74 | | - |
75 | | -Add an import path (`-I` flag) pointing to the contents of the `proto/protovalidate` |
76 | | -directory to your invocation of `protoc`: |
77 | | - |
78 | | -```shell |
79 | | -protoc \ |
80 | | - -I ./vendor/protovalidate/proto/protovalidate \ |
81 | | - # <snip> |
82 | | -``` |
83 | | - |
84 | | -### Implementing validation constraints |
85 | | - |
86 | | -Validation constraints can be enforced using the `buf.validate` Protobuf package. The rules are specified directly in the `.proto` files. |
87 | | - |
88 | | -Let's consider a few examples: |
89 | | - |
90 | | -1. **Scalar field validation:** For a basic `User` message, we can enforce constraints such as a minimum length for the user's name. |
91 | | - |
92 | | - ```protobuf |
93 | | - syntax = "proto3"; |
94 | | -
|
95 | | - import "buf/validate/validate.proto"; |
96 | | -
|
97 | | - message User { |
98 | | - // User's name, must be at least 1 character long. |
99 | | - string name = 1 [(buf.validate.field).string.min_len = 1]; |
100 | | - } |
101 | | - ``` |
102 | | - |
103 | | -2. **Map field validation:** For a `Product` message with a map of item quantities, we can ensure that all quantities are positive. |
104 | | - |
105 | | - ```protobuf |
106 | | - syntax = "proto3"; |
107 | | -
|
108 | | - import "buf/validate/validate.proto"; |
109 | | -
|
110 | | - message Product { |
111 | | - // Map of item quantities, all quantities must be positive. |
112 | | - map<string, int32> item_quantities = 1 [(buf.validate.field).map.values.int32.gt = 0]; |
113 | | - } |
114 | | - ``` |
115 | | - |
116 | | -3. **Well-known type (WKT) validation:** For the `User` message, we can add a constraint to ensure the `created_at` timestamp is in the past. |
| 40 | +## Supported Languages |
117 | 41 |
|
118 | | - ```protobuf |
119 | | - syntax = "proto3"; |
| 42 | +This repository is the Protovalidate core: the Protobuf definition of its API and [conformance testing utilities][conformance]. |
120 | 43 |
|
121 | | - import "google/protobuf/timestamp.proto"; |
122 | | - import "buf/validate/validate.proto"; |
| 44 | +To start using Protovalidate in your projects, see the [developer quickstart][quickstart], [Protovalidate overview][protovalidate], or go directly to the repository for your language of choice: |
123 | 45 |
|
124 | | - message User { |
125 | | - // User's creation date must be in the past. |
126 | | - google.protobuf.Timestamp created_at = 1 [(buf.validate.field).timestamp.lt_now = true]; |
127 | | - } |
128 | | - ``` |
| 46 | +- [`protovalidate-go`][pv-go] (Go) |
| 47 | +- [`protovalidate-java`][pv-java] (Java) |
| 48 | +- [`protovalidate-python`][pv-python] (Python) |
| 49 | +- [`protovalidate-cc`][pv-cc] (C++) |
| 50 | +- `protovalidate-es` (TypeScript and JavaScript, coming soon!) |
129 | 51 |
|
130 | | -For more advanced or custom constraints, `protovalidate` allows for CEL expressions that can incorporate information across fields. |
131 | | - |
132 | | -1. **Field-level expressions:** We can enforce that a products' `price`, sent as a string, includes a currency symbol like "$" or "£". We want to ensure that the price is positive and the currency symbol is valid. |
133 | | - |
134 | | - ```protobuf |
135 | | - syntax = "proto3"; |
136 | | -
|
137 | | - import "buf/validate/validate.proto"; |
138 | | -
|
139 | | - message Product { |
140 | | - string price = 1 [(buf.validate.field).cel = { |
141 | | - id: "product.price", |
142 | | - message: "Price must be positive and include a valid currency symbol ($ or £)", |
143 | | - expression: "(this.startsWith('$') || this.startsWith('£')) && double(this.substring(1)) > 0" |
144 | | - }]; |
145 | | - } |
146 | | - ``` |
147 | | - |
148 | | -2. **Message-level expressions:** For a `Transaction` message, we can use a message-level CEL expression to ensure that the `delivery_date` is always after the `purchase_date`. |
149 | | - |
150 | | - ```protobuf |
151 | | - syntax = "proto3"; |
152 | | -
|
153 | | - import "google/protobuf/timestamp.proto"; |
154 | | - import "buf/validate/validate.proto"; |
155 | | -
|
156 | | - message Transaction { |
157 | | - google.protobuf.Timestamp purchase_date = 1; |
158 | | - google.protobuf.Timestamp delivery_date = 2; |
159 | | -
|
160 | | - option (buf.validate.message).cel = { |
161 | | - id: "transaction.delivery_date", |
162 | | - message: "Delivery date must be after purchase date", |
163 | | - expression: "this.delivery_date > this.purchase_date" |
164 | | - }; |
165 | | - } |
166 | | - ``` |
167 | | - |
168 | | -3. **Producing an error message in the expression:** We can produce custom error messages directly in the CEL expressions. In this example, if the `age` is less than 18, the CEL expression will evaluate to the error message string. |
169 | | - |
170 | | - ```protobuf |
171 | | - syntax = "proto3"; |
172 | | -
|
173 | | - import "buf/validate/validate.proto"; |
174 | | -
|
175 | | - message User { |
176 | | - int32 age = 1 [(buf.validate.field).cel = { |
177 | | - id: "user.age", |
178 | | - expression: "this < 18 ? 'User must be at least 18 years old': ''" |
179 | | - }]; |
180 | | - } |
181 | | - ``` |
182 | | - |
183 | | -Check out [`examples`][examples] for examples on both standard constraints and custom CEL constraints. |
184 | | - |
185 | | -### Validate Messages |
186 | | - |
187 | | -Once the messages are annotated with constraints, use one of the [supported language libraries](#implementations) to validate; no additional code generation necessary. |
| 52 | +> [!NOTE] |
| 53 | +> Interested in adding support for another language? Check out our [Contributing Guidelines][contributing]. |
188 | 54 |
|
189 | 55 | ## Documentation |
190 | 56 |
|
191 | | -`protovalidate` provides a robust framework for validating Protobuf messages by |
192 | | -enforcing standard and custom constraints on various data types, and offering |
193 | | -detailed error information when validation violations occur. For a detailed |
194 | | -overview of all its components, the supported constraints, and how to use them |
195 | | -effectively, please refer to our [comprehensive documentation](docs/README.md). |
196 | | -The key components include: |
197 | | - |
198 | | -- [**Standard Constraints**](https://github.com/bufbuild/protovalidate/blob/main/docs/standard-constraints.md): `protovalidate` |
199 | | - supports a wide range of standard |
200 | | - constraints for all field types as well as special functionality for the |
201 | | - Protobuf Well-Known-Types. You can apply these constraints to your Protobuf |
202 | | - messages to ensure they meet certain common conditions. |
| 57 | +Comprehensive documentation for Protovalidate is available in [Buf's documentation library][protovalidate]. |
203 | 58 |
|
204 | | -- [**Custom Constraints**](https://github.com/bufbuild/protovalidate/blob/main/docs/custom-constraints.md): With Google's Common |
205 | | - Expression Language (CEL), |
206 | | - `protovalidate` allows you to create complex, custom constraints to |
207 | | - handle unique validation scenarios that aren't covered by the standard |
208 | | - constraints at both the field and message level. |
| 59 | +Highlights include: |
209 | 60 |
|
210 | | -- [**Error Handling**](https://github.com/bufbuild/protovalidate/blob/main/docs/README.md#errors): When a violation |
211 | | - occurs, `protovalidate` provides |
212 | | - detailed error information to help you quickly identify the source and fix for |
213 | | - an issue. |
| 61 | +* The [developer quickstart][quickstart] |
| 62 | +* Comprehensive RPC quickstarts for [Connect and Go][connect-go], [gRPC and Go][grpc-go], [gRPC and Java][grpc-java], and [gRPC and Python][grpc-python] |
| 63 | +* A [migration guide for protoc-gen-validate][migration-guide] users |
214 | 64 |
|
215 | | -### protoc-gen-validate |
| 65 | +## Contribution |
216 | 66 |
|
217 | | -`protovalidate` is the spiritual successor to [`protoc-gen-validate`][pgv], offering |
218 | | -all of the same functionality present in the original plugin, without the need |
219 | | -for custom code generation, and the new ability to describe complex constraints in CEL. |
| 67 | +We genuinely appreciate any help! If you'd like to contribute, check out these resources: |
220 | 68 |
|
221 | | -`protovalidate`'s constraints very closely emulate those |
222 | | -in `protoc-gen-validate` to ensure an easy transition for developers. To |
223 | | -migrate from `protoc-gen-validate` to `protovalidate`, use the |
224 | | -provided [migration tool][migration-tool] to |
225 | | -incrementally upgrade your `.proto` files. |
| 69 | +- [Contributing Guidelines][contributing]: Guidelines to make your contribution process straightforward and meaningful |
| 70 | +- [Conformance testing utilities](https://github.com/bufbuild/protovalidate/tree/main/docs/conformance.md): Utilities providing acceptance testing of `protovalidate` implementations |
226 | 71 |
|
227 | | -## Ecosystem |
| 72 | +## Related Sites |
228 | 73 |
|
229 | | -- [Buf][buf] |
230 | | -- [CEL Specification][cel-spec] |
| 74 | +- [Buf][buf]: Enterprise-grade Kafka and gRPC for the modern age |
| 75 | +- [Common Expression Language (CEL)][cel]: The open-source technology at the core of Protovalidate |
231 | 76 |
|
232 | 77 | ## Legal |
233 | 78 |
|
234 | 79 | Offered under the [Apache 2 license][license]. |
235 | 80 |
|
236 | | -[announce]: https://buf.build/blog/protoc-gen-validate-v1-and-v2/ |
237 | | -[buf-deps]: https://buf.build/docs/configuration/v1/buf-yaml/#deps |
238 | | -[buf-mod]: https://buf.build/bufbuild/protovalidate |
239 | 81 | [buf]: https://buf.build |
240 | | -[cel-spec]: https://github.com/google/cel-spec |
241 | | -[ci]: https://github.com/bufbuild/protovalidate/actions/workflows/ci.yaml |
242 | | -[conformance]: https://github.com/bufbuild/protovalidate/blob/main/docs/conformance.md |
243 | | -[contributing]: https://github.com/bufbuild/protovalidate/blob/main/.github/CONTRIBUTING.md |
244 | | -[docs]: https://github.com/bufbuild/protovalidate/blob/main/docs |
245 | | -[examples]: https://github.com/bufbuild/protovalidate/tree/main/examples |
246 | | -[file-bug]: https://github.com/bufbuild/protovalidate/issues/new?assignees=&labels=Bug&template=bug_report.md&title=%5BBUG%5D |
247 | | -[file-feature-request]: https://github.com/bufbuild/protovalidate/issues/new?assignees=&labels=Feature&template=feature_request.md&title=%5BFeature+Request%5D |
248 | | -[license]: https://github.com/bufbuild/protovalidate/blob/main/LICENSE |
249 | | -[migrate]: https://buf.build/docs/migration-guides/migrate-from-protoc-gen-validate/ |
250 | | -[migration-tool]: https://github.com/bufbuild/protovalidate/blob/main/tools/protovalidate-migrate |
251 | | -[pgv]: https://github.com/bufbuild/protoc-gen-validate |
| 82 | +[cel]: https://cel.dev |
| 83 | + |
252 | 84 | [pv-go]: https://github.com/bufbuild/protovalidate-go |
253 | | -[pv-cc]: https://github.com/bufbuild/protovalidate-cc |
254 | 85 | [pv-java]: https://github.com/bufbuild/protovalidate-java |
255 | 86 | [pv-python]: https://github.com/bufbuild/protovalidate-python |
| 87 | +[pv-cc]: https://github.com/bufbuild/protovalidate-cc |
| 88 | + |
| 89 | +[buf-mod]: https://buf.build/bufbuild/protovalidate |
256 | 90 | [slack]: https://buf.build/links/slack |
257 | | -[validate-proto]: https://buf.build/bufbuild/protovalidate/docs/main:buf.validate |
| 91 | +[license]: LICENSE |
| 92 | +[contributing]: .github/CONTRIBUTING.md |
| 93 | + |
| 94 | +[protoc-gen-validate]: https://github.com/bufbuild/protoc-gen-validate |
| 95 | +[conformance]: https://github.com/bufbuild/protovalidate/blob/main/docs/conformance.md |
| 96 | +[ci]: https://github.com/bufbuild/protovalidate/actions/workflows/ci.yaml |
| 97 | + |
| 98 | +[protovalidate]: https://buf.build/docs/protovalidate/ |
| 99 | +[quickstart]: https://buf.build/docs/protovalidate/quickstart/ |
| 100 | +[connect-go]: https://buf.build/docs/protovalidate/quickstart/connect-go/ |
| 101 | +[grpc-go]: https://buf.build/docs/protovalidate/quickstart/grpc-go/ |
| 102 | +[grpc-java]: https://buf.build/docs/protovalidate/quickstart/grpc-java/ |
| 103 | +[grpc-python]: https://buf.build/docs/protovalidate/quickstart/grpc-python/ |
258 | 104 | [migration-guide]: https://buf.build/docs/migration-guides/migrate-from-protoc-gen-validate/ |
0 commit comments