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)) {}
37ValidationError::ValidationError(buf::validate::ValidationResult result, std::string message_name)
39 description_(fmt::format(
40 "Message '{}' validation error: {} constraint(s) violated",
42 result.violations_size()
44 result_(std::move(result)),
45 message_name_(std::move(message_name)) {}
47ValidationError::Type ValidationError::GetType()
const {
return type_; }
49const std::string& ValidationError::GetMessageName()
const {
return message_name_; }
51const std::string& ValidationError::GetDescription()
const {
return description_; }
53const std::vector<buf::validate::RuleViolation>& ValidationError::GetViolations()
const {
54 if (GetType() == Type::kInternal || !result_.has_value()) {
55 static constexpr std::vector<buf::validate::RuleViolation> kNoViolations;
58 return result_->violations();
61grpc::Status ValidationError::GetGrpcStatus(
bool include_violations)
const {
62 google::rpc::Status gstatus;
63 gstatus.set_message(GetDescription());
66 gstatus.set_code(grpc::StatusCode::INTERNAL);
69 gstatus.set_code(grpc::StatusCode::INVALID_ARGUMENT);
73 if (include_violations) {
74 gstatus.add_details()->PackFrom(MakeViolationsProto());
76 return ugrpc::ToGrpcStatus(gstatus);
79buf::validate::Violations ValidationError::MakeViolationsProto()
const {
80 buf::validate::Violations proto;
82 GetViolations().begin(),
83 GetViolations().end(),
84 RepeatedPtrFieldBackInserter(proto.mutable_violations()),
85 [](
const buf::validate::RuleViolation& violation) {
return violation.proto(); }
90logging::LogHelper& operator<<(logging::LogHelper& lh,
const ValidationError& error) {
91 lh << error.GetDescription();
92 for (
const buf::validate::RuleViolation& violation : error.GetViolations()) {
93 lh << violation.proto();
98ValidationResult::ValidationResult(ValidationError error) : error_(std::move(error)) {}
100bool ValidationResult::IsSuccess()
const {
return !error_.has_value(); }
102const ValidationError& ValidationResult::GetError()
const& {
104 throw std::logic_error(
"Requested error for success validation result");
106 return error_.value();
109ValidationError&& ValidationResult::GetError() && {
111 throw std::logic_error(
"Requested error for success validation result");
113 return std::move(error_).value();
116ValidationResult ValidateMessage(
const google::protobuf::Message& message,
const ValidationParams& params) {
117 auto validator_factory = kValidatorFactory.Use();
118 google::protobuf::Arena arena;
119 auto validator = (*validator_factory)->NewValidator(&arena, params.fail_fast);
120 auto result = validator.Validate(message);
122 return ValidationError(
123 ValidationError::Type::kInternal,
125 "internal protovalidate error (check constraints syntax in the proto file) - {}",
126 result.status().ToString()
128 message.GetTypeName()
131 if (result->violations_size() != 0) {
132 return ValidationError(result.value(), message.GetTypeName());
134 return ValidationResult();