1#include <userver/grpc-protovalidate/validate.hpp>
11#include <google/protobuf/arena.h>
12#include <google/protobuf/message.h>
13#include <google/protobuf/repeated_ptr_field.h>
14#include <google/rpc/status.pb.h>
15#include <grpcpp/support/status.h>
17#include <grpc-protovalidate/impl/utils.hpp>
18#include <userver/compiler/thread_local.hpp>
19#include <userver/grpc-protovalidate/buf_validate.hpp>
20#include <userver/ugrpc/status_utils.hpp>
21#include <userver/utils/assert.hpp>
23USERVER_NAMESPACE_BEGIN
25namespace grpc_protovalidate {
29compiler::ThreadLocal kValidatorFactory = [] {
return impl::CreateProtoValidatorFactory(); };
33ValidationError::ValidationError(Type type, std::string description, std::string message_name)
35 description_(fmt::format(
"Message '{}' validation error: {}", message_name, std::move(description))),
36 result_(std::nullopt),
37 message_name_(std::move(message_name))
40ValidationError::ValidationError(buf::validate::ValidationResult result, std::string message_name)
42 description_(fmt::format(
43 "Message '{}' validation error: {} constraint(s) violated",
45 result.violations_size()
47 result_(std::move(result)),
48 message_name_(std::move(message_name))
51ValidationError::Type ValidationError::GetType()
const {
return type_; }
53const std::string& ValidationError::GetMessageName()
const {
return message_name_; }
55const std::string& ValidationError::GetDescription()
const {
return description_; }
57const std::vector<buf::validate::RuleViolation>& ValidationError::GetViolations()
const {
58 if (GetType() == Type::kInternal || !result_.has_value()) {
59 static constexpr std::vector<buf::validate::RuleViolation> kNoViolations;
62 return result_->violations();
65grpc::Status ValidationError::GetGrpcStatus(
bool include_violations, grpc::StatusCode rule_violation_status)
const {
66 google::rpc::Status gstatus;
67 gstatus.set_message(GetDescription());
70 gstatus.set_code(grpc::StatusCode::INTERNAL);
73 gstatus.set_code(rule_violation_status);
77 if (include_violations) {
78 gstatus.add_details()->PackFrom(MakeViolationsProto());
80 return ugrpc::ToGrpcStatus(gstatus);
83buf::validate::Violations ValidationError::MakeViolationsProto()
const {
84 buf::validate::Violations proto;
85 std::ranges::transform(
87 RepeatedPtrFieldBackInserter(proto.mutable_violations()),
88 [](
const buf::validate::RuleViolation& violation) {
return violation.proto(); }
93logging::LogHelper& operator<<(logging::LogHelper& lh,
const ValidationError& error) {
94 lh << error.GetDescription();
95 for (
const buf::validate::RuleViolation& violation : error.GetViolations()) {
96 lh << violation.proto();
101ValidationResult::ValidationResult(ValidationError error)
102 : error_(std::move(error))
105bool ValidationResult::IsSuccess()
const {
return !error_.has_value(); }
107const ValidationError& ValidationResult::GetError()
const& {
109 throw std::logic_error(
"Requested error for success validation result");
111 return error_.value();
114ValidationError&& ValidationResult::GetError() && {
116 throw std::logic_error(
"Requested error for success validation result");
118 return std::move(error_).value();
121ValidationResult ValidateMessage(
const google::protobuf::Message& message,
const ValidationParams& params) {
122 auto validator_factory = kValidatorFactory.Use();
123 google::protobuf::Arena arena;
124 auto validator = (*validator_factory)->NewValidator(&arena, params.fail_fast);
125 auto result = validator.Validate(message);
127 return ValidationError(
128 ValidationError::Type::kInternal,
130 "internal protovalidate error (check constraints syntax in the proto file) - {}",
131 result.status().ToString()
133 message.GetTypeName()
136 if (result->violations_size() != 0) {
137 return ValidationError(result.value(), message.GetTypeName());
139 return ValidationResult();