mirror of
https://gitee.com/zyjblog/oatpp.git
synced 2025-01-03 05:22:24 +08:00
Merge pull request #565 from JeremyGuinn/error-handler-enhancements
Add new virtual handleError method to handle the original error
This commit is contained in:
commit
0a3969b157
@ -71,27 +71,34 @@ const auto& OATPP_MACRO_FIRSTARG PARAM_LIST = __request;
|
||||
#define OATPP_MACRO_API_CONTROLLER_HEADER_1(TYPE, NAME) \
|
||||
const auto& __param_str_val_##NAME = __request->getHeader(#NAME); \
|
||||
if(!__param_str_val_##NAME){ \
|
||||
return ApiController::handleError(Status::CODE_400, "Missing HEADER parameter '" #NAME "'"); \
|
||||
auto httpError = oatpp::web::protocol::http::HttpError(Status::CODE_400, "Missing HEADER parameter '" #NAME "'"); \
|
||||
auto eptr = std::make_exception_ptr(httpError); \
|
||||
return ApiController::handleError(eptr); \
|
||||
} \
|
||||
bool __param_validation_check_##NAME; \
|
||||
const auto& NAME = ApiController::TypeInterpretation<TYPE>::fromString(#TYPE, __param_str_val_##NAME, __param_validation_check_##NAME); \
|
||||
if(!__param_validation_check_##NAME){ \
|
||||
return ApiController::handleError(Status::CODE_400, "Invalid HEADER parameter '" #NAME "'. Expected type is '" #TYPE "'"); \
|
||||
auto httpError = oatpp::web::protocol::http::HttpError(Status::CODE_400, "Invalid HEADER parameter '" #NAME "'. Expected type is '" #TYPE "'"); \
|
||||
auto eptr = std::make_exception_ptr(httpError); \
|
||||
return ApiController::handleError(eptr); \
|
||||
}
|
||||
|
||||
#define OATPP_MACRO_API_CONTROLLER_HEADER_2(TYPE, NAME, QUALIFIER) \
|
||||
const auto& __param_str_val_##NAME = __request->getHeader(QUALIFIER); \
|
||||
if(!__param_str_val_##NAME){ \
|
||||
return ApiController::handleError(Status::CODE_400, \
|
||||
oatpp::String("Missing HEADER parameter '") + QUALIFIER + "'"); \
|
||||
auto httpError = oatpp::web::protocol::http::HttpError(Status::CODE_400, oatpp::String("Missing HEADER parameter '") + QUALIFIER + "'"); \
|
||||
auto eptr = std::make_exception_ptr(httpError); \
|
||||
return ApiController::handleError(eptr); \
|
||||
} \
|
||||
bool __param_validation_check_##NAME; \
|
||||
const auto& NAME = ApiController::TypeInterpretation<TYPE>::fromString(#TYPE, __param_str_val_##NAME, __param_validation_check_##NAME); \
|
||||
if(!__param_validation_check_##NAME){ \
|
||||
return ApiController::handleError(Status::CODE_400, \
|
||||
auto httpError = oatpp::web::protocol::http::HttpError(Status::CODE_400, \
|
||||
oatpp::String("Invalid HEADER parameter '") + \
|
||||
QUALIFIER + \
|
||||
"'. Expected type is '" #TYPE "'"); \
|
||||
auto eptr = std::make_exception_ptr(httpError); \
|
||||
return ApiController::handleError(eptr); \
|
||||
}
|
||||
|
||||
#define OATPP_MACRO_API_CONTROLLER_HEADER(TYPE, PARAM_LIST) \
|
||||
@ -114,27 +121,35 @@ OATPP_MACRO_API_CONTROLLER_MACRO_SELECTOR(OATPP_MACRO_API_CONTROLLER_HEADER_INFO
|
||||
#define OATPP_MACRO_API_CONTROLLER_PATH_1(TYPE, NAME) \
|
||||
const auto& __param_str_val_##NAME = __request->getPathVariable(#NAME); \
|
||||
if(!__param_str_val_##NAME){ \
|
||||
return ApiController::handleError(Status::CODE_400, "Missing PATH parameter '" #NAME "'"); \
|
||||
auto httpError = oatpp::web::protocol::http::HttpError(Status::CODE_400, "Missing PATH parameter '" #NAME "'"); \
|
||||
auto eptr = std::make_exception_ptr(httpError); \
|
||||
return ApiController::handleError(eptr); \
|
||||
} \
|
||||
bool __param_validation_check_##NAME; \
|
||||
const auto& NAME = ApiController::TypeInterpretation<TYPE>::fromString(#TYPE, __param_str_val_##NAME, __param_validation_check_##NAME); \
|
||||
if(!__param_validation_check_##NAME){ \
|
||||
return ApiController::handleError(Status::CODE_400, "Invalid PATH parameter '" #NAME "'. Expected type is '" #TYPE "'"); \
|
||||
auto httpError = oatpp::web::protocol::http::HttpError(Status::CODE_400, "Invalid PATH parameter '" #NAME "'. Expected type is '" #TYPE "'"); \
|
||||
auto eptr = std::make_exception_ptr(httpError); \
|
||||
return ApiController::handleError(eptr); \
|
||||
}
|
||||
|
||||
#define OATPP_MACRO_API_CONTROLLER_PATH_2(TYPE, NAME, QUALIFIER) \
|
||||
const auto& __param_str_val_##NAME = __request->getPathVariable(QUALIFIER); \
|
||||
if(!__param_str_val_##NAME){ \
|
||||
return ApiController::handleError(Status::CODE_400, \
|
||||
auto httpError = oatpp::web::protocol::http::HttpError(Status::CODE_400, \
|
||||
oatpp::String("Missing PATH parameter '") + QUALIFIER + "'"); \
|
||||
auto eptr = std::make_exception_ptr(httpError); \
|
||||
return ApiController::handleError(eptr); \
|
||||
} \
|
||||
bool __param_validation_check_##NAME; \
|
||||
const auto NAME = ApiController::TypeInterpretation<TYPE>::fromString(#TYPE, __param_str_val_##NAME, __param_validation_check_##NAME); \
|
||||
if(!__param_validation_check_##NAME){ \
|
||||
return ApiController::handleError(Status::CODE_400, \
|
||||
auto httpError = oatpp::web::protocol::http::HttpError(Status::CODE_400, \
|
||||
oatpp::String("Invalid PATH parameter '") + \
|
||||
QUALIFIER + \
|
||||
"'. Expected type is '" #TYPE "'"); \
|
||||
auto eptr = std::make_exception_ptr(httpError); \
|
||||
return ApiController::handleError(eptr); \
|
||||
}
|
||||
|
||||
#define OATPP_MACRO_API_CONTROLLER_PATH(TYPE, PARAM_LIST) \
|
||||
@ -163,27 +178,35 @@ const auto& OATPP_MACRO_FIRSTARG PARAM_LIST = __request->getQueryParameters();
|
||||
#define OATPP_MACRO_API_CONTROLLER_QUERY_1(TYPE, NAME) \
|
||||
const auto& __param_str_val_##NAME = __request->getQueryParameter(#NAME); \
|
||||
if(!__param_str_val_##NAME){ \
|
||||
return ApiController::handleError(Status::CODE_400, "Missing QUERY parameter '" #NAME "'"); \
|
||||
auto httpError = oatpp::web::protocol::http::HttpError(Status::CODE_400, "Missing QUERY parameter '" #NAME "'"); \
|
||||
auto eptr = std::make_exception_ptr(httpError); \
|
||||
return ApiController::handleError(eptr); \
|
||||
} \
|
||||
bool __param_validation_check_##NAME; \
|
||||
const auto& NAME = ApiController::TypeInterpretation<TYPE>::fromString(#TYPE, __param_str_val_##NAME, __param_validation_check_##NAME); \
|
||||
if(!__param_validation_check_##NAME){ \
|
||||
return ApiController::handleError(Status::CODE_400, "Invalid QUERY parameter '" #NAME "'. Expected type is '" #TYPE "'"); \
|
||||
auto httpError = oatpp::web::protocol::http::HttpError(Status::CODE_400, "Invalid QUERY parameter '" #NAME "'. Expected type is '" #TYPE "'"); \
|
||||
auto eptr = std::make_exception_ptr(httpError); \
|
||||
return ApiController::handleError(eptr); \
|
||||
}
|
||||
|
||||
#define OATPP_MACRO_API_CONTROLLER_QUERY_2(TYPE, NAME, QUALIFIER) \
|
||||
const auto& __param_str_val_##NAME = __request->getQueryParameter(QUALIFIER); \
|
||||
if(!__param_str_val_##NAME){ \
|
||||
return ApiController::handleError(Status::CODE_400, \
|
||||
if(!__param_str_val_##NAME) \
|
||||
auto httpError = oatpp::web::protocol::http::HttpError(Status::CODE_400, \
|
||||
oatpp::String("Missing QUERY parameter '") + QUALIFIER + "'"); \
|
||||
auto eptr = std::make_exception_ptr(httpError); \
|
||||
return ApiController::handleError(eptr); \
|
||||
} \
|
||||
bool __param_validation_check_##NAME; \
|
||||
const auto& NAME = ApiController::TypeInterpretation<TYPE>::fromString(#TYPE, __param_str_val_##NAME, __param_validation_check_##NAME); \
|
||||
if(!__param_validation_check_##NAME){ \
|
||||
return ApiController::handleError(Status::CODE_400, \
|
||||
auto httpError = oatpp::web::protocol::http::HttpError(Status::CODE_400, \
|
||||
oatpp::String("Invalid QUERY parameter '") + \
|
||||
QUALIFIER + \
|
||||
"'. Expected type is '" #TYPE "'"); \
|
||||
auto eptr = std::make_exception_ptr(httpError); \
|
||||
return ApiController::handleError(eptr); \
|
||||
}
|
||||
|
||||
#define OATPP_MACRO_API_CONTROLLER_QUERY_3(TYPE, NAME, QUALIFIER, DEFAULT) \
|
||||
@ -193,10 +216,12 @@ if(__param_str_val_##NAME) { \
|
||||
bool __param_validation_check_##NAME; \
|
||||
NAME = ApiController::TypeInterpretation<TYPE>::fromString(#TYPE, __param_str_val_##NAME, __param_validation_check_##NAME); \
|
||||
if(!__param_validation_check_##NAME){ \
|
||||
return ApiController::handleError(Status::CODE_400, \
|
||||
auto httpError = oatpp::web::protocol::http::HttpError(Status::CODE_400, \
|
||||
oatpp::String("Invalid QUERY parameter '") + \
|
||||
QUALIFIER + \
|
||||
"'. Expected type is '" #TYPE "'"); \
|
||||
auto eptr = std::make_exception_ptr(httpError); \
|
||||
return ApiController::handleError(eptr); \
|
||||
} \
|
||||
}
|
||||
|
||||
@ -236,12 +261,16 @@ if(getDefaultObjectMapper()) { \
|
||||
|
||||
#define OATPP_MACRO_API_CONTROLLER_BODY_DTO(TYPE, PARAM_LIST) \
|
||||
if(!getDefaultObjectMapper()) { \
|
||||
return ApiController::handleError(Status::CODE_500, "ObjectMapper was NOT set. Can't deserialize the request body."); \
|
||||
auto httpError = oatpp::web::protocol::http::HttpError(Status::CODE_500, "ObjectMapper was NOT set. Can't deserialize the request body."); \
|
||||
auto eptr = std::make_exception_ptr(httpError); \
|
||||
return ApiController::handleError(eptr); \
|
||||
} \
|
||||
const auto& OATPP_MACRO_FIRSTARG PARAM_LIST = \
|
||||
__request->readBodyToDto<TYPE>(getDefaultObjectMapper().get()); \
|
||||
if(!OATPP_MACRO_FIRSTARG PARAM_LIST) { \
|
||||
return ApiController::handleError(Status::CODE_400, "Missing valid body parameter '" OATPP_MACRO_FIRSTARG_STR PARAM_LIST "'"); \
|
||||
auto httpError = oatpp::web::protocol::http::HttpError(Status::CODE_400, "Missing valid body parameter '" OATPP_MACRO_FIRSTARG_STR PARAM_LIST "'"); \
|
||||
auto eptr = std::make_exception_ptr(httpError); \
|
||||
return ApiController::handleError(eptr); \
|
||||
}
|
||||
|
||||
// __INFO
|
||||
|
@ -27,11 +27,7 @@
|
||||
namespace oatpp { namespace async {
|
||||
|
||||
Error::Error(const std::string& what)
|
||||
: m_what(what)
|
||||
: runtime_error(what)
|
||||
{}
|
||||
|
||||
const char* Error::what() const {
|
||||
return m_what.c_str();
|
||||
}
|
||||
|
||||
}}
|
@ -33,27 +33,14 @@ namespace oatpp { namespace async {
|
||||
/**
|
||||
* Class to hold and communicate errors between Coroutines
|
||||
*/
|
||||
class Error : public oatpp::base::Countable {
|
||||
private:
|
||||
std::string m_what;
|
||||
class Error : public std::runtime_error, public oatpp::base::Countable {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param what - error explanation.
|
||||
*/
|
||||
Error(const std::string& what);
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~Error() = default;
|
||||
|
||||
/**
|
||||
* Error explanation.
|
||||
* @return
|
||||
*/
|
||||
const char* what() const;
|
||||
explicit Error(const std::string& what);
|
||||
|
||||
/**
|
||||
* Check if error belongs to specified class.
|
||||
|
@ -70,6 +70,7 @@ const Status Status::CODE_414(414, "Request-URI Too Large");
|
||||
const Status Status::CODE_415(415, "Unsupported Media Type");
|
||||
const Status Status::CODE_416(416, "Requested Range Not Satisfiable");
|
||||
const Status Status::CODE_417(417, "Expectation Failed");
|
||||
const Status Status::CODE_418(418, "I'm a Teapot");
|
||||
const Status Status::CODE_422(422, "Unprocessable Entity");
|
||||
const Status Status::CODE_423(423, "Locked");
|
||||
const Status Status::CODE_424(424, "Failed Dependency");
|
||||
|
@ -246,6 +246,11 @@ public:
|
||||
*/
|
||||
static const Status CODE_417;// Expectation Failed
|
||||
|
||||
/**
|
||||
* I'm a Teapot (rfc7168 2.3.3)
|
||||
*/
|
||||
static const Status CODE_418;// I'm a teapot
|
||||
|
||||
/**
|
||||
* Unprocessable Entity.
|
||||
*/
|
||||
|
@ -107,21 +107,17 @@ HttpProcessor::processNextRequest(ProcessingResources& resources,
|
||||
<< "', URL: '" << request->getStartingLine().path.toString() << "'";
|
||||
|
||||
connectionState = ConnectionState::CLOSING;
|
||||
return resources.components->errorHandler->handleError(protocol::http::Status::CODE_404, ss.toString());
|
||||
oatpp::web::protocol::http::HttpError error(protocol::http::Status::CODE_404, ss.toString());
|
||||
auto ptr = std::make_exception_ptr(error);
|
||||
return resources.components->errorHandler->handleError(ptr);
|
||||
|
||||
}
|
||||
|
||||
request->setPathVariables(route.getMatchMap());
|
||||
return route.getEndpoint()->handle(request);
|
||||
|
||||
} catch (oatpp::web::protocol::http::HttpError& error) {
|
||||
response = resources.components->errorHandler->handleError(error.getInfo().status, error.getMessage(), error.getHeaders());
|
||||
connectionState = ConnectionState::CLOSING;
|
||||
} catch (std::exception& error) {
|
||||
response = resources.components->errorHandler->handleError(protocol::http::Status::CODE_500, error.what());
|
||||
connectionState = ConnectionState::CLOSING;
|
||||
} catch (...) {
|
||||
response = resources.components->errorHandler->handleError(protocol::http::Status::CODE_500, "Unhandled Error");
|
||||
response = resources.components->errorHandler->handleError(std::current_exception());
|
||||
connectionState = ConnectionState::CLOSING;
|
||||
}
|
||||
|
||||
@ -143,7 +139,9 @@ HttpProcessor::ConnectionState HttpProcessor::processNextRequest(ProcessingResou
|
||||
std::shared_ptr<protocol::http::outgoing::Response> response;
|
||||
|
||||
if(error.status.code != 0) {
|
||||
response = resources.components->errorHandler->handleError(error.status, "Invalid Request Headers");
|
||||
oatpp::web::protocol::http::HttpError httpError(error.status, "Invalid Request Headers");
|
||||
auto eptr = std::make_exception_ptr(httpError);
|
||||
response = resources.components->errorHandler->handleError(eptr);
|
||||
connectionState = ConnectionState::CLOSING;
|
||||
} else {
|
||||
|
||||
@ -160,19 +158,15 @@ HttpProcessor::ConnectionState HttpProcessor::processNextRequest(ProcessingResou
|
||||
for (auto& interceptor : resources.components->responseInterceptors) {
|
||||
response = interceptor->intercept(request, response);
|
||||
if (!response) {
|
||||
response = resources.components->errorHandler->handleError(
|
||||
protocol::http::Status::CODE_500,
|
||||
"Response Interceptor returned an Invalid Response - 'null'"
|
||||
);
|
||||
oatpp::web::protocol::http::HttpError httpError(protocol::http::Status::CODE_500, "Response Interceptor returned an Invalid Response - 'null'");
|
||||
auto eptr = std::make_exception_ptr(httpError);
|
||||
response = resources.components->errorHandler->handleError(eptr);
|
||||
connectionState = ConnectionState::CLOSING;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (...) {
|
||||
response = resources.components->errorHandler->handleError(
|
||||
protocol::http::Status::CODE_500,
|
||||
"Unhandled Error in Response Interceptor"
|
||||
);
|
||||
response = resources.components->errorHandler->handleError(std::current_exception());
|
||||
connectionState = ConnectionState::CLOSING;
|
||||
}
|
||||
|
||||
@ -327,7 +321,9 @@ oatpp::async::Action HttpProcessor::Coroutine::onHeadersParsed(const RequestHead
|
||||
data::stream::BufferOutputStream ss;
|
||||
ss << "No mapping for HTTP-method: '" << headersReadResult.startingLine.method.toString()
|
||||
<< "', URL: '" << headersReadResult.startingLine.path.toString() << "'";
|
||||
m_currentResponse = m_components->errorHandler->handleError(protocol::http::Status::CODE_404, ss.toString());
|
||||
oatpp::web::protocol::http::HttpError error(protocol::http::Status::CODE_404, ss.toString());
|
||||
auto eptr = std::make_exception_ptr(error);
|
||||
m_currentResponse = m_components->errorHandler->handleError(eptr);
|
||||
m_connectionState = ConnectionState::CLOSING;
|
||||
return yieldTo(&HttpProcessor::Coroutine::onResponseFormed);
|
||||
}
|
||||
@ -352,10 +348,9 @@ HttpProcessor::Coroutine::Action HttpProcessor::Coroutine::onResponseFormed() {
|
||||
for(auto& interceptor : m_components->responseInterceptors) {
|
||||
m_currentResponse = interceptor->intercept(m_currentRequest, m_currentResponse);
|
||||
if(!m_currentResponse) {
|
||||
m_currentResponse = m_components->errorHandler->handleError(
|
||||
protocol::http::Status::CODE_500,
|
||||
"Response Interceptor returned an Invalid Response - 'null'"
|
||||
);
|
||||
oatpp::web::protocol::http::HttpError error(protocol::http::Status::CODE_500, "Response Interceptor returned an Invalid Response - 'null'");
|
||||
auto eptr = std::make_exception_ptr(error);
|
||||
m_currentResponse = m_components->errorHandler->handleError(eptr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -430,7 +425,9 @@ HttpProcessor::Coroutine::Action HttpProcessor::Coroutine::handleError(Error* er
|
||||
return error;
|
||||
}
|
||||
|
||||
m_currentResponse = m_components->errorHandler->handleError(protocol::http::Status::CODE_500, error->what());
|
||||
oatpp::web::protocol::http::HttpError httpError(protocol::http::Status::CODE_500, error->what());
|
||||
auto eptr = std::make_exception_ptr(httpError);
|
||||
m_currentResponse = m_components->errorHandler->handleError(eptr);
|
||||
return yieldTo(&HttpProcessor::Coroutine::onResponseFormed);
|
||||
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "ApiController.hpp"
|
||||
|
||||
#include "oatpp/web/server/handler/ErrorHandler.hpp"
|
||||
|
||||
namespace oatpp { namespace web { namespace server { namespace api {
|
||||
@ -49,13 +50,17 @@ std::shared_ptr<ApiController::RequestHandler> ApiController::getEndpointHandler
|
||||
|
||||
void ApiController::setErrorHandler(const std::shared_ptr<handler::ErrorHandler>& errorHandler){
|
||||
m_errorHandler = errorHandler;
|
||||
if(!m_errorHandler) {
|
||||
m_errorHandler = handler::DefaultErrorHandler::createShared();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<ApiController::OutgoingResponse> ApiController::handleError(const Status& status, const oatpp::String& message) const {
|
||||
std::shared_ptr<ApiController::OutgoingResponse> ApiController::handleError(const std::exception_ptr& exceptionPtr) const {
|
||||
if(m_errorHandler) {
|
||||
return m_errorHandler->handleError(status, message);
|
||||
return m_errorHandler->handleError(exceptionPtr);
|
||||
}
|
||||
throw oatpp::web::protocol::http::HttpError(status, message);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ApiController::setDefaultAuthorizationHandler(const std::shared_ptr<handler::AuthorizationHandler>& authorizationHandler){
|
||||
|
@ -236,7 +236,8 @@ protected:
|
||||
}
|
||||
|
||||
async::Action handleError(async::Error* error) override {
|
||||
auto response = m_handler->m_controller->m_errorHandler->handleError(protocol::http::Status::CODE_500, error->what());
|
||||
auto eptr = std::make_exception_ptr(*error);
|
||||
auto response = m_handler->m_controller->m_errorHandler->handleError(eptr);
|
||||
return this->_return(response);
|
||||
}
|
||||
|
||||
@ -262,27 +263,22 @@ protected:
|
||||
|
||||
if(m_method == nullptr) {
|
||||
if(m_methodAsync == nullptr) {
|
||||
return m_controller->handleError(Status::CODE_500, "[ApiController]: Error. Handler method is nullptr.");
|
||||
throw protocol::http::HttpError(Status::CODE_500, "[ApiController]: Error. Handler method is nullptr.");;
|
||||
}
|
||||
return m_controller->handleError(Status::CODE_500, "[ApiController]: Error. Non-async call to async endpoint.");
|
||||
throw protocol::http::HttpError(Status::CODE_500, "[ApiController]: Error. Non-async call to async endpoint.");;
|
||||
}
|
||||
|
||||
if(m_controller->m_errorHandler) {
|
||||
|
||||
try {
|
||||
return (m_controller->*m_method)(request);
|
||||
} catch (oatpp::web::protocol::http::HttpError& error) {
|
||||
return m_controller->m_errorHandler->handleError(error.getInfo().status, error.getMessage(), error.getHeaders());
|
||||
} catch (std::exception& error) {
|
||||
return m_controller->m_errorHandler->handleError(protocol::http::Status::CODE_500, error.what());
|
||||
} catch (...) {
|
||||
return m_controller->m_errorHandler->handleError(protocol::http::Status::CODE_500, "Unknown error");
|
||||
auto response = m_controller->handleError(std::current_exception());
|
||||
if(response != nullptr) {
|
||||
return response;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
return (m_controller->*m_method)(request);
|
||||
|
||||
}
|
||||
|
||||
oatpp::async::CoroutineStarterForResult<const std::shared_ptr<OutgoingResponse>&>
|
||||
@ -383,18 +379,16 @@ public:
|
||||
const Endpoints& getEndpoints();
|
||||
|
||||
/**
|
||||
* [under discussion]
|
||||
* Set error handler to handle calls to handleError
|
||||
* Set error handler to handle errors that occur during the endpoint's execution
|
||||
*/
|
||||
void setErrorHandler(const std::shared_ptr<handler::ErrorHandler>& errorHandler);
|
||||
|
||||
/**
|
||||
* [under discussion]
|
||||
* Do not use it directly. This method is under discussion.
|
||||
* Currently returns Response created by registered ErrorHandler or returns Response created by DefaultErrorHandler::handleDefaultError
|
||||
* Notice: Does not throw the Error anymore, error-response has to be returned by the caller!
|
||||
* Handle the exception using the registered ErrorHandler or if no handler has been set, uses the DefaultErrorHandler::handleError
|
||||
* @note Does not rethrow an exception anymore, OutgoingResponse has to be returned by the caller!
|
||||
* @note If this handler fails to handle the exception, it will be handled by the connection handlers ErrorHandler.
|
||||
*/
|
||||
std::shared_ptr<OutgoingResponse> handleError(const Status& status, const oatpp::String& message) const;
|
||||
std::shared_ptr<OutgoingResponse> handleError(const std::exception_ptr& exceptionPtr) const;
|
||||
|
||||
/**
|
||||
* [under discussion]
|
||||
|
@ -28,9 +28,36 @@
|
||||
|
||||
namespace oatpp { namespace web { namespace server { namespace handler {
|
||||
|
||||
std::shared_ptr<protocol::http::outgoing::Response> ErrorHandler::handleError(const std::exception_ptr& exceptionPtr) {
|
||||
|
||||
std::shared_ptr<protocol::http::outgoing::Response> response;
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
/* Default impl for backwards compatibility until the deprecated methods are removed */
|
||||
try {
|
||||
if(exceptionPtr) {
|
||||
std::rethrow_exception(exceptionPtr);
|
||||
}
|
||||
} catch (protocol::http::HttpError& httpError) {
|
||||
response = handleError(httpError.getInfo().status, httpError.getMessage(), httpError.getHeaders());
|
||||
} catch (std::exception& error) {
|
||||
response = handleError(protocol::http::Status::CODE_500, error.what());
|
||||
} catch (...) {
|
||||
response = handleError(protocol::http::Status::CODE_500, "An unknown error has occurred");
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
return response;
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<protocol::http::outgoing::Response> ErrorHandler::handleError(const protocol::http::Status& status, const oatpp::String& message) {
|
||||
Headers headers;
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
return handleError(status, message, headers);
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
|
||||
std::shared_ptr<protocol::http::outgoing::Response>
|
||||
@ -55,4 +82,9 @@ DefaultErrorHandler::handleError(const oatpp::web::protocol::http::Status &statu
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<protocol::http::outgoing::Response>
|
||||
DefaultErrorHandler::handleError(const std::exception_ptr& error) {
|
||||
return ErrorHandler::handleError(error);
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
@ -42,10 +42,17 @@ public:
|
||||
typedef web::protocol::http::Headers Headers;
|
||||
public:
|
||||
/**
|
||||
* Virtual destructor since the class is ment to be derived from.
|
||||
* Virtual destructor since the class is meant to be derived from.
|
||||
* */
|
||||
virtual ~ErrorHandler() = default;
|
||||
|
||||
/**
|
||||
* Implement this method!
|
||||
* @param error - &std::exception;.
|
||||
* @return - std::shared_ptr to &id:oatpp::web::protocol::http::outgoing::Response;.
|
||||
*/
|
||||
virtual std::shared_ptr<protocol::http::outgoing::Response> handleError(const std::exception_ptr& exceptionPtr) = 0;
|
||||
|
||||
/**
|
||||
* Implement this method!
|
||||
* @param status - &id:oatpp::web::protocol::http::Status;.
|
||||
@ -53,6 +60,7 @@ public:
|
||||
* @param Headers - &id:oatpp::web::protocol::http::Headers;
|
||||
* @return - std::shared_ptr to &id:oatpp::web::protocol::http::outgoing::Response;.
|
||||
*/
|
||||
[[deprecated]]
|
||||
virtual
|
||||
std::shared_ptr<protocol::http::outgoing::Response>
|
||||
handleError(const protocol::http::Status& status, const oatpp::String& message, const Headers& headers) = 0;
|
||||
@ -63,6 +71,7 @@ public:
|
||||
* @param message - &id:oatpp::String;.
|
||||
* @return - std::shared_ptr to &id:oatpp::web::protocol::http::outgoing::Response;.
|
||||
*/
|
||||
[[deprecated]]
|
||||
std::shared_ptr<protocol::http::outgoing::Response> handleError(const protocol::http::Status& status, const oatpp::String& message);
|
||||
|
||||
};
|
||||
@ -75,8 +84,7 @@ public:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
DefaultErrorHandler()
|
||||
{}
|
||||
DefaultErrorHandler() = default;
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -87,6 +95,8 @@ public:
|
||||
return std::make_shared<DefaultErrorHandler>();
|
||||
}
|
||||
|
||||
std::shared_ptr<protocol::http::outgoing::Response> handleError(const std::exception_ptr& error) override;
|
||||
|
||||
/**
|
||||
* Implementation of &l:ErrorHandler::handleError ();
|
||||
* @param status - &id:oatpp::web::protocol::http::Status;.
|
||||
|
@ -109,6 +109,7 @@ add_executable(oatppAllTests
|
||||
oatpp/web/app/DTOs.hpp
|
||||
oatpp/web/app/ControllerWithInterceptors.hpp
|
||||
oatpp/web/app/ControllerWithInterceptorsAsync.hpp
|
||||
oatpp/web/app/ControllerWithErrorHandler.hpp
|
||||
)
|
||||
|
||||
target_link_libraries(oatppAllTests PRIVATE oatpp PRIVATE oatpp-test)
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "oatpp/web/app/Client.hpp"
|
||||
|
||||
#include "oatpp/web/app/ControllerWithInterceptors.hpp"
|
||||
#include "oatpp/web/app/ControllerWithErrorHandler.hpp"
|
||||
#include "oatpp/web/app/Controller.hpp"
|
||||
#include "oatpp/web/app/BasicAuthorizationController.hpp"
|
||||
#include "oatpp/web/app/BearerAuthorizationController.hpp"
|
||||
@ -143,6 +144,7 @@ void FullTest::onRun() {
|
||||
|
||||
runner.addController(app::Controller::createShared());
|
||||
runner.addController(app::ControllerWithInterceptors::createShared());
|
||||
runner.addController(app::ControllerWithErrorHandler::createShared());
|
||||
runner.addController(app::DefaultBasicAuthorizationController::createShared());
|
||||
runner.addController(app::BasicAuthorizationController::createShared());
|
||||
runner.addController(app::BearerAuthorizationController::createShared());
|
||||
@ -487,6 +489,13 @@ void FullTest::onRun() {
|
||||
OATPP_ASSERT(value == "Hello World!!!");
|
||||
}
|
||||
|
||||
{ // test controller's error handler catches
|
||||
auto response = client->getCaughtError(connection);
|
||||
OATPP_ASSERT(response->getStatusCode() == 418);
|
||||
auto value = response->readBodyToString();
|
||||
OATPP_ASSERT(value == "Controller With Errors!");
|
||||
}
|
||||
|
||||
{ // test header replacement
|
||||
auto response = client->getInterceptors(connection);
|
||||
OATPP_ASSERT(response->getStatusCode() == 200);
|
||||
|
@ -76,6 +76,8 @@ public:
|
||||
|
||||
API_CALL("GET", "test/interceptors", getInterceptors)
|
||||
|
||||
API_CALL("GET", "test/errorhandling", getCaughtError)
|
||||
|
||||
API_CALL_HEADERS(getDefaultHeaders1) {
|
||||
headers.put("X-DEFAULT", "hello_1");
|
||||
}
|
||||
|
105
test/oatpp/web/app/ControllerWithErrorHandler.hpp
Normal file
105
test/oatpp/web/app/ControllerWithErrorHandler.hpp
Normal file
@ -0,0 +1,105 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_test_web_app_ControllerWithErrorHandler_hpp
|
||||
#define oatpp_test_web_app_ControllerWithErrorHandler_hpp
|
||||
|
||||
#include "oatpp/web/server/api/ApiController.hpp"
|
||||
#include "oatpp/parser/json/mapping/ObjectMapper.hpp"
|
||||
#include "oatpp/core/utils/ConversionUtils.hpp"
|
||||
#include "oatpp/core/macro/codegen.hpp"
|
||||
#include "oatpp/core/macro/component.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace oatpp { namespace test { namespace web { namespace app {
|
||||
|
||||
namespace http = oatpp::web::protocol::http;
|
||||
|
||||
/**
|
||||
* Custom Error Handler.
|
||||
*/
|
||||
class CustomErrorHandler : public oatpp::base::Countable, public oatpp::web::server::handler::ErrorHandler {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
CustomErrorHandler() = default;
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create shared DefaultErrorHandler.
|
||||
* @return - `std::shared_ptr` to DefaultErrorHandler.
|
||||
*/
|
||||
static std::shared_ptr<CustomErrorHandler> createShared() {
|
||||
return std::make_shared<CustomErrorHandler>();
|
||||
}
|
||||
|
||||
std::shared_ptr<http::outgoing::Response> handleError(const std::exception_ptr& error) override {
|
||||
try {
|
||||
std::rethrow_exception(error);
|
||||
} catch(const std::runtime_error& e) {
|
||||
return oatpp::web::protocol::http::outgoing::ResponseFactory::createResponse(http::Status::CODE_418, e.what());
|
||||
} catch(...) {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<oatpp::web::protocol::http::outgoing::Response> handleError(const http::Status& status, const oatpp::String& message, const Headers& headers) override {
|
||||
throw std::logic_error("Function not implemented");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class ControllerWithErrorHandler : public oatpp::web::server::api::ApiController {
|
||||
private:
|
||||
static constexpr const char* TAG = "test::web::app::ControllerWithErrorHandler";
|
||||
public:
|
||||
explicit ControllerWithErrorHandler(const std::shared_ptr<ObjectMapper>& objectMapper)
|
||||
: oatpp::web::server::api::ApiController(objectMapper)
|
||||
{
|
||||
setErrorHandler(CustomErrorHandler::createShared());
|
||||
}
|
||||
public:
|
||||
|
||||
static std::shared_ptr<ControllerWithErrorHandler> createShared(const std::shared_ptr<ObjectMapper>& objectMapper = OATPP_GET_COMPONENT(std::shared_ptr<ObjectMapper>)){
|
||||
return std::make_shared<ControllerWithErrorHandler>(objectMapper);
|
||||
}
|
||||
|
||||
#include OATPP_CODEGEN_BEGIN(ApiController)
|
||||
|
||||
ENDPOINT("GET", "test/errorhandling", errorCaught,
|
||||
REQUEST(std::shared_ptr<IncomingRequest>, request))
|
||||
{
|
||||
throw std::runtime_error("Controller With Errors!");
|
||||
}
|
||||
|
||||
|
||||
#include OATPP_CODEGEN_END(ApiController)
|
||||
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
#endif /* oatpp_test_web_app_ControllerWithErrorHandler_hpp */
|
Loading…
Reference in New Issue
Block a user