8#include <unordered_map>
10#include <userver/formats/json.hpp>
11#include <userver/utils/assert.hpp>
12#include <userver/utils/str_icase.hpp>
13#include <userver/utils/void_t.hpp>
15USERVER_NAMESPACE_BEGIN
72 std::size_t operator()(
HandlerErrorCode c)
const {
return static_cast<std::size_t>(c); }
100concept HasExternalBodyFormatted =
requires {
102 std::bool_constant<T::kIsExternalBodyFormatted>{}
103 } -> std::same_as<std::true_type>;
107concept HasInternalMessage =
requires(
const T& t) { t.GetInternalMessage(); };
110concept HasExternalBody =
requires(
const T& t) { t.GetExternalBody(); };
113concept HasServiceCode =
requires(
const T& t) { t.GetServiceCode(); };
116concept IsMessageBuilder = HasExternalBody<T>;
119struct MessageExtractor {
122 "Please use your message builder to build external body for "
123 "your error. See server::handlers::CustomHandlerException "
129 constexpr bool IsExternalBodyFormatted()
const {
return impl::HasExternalBodyFormatted<T>; }
131 std::string GetServiceCode()
const {
132 if constexpr (HasServiceCode<T>) {
133 return builder.GetServiceCode();
135 return std::string{};
139 std::string GetExternalBody()
const {
return builder.GetExternalBody(); }
141 std::string GetInternalMessage()
const {
142 if constexpr (HasInternalMessage<T>) {
143 return builder.GetInternalMessage();
145 return std::string{};
150struct CustomHandlerExceptionData
final {
151 CustomHandlerExceptionData() =
default;
152 CustomHandlerExceptionData(
const CustomHandlerExceptionData&) =
default;
153 CustomHandlerExceptionData(CustomHandlerExceptionData&&)
noexcept =
default;
155 template <
typename... Args>
156 explicit CustomHandlerExceptionData(Args&&... args) {
157 (Apply(std::forward<Args>(args)), ...);
160 bool is_external_body_formatted{
false};
162 std::string service_code;
163 std::string internal_message;
164 std::string external_body;
166 formats::json::
Value details;
169 void Apply(
HandlerErrorCode l_handler_code) { handler_code = l_handler_code; }
171 void Apply(
ServiceErrorCode l_service_code) { service_code = std::move(l_service_code.body); }
173 void Apply(
InternalMessage l_internal_message) { internal_message = std::move(l_internal_message.body); }
175 void Apply(
ExternalBody l_external_body) { external_body = std::move(l_external_body.body); }
177 void Apply(
ExtraHeaders l_headers) { headers = std::move(l_headers.headers); }
179 void Apply(formats::json::
Value l_details) { details = std::move(l_details); }
181 template <
typename MessageBuilder>
182 void Apply(MessageBuilder&& builder) {
183 const impl::MessageExtractor<MessageBuilder> extractor{builder};
184 is_external_body_formatted = extractor.IsExternalBodyFormatted();
185 service_code = extractor.GetServiceCode();
186 external_body = extractor.GetExternalBody();
187 internal_message = extractor.GetInternalMessage();
237 template <
typename... Args>
249 ServiceErrorCode service_code,
250 ExternalBody external_body,
251 InternalMessage internal_message,
252 HandlerErrorCode handler_code,
253 ExtraHeaders headers = {},
257 std::move(service_code),
258 std::move(external_body),
259 std::move(internal_message),
267 template <
typename MessageBuilder>
268 requires impl::IsMessageBuilder<MessageBuilder>
270 :
CustomHandlerException(impl::CustomHandlerExceptionData{std::forward<MessageBuilder>(builder), handler_code})
274 explicit CustomHandlerException(impl::CustomHandlerExceptionData&& data)
276 data.internal_message.empty() ? std::string{GetCodeDescription(data.handler_code)} : data.internal_message
278 data_(std::move(data))
282 "The details JSON value must be either null or an object"
287 HandlerErrorCode GetCode()
const {
return data_.handler_code; }
289 const std::string& GetServiceCode()
const {
return data_.service_code; }
291 bool IsExternalErrorBodyFormatted()
const {
return data_.is_external_body_formatted; }
293 const std::string& GetExternalErrorBody()
const {
return data_.external_body; }
295 const formats::json::
Value& GetDetails()
const {
return data_.details; }
297 const Headers& GetExtraHeaders()
const {
return data_.headers; }
300 impl::CustomHandlerExceptionData data_;
309 constexpr static HandlerErrorCode kDefaultCode = Code;
316 template <
typename... Args>
326 using BaseType::BaseType;
333 using BaseType::BaseType;
340 using BaseType::BaseType;
347 using BaseType::BaseType;
355 using BaseType::BaseType;
362 using BaseType::BaseType;