8#include <unordered_map>
10#include <userver/formats/json.hpp>
11#include <userver/utils/assert.hpp>
12#include <userver/utils/str_icase.hpp>
14USERVER_NAMESPACE_BEGIN
71 std::size_t operator()(
HandlerErrorCode c)
const {
return static_cast<std::size_t>(c); }
99concept HasExternalBodyFormatted =
requires {
101 std::bool_constant<T::kIsExternalBodyFormatted>{}
102 } -> std::same_as<std::true_type>;
106concept HasInternalMessage =
requires(
const T& t) { t.GetInternalMessage(); };
109concept HasExternalBody =
requires(
const T& t) { t.GetExternalBody(); };
112concept HasServiceCode =
requires(
const T& t) { t.GetServiceCode(); };
115concept IsMessageBuilder = HasExternalBody<T>;
118struct MessageExtractor {
121 "Please use your message builder to build external body for "
122 "your error. See server::handlers::CustomHandlerException "
128 constexpr bool IsExternalBodyFormatted()
const {
return impl::HasExternalBodyFormatted<T>; }
130 std::string GetServiceCode()
const {
131 if constexpr (HasServiceCode<T>) {
132 return builder.GetServiceCode();
134 return std::string{};
138 std::string GetExternalBody()
const {
return builder.GetExternalBody(); }
140 std::string GetInternalMessage()
const {
141 if constexpr (HasInternalMessage<T>) {
142 return builder.GetInternalMessage();
144 return std::string{};
149struct CustomHandlerExceptionData
final {
150 CustomHandlerExceptionData() =
default;
151 CustomHandlerExceptionData(
const CustomHandlerExceptionData&) =
default;
152 CustomHandlerExceptionData(CustomHandlerExceptionData&&)
noexcept =
default;
154 template <
typename... Args>
155 explicit CustomHandlerExceptionData(Args&&... args) {
156 (Apply(std::forward<Args>(args)), ...);
159 bool is_external_body_formatted{
false};
161 std::string service_code;
162 std::string internal_message;
163 std::string external_body;
165 formats::json::
Value details;
168 void Apply(
HandlerErrorCode l_handler_code) { handler_code = l_handler_code; }
170 void Apply(
ServiceErrorCode l_service_code) { service_code = std::move(l_service_code.body); }
172 void Apply(
InternalMessage l_internal_message) { internal_message = std::move(l_internal_message.body); }
174 void Apply(
ExternalBody l_external_body) { external_body = std::move(l_external_body.body); }
176 void Apply(
ExtraHeaders l_headers) { headers = std::move(l_headers.headers); }
178 void Apply(formats::json::
Value l_details) { details = std::move(l_details); }
180 template <
typename MessageBuilder>
181 void Apply(MessageBuilder&& builder) {
182 const impl::MessageExtractor<MessageBuilder> extractor{builder};
183 is_external_body_formatted = extractor.IsExternalBodyFormatted();
184 service_code = extractor.GetServiceCode();
185 external_body = extractor.GetExternalBody();
186 internal_message = extractor.GetInternalMessage();
236 template <
typename... Args>
248 ServiceErrorCode service_code,
249 ExternalBody external_body,
250 InternalMessage internal_message,
251 HandlerErrorCode handler_code,
252 ExtraHeaders headers = {},
256 std::move(service_code),
257 std::move(external_body),
258 std::move(internal_message),
266 template <
typename MessageBuilder>
267 requires impl::IsMessageBuilder<MessageBuilder>
269 :
CustomHandlerException(impl::CustomHandlerExceptionData{std::forward<MessageBuilder>(builder), handler_code})
273 explicit CustomHandlerException(impl::CustomHandlerExceptionData&& data)
275 data.internal_message.empty() ? std::string{GetCodeDescription(data.handler_code)} : data.internal_message
277 data_(std::move(data))
281 "The details JSON value must be either null or an object"
286 HandlerErrorCode GetCode()
const {
return data_.handler_code; }
288 const std::string& GetServiceCode()
const {
return data_.service_code; }
290 bool IsExternalErrorBodyFormatted()
const {
return data_.is_external_body_formatted; }
292 const std::string& GetExternalErrorBody()
const {
return data_.external_body; }
294 const formats::json::
Value& GetDetails()
const {
return data_.details; }
296 const Headers& GetExtraHeaders()
const {
return data_.headers; }
299 impl::CustomHandlerExceptionData data_;
308 constexpr static HandlerErrorCode kDefaultCode = Code;
315 template <
typename... Args>
325 using BaseType::BaseType;
332 using BaseType::BaseType;
339 using BaseType::BaseType;
346 using BaseType::BaseType;
354 using BaseType::BaseType;
361 using BaseType::BaseType;