1#include <userver/grpc-protovalidate/validate.hpp>
9#include <google/protobuf/arena.h>
10#include <google/protobuf/message.h>
11#include <google/protobuf/repeated_ptr_field.h>
12#include <google/rpc/status.pb.h>
13#include <grpcpp/support/status.h>
15#include <grpc-protovalidate/impl/utils.hpp>
16#include <userver/compiler/thread_local.hpp>
17#include <userver/grpc-protovalidate/buf_validate.hpp>
18#include <userver/ugrpc/status_utils.hpp>
19#include <userver/utils/assert.hpp>
21USERVER_NAMESPACE_BEGIN
23namespace grpc_protovalidate {
27compiler::ThreadLocal kValidatorFactory = [] {
return impl::CreateProtoValidatorFactory(); };
31ValidationError::ValidationError(Type type, std::string description, std::string message_name)
33 description_(fmt::format(
"Message '{}' validation error: {}", message_name, std::move(description))),
34 result_(std::nullopt),
35 message_name_(std::move(message_name))
38ValidationError::ValidationError(buf::validate::ValidationResult result, std::string message_name)
40 description_(fmt::format(
41 "Message '{}' validation error: {} constraint(s) violated",
43 result.violations_size()
45 result_(std::move(result)),
46 message_name_(std::move(message_name))
49ValidationError::Type ValidationError::GetType()
const {
return type_; }
51const std::string& ValidationError::GetMessageName()
const {
return message_name_; }
53const std::string& ValidationError::GetDescription()
const {
return description_; }
55const std::vector<buf::validate::RuleViolation>& ValidationError::GetViolations()
const {
56 if (GetType() == Type::kInternal || !result_.has_value()) {
57 static constexpr std::vector<buf::validate::RuleViolation> kNoViolations;
60 return result_->violations();
63grpc::Status ValidationError::GetGrpcStatus(
bool include_violations)
const {
64 google::rpc::Status gstatus;
65 gstatus.set_message(GetDescription());
68 gstatus.set_code(grpc::StatusCode::INTERNAL);
71 gstatus.set_code(grpc::StatusCode::INVALID_ARGUMENT);
75 if (include_violations) {
76 gstatus.add_details()->PackFrom(MakeViolationsProto());
78 return ugrpc::ToGrpcStatus(gstatus);
81buf::validate::Violations ValidationError::MakeViolationsProto()
const {
82 buf::validate::Violations proto;
84 GetViolations().begin(),
85 GetViolations().end(),
86 RepeatedPtrFieldBackInserter(proto.mutable_violations()),
87 [](
const buf::validate::RuleViolation& violation) {
return violation.proto(); }
92logging::LogHelper& operator<<(logging::LogHelper& lh,
const ValidationError& error) {
93 lh << error.GetDescription();
94 for (
const buf::validate::RuleViolation& violation : error.GetViolations()) {
95 lh << violation.proto();
100ValidationResult::ValidationResult(ValidationError error)
101 : error_(std::move(error))
104bool ValidationResult::IsSuccess()
const {
return !error_.has_value(); }
106const ValidationError& ValidationResult::GetError()
const& {
108 throw std::logic_error(
"Requested error for success validation result");
110 return error_.value();
113ValidationError&& ValidationResult::GetError() && {
115 throw std::logic_error(
"Requested error for success validation result");
117 return std::move(error_).value();
120ValidationResult ValidateMessage(
const google::protobuf::Message& message,
const ValidationParams& params) {
121 auto validator_factory = kValidatorFactory.Use();
122 google::protobuf::Arena arena;
123 auto validator = (*validator_factory)->NewValidator(&arena, params.fail_fast);
124 auto result = validator.Validate(message);
126 return ValidationError(
127 ValidationError::Type::kInternal,
129 "internal protovalidate error (check constraints syntax in the proto file) - {}",
130 result.status().ToString()
132 message.GetTypeName()
135 if (result->violations_size() != 0) {
136 return ValidationError(result.value(), message.GetTypeName());
138 return ValidationResult();