Skip to main content

prost_protovalidate/
lib.rs

1//! Runtime validation for Protocol Buffer messages using
2//! [`buf.validate`](https://github.com/bufbuild/protovalidate) rules.
3//!
4//! This crate dynamically inspects `prost-reflect` message descriptors at runtime,
5//! compiles `buf.validate` constraint annotations (including CEL expressions),
6//! and evaluates them against concrete message instances.
7//!
8//! # Quick start
9//!
10//! For one-off validation, use the [`validate`] convenience function:
11//!
12//! ```rust,no_run
13//! # #[cfg(feature = "reflect")]
14//! # mod example {
15//! use prost_protovalidate::validate;
16//! # fn example(msg: impl prost_reflect::ReflectMessage) {
17//! match validate(&msg) {
18//!     Ok(()) => { /* message is valid */ }
19//!     Err(e) => eprintln!("validation failed: {e}"),
20//! }
21//! # }
22//! # }
23//! ```
24//!
25//! For repeated validations, construct a [`Validator`] once to cache compiled
26//! rules across calls:
27//!
28//! ```rust,no_run
29//! # #[cfg(feature = "reflect")]
30//! # mod example {
31//! use prost_protovalidate::Validator;
32//! # fn example(msg: impl prost_reflect::ReflectMessage) {
33//! let validator = Validator::new();
34//! validator.validate(&msg).expect("message should be valid");
35//! # }
36//! # }
37//! ```
38//!
39//! # Feature flags
40//!
41//! | Feature       | Default | Description |
42//! |---------------|---------|-------------|
43//! | `cel`         | Yes     | CEL expression evaluation and `chrono` time support (implies `reflect`). Disable for a lighter dependency footprint when only standard rules are used. |
44//! | `reflect`     | Yes (via `cel`) | Runtime reflection: the descriptor-driven [`Validator`], validation filters, `Violation` rule-path hydration, and the [`bridge`] module consumed by `prost-protovalidate-build`'s `runtime_bridge` generated code. Disable for a slim, `prost-reflect`-free build carrying only the [`Validate`] trait, [`Violation`]/[`ValidationError`], and the [`validators`] helpers used by `prost-protovalidate-build` generated code. |
45//! | `tonic`       | No      | Adds [`tonic`](https://docs.rs/tonic) integration: a `From<ValidationError> for tonic::Status` impl and a `ValidateRequest` extension trait so gRPC handlers can call `req.validate_inner()?`. |
46//! | `tonic-types` | No      | Implies `tonic`. Attaches a `google.rpc.BadRequest` detail with one `FieldViolation` per [`Violation`] to validation-failure statuses. |
47//!
48//! Without the `cel` feature, any message or field annotated with CEL
49//! expressions (via both `cel` and legacy `cel_expression`, including
50//! `buf.validate.predefined` rules) will produce a [`CompilationError`] at
51//! validation time. Standard rules (range checks, string constraints, format
52//! validators, etc.) work without `cel`.
53//!
54//! Without `reflect`, violations skip descriptor-based rule-path hydration:
55//! [`Violation::to_proto`] emits rule-path elements with names only (no
56//! `field_number`/`field_type` metadata). The string accessors
57//! ([`Violation::field_path`], [`Violation::rule_path`],
58//! [`Violation::rule_id`], [`Violation::message`]) are unaffected.
59//!
60//! # Error types
61//!
62//! | Type | When |
63//! |------|------|
64//! | [`ValidationError`] | One or more constraint violations detected |
65//! | [`CompilationError`] | A CEL expression or constraint definition failed to parse |
66//! | [`RuntimeError`] | An unexpected failure during evaluation |
67//!
68//! All three are unified under [`Error`].
69//!
70//! # Re-exported types
71//!
72//! The [`types`] module re-exports [`prost-protovalidate-types`](https://crates.io/crates/prost-protovalidate-types)
73//! so consumers do not need to depend on it directly.
74
75#![warn(missing_docs)]
76// The crate docs and `time` module link to reflection-only items
77// (`Validator`, `validate`, `ValidatorOption`, `ValidationOption`, and the
78// `Violation` enrichment accessors) that are `#[cfg(feature = "reflect")]`.
79// Under `--no-default-features` those links have no target; allow the broken
80// intra-doc link lint in that configuration only. The default/all-features
81// docs (docs.rs) still lint every link.
82#![cfg_attr(not(feature = "reflect"), allow(rustdoc::broken_intra_doc_links))]
83
84#[cfg(feature = "reflect")]
85pub mod bridge;
86#[cfg(feature = "reflect")]
87mod config;
88mod error;
89mod formats;
90pub mod time;
91#[cfg(feature = "tonic")]
92pub mod tonic;
93#[cfg(feature = "reflect")]
94mod validator;
95pub mod validators;
96mod violation;
97
98/// Re-export of [`prost-protovalidate-types`](https://crates.io/crates/prost-protovalidate-types)
99/// for accessing generated `buf.validate` proto types and descriptor pool.
100pub use prost_protovalidate_types as types;
101
102/// Re-export of [`regex`](https://crates.io/crates/regex) so generated validators
103/// from `prost-protovalidate-build` can construct compiled patterns without the
104/// consumer's `Cargo.toml` needing a direct `regex` dependency.
105pub use regex;
106
107#[cfg(feature = "reflect")]
108pub use config::{Filter, ValidationOption, ValidatorOption};
109pub use error::{CompilationError, Error, RuntimeError, ValidationError};
110#[cfg(feature = "reflect")]
111pub use validator::{Validator, validate};
112pub use violation::Violation;
113
114/// Compile-time validation for Protocol Buffer messages with generated validators.
115///
116/// This trait is implemented by `prost-protovalidate-build` for messages that
117/// have **only** standard `buf.validate` rules (no CEL expressions). Validators
118/// run through monomorphized direct field access at runtime — no
119/// `prost-reflect` transcoding, no CEL interpreter on the hot path. For
120/// messages using CEL expressions or a mix of standard + CEL rules, use the
121/// runtime [`Validator`] instead.
122///
123/// # Generated violations
124///
125/// Violations produced by generated validators have identical [`Violation::field_path()`],
126/// [`Violation::rule_id()`], [`Violation::rule_path()`], and [`Violation::message()`]
127/// as the runtime validator. The enrichment accessors
128/// ([`Violation::field_descriptor()`], [`Violation::field_value()`],
129/// [`Violation::rule_descriptor()`], [`Violation::rule_value()`]) return `None` —
130/// these require runtime reflection data not available in generated code.
131///
132/// # Errors
133///
134/// Returns [`ValidationError`] containing all constraint violations found.
135pub trait Validate {
136    /// Validate this message against its `buf.validate` rules.
137    ///
138    /// # Errors
139    /// Returns [`ValidationError`] containing all constraint violations found.
140    fn validate(&self) -> Result<(), ValidationError>;
141}
142
143/// Normalize protobuf Edition 2023 descriptors to proto3 format for
144/// compatibility with `prost-reflect` 0.16 which does not support editions.
145#[cfg(feature = "reflect")]
146pub use validator::editions::normalize_edition_descriptor_set;