protovalidate-buffa-macros-v0.3.1
protovalidate-buffa-macros v0.3.1
#[connect_impl] just levelled up. This patch release teaches the macro to recognise Connect 0.7's ServiceRequest<'_, T> request parameters alongside the existing OwnedView<T> support — meaning your service impls get automatic, zero-boilerplate proto validation regardless of which request wrapper your handlers use. One attribute, every handler covered, no per-method discipline required. The full upstream conformance suite remains at a perfect 2872 / 2872 (100%) across proto2, proto3, and editions 2023.
🐛 Bug Fixes
#[connect_impl] now validates ServiceRequest handlers
Prior to this release, the macro only injected validate()? into handlers whose request parameter was typed as OwnedView<_>. Handlers using Connect 0.7's connectrpc::ServiceRequest<'_, T> wrapper were silently skipped — no validation, no error, just a gap in your safety net.
Before (validation was not injected):
#[connect_impl]
impl UserService for UserServiceImpl {
async fn create_user(
&self,
ctx: Context,
request: connectrpc::ServiceRequest<'_, pb::CreateUserRequest>,
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Previously ignored by #[connect_impl] — no validate()!
) -> Result<(pb::CreateUserResponse, Context), ConnectError> {
// User code ran even on invalid requests. Oops.
}
}After (validation is injected automatically):
#[connect_impl]
impl UserService for UserServiceImpl {
async fn create_user(
&self,
ctx: Context,
request: connectrpc::ServiceRequest<'_, pb::CreateUserRequest>,
) -> Result<(pb::CreateUserResponse, Context), ConnectError> {
// #[connect_impl] now validates the request here automatically.
// Body only sees already-validated requests — for both OwnedView and ServiceRequest.
}
}The macro now recognises both OwnedView<_> and ServiceRequest<'_, _> as handler request parameters and injects validation for either. Non-handler methods that lack a recognised request parameter continue to be left untouched.
If you match on validation errors, remember to use the typed fields — not stringly-typed rule ID prefixes:
match req.validate() {
Ok(()) => { /* proceed */ }
Err(e) if e.compile_error.is_some() => {
// Schema mismatch caught at codegen time — should not reach production
panic!("codegen schema error: {:?}", e.compile_error);
}
Err(e) if e.runtime_error.is_some() => {
// Rule precondition failed at runtime (e.g. non-UTF-8 bytes under `pattern`)
return Err(e.into_connect_error());
}
Err(e) => {
// One or more field violations
return Err(e.into_connect_error());
}
}Getting Started
Library consumers
Add to your Cargo.toml:
[dependencies]
protovalidate-buffa = "0.5.1" # re-exports #[connect_impl] and the full runtimeThe #[connect_impl] macro is gated behind the connect feature (enabled by default). If you want the macros crate directly:
[dependencies]
protovalidate-buffa-macros = "0.3.1"Codegen plugin
cargo install \
--git https://github.com/mathematic-inc/protovalidate-buffa \
--tag protovalidate-buffa-macros-v0.3.1 \
protoc-gen-protovalidate-buffaThen wire it into buf.gen.yaml:
plugins:
- local: protoc-gen-protovalidate-buffa
out: gen/protovalidate
strategy: allHappy validating! 🛡️