ApiController.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. /***************************************************************************
  2. *
  3. * Project _____ __ ____ _ _
  4. * ( _ ) /__\ (_ _)_| |_ _| |_
  5. * )(_)( /(__)\ )( (_ _)(_ _)
  6. * (_____)(__)(__)(__) |_| |_|
  7. *
  8. *
  9. * Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
  10. *
  11. * Licensed under the Apache License, Version 2.0 (the "License");
  12. * you may not use this file except in compliance with the License.
  13. * You may obtain a copy of the License at
  14. *
  15. * http://www.apache.org/licenses/LICENSE-2.0
  16. *
  17. * Unless required by applicable law or agreed to in writing, software
  18. * distributed under the License is distributed on an "AS IS" BASIS,
  19. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  20. * See the License for the specific language governing permissions and
  21. * limitations under the License.
  22. *
  23. ***************************************************************************/
  24. #ifndef oatpp_web_server_api_Controller_hpp
  25. #define oatpp_web_server_api_Controller_hpp
  26. #include "./Endpoint.hpp"
  27. #include "oatpp/web/server/handler/AuthorizationHandler.hpp"
  28. #include "oatpp/web/server/handler/ErrorHandler.hpp"
  29. #include "oatpp/web/server/handler/AuthorizationHandler.hpp"
  30. #include "oatpp/web/protocol/http/incoming/Response.hpp"
  31. #include "oatpp/web/protocol/http/outgoing/Request.hpp"
  32. #include "oatpp/web/protocol/http/outgoing/ResponseFactory.hpp"
  33. #include "oatpp/core/utils/ConversionUtils.hpp"
  34. #include <list>
  35. #include <unordered_map>
  36. namespace oatpp { namespace web { namespace server { namespace api {
  37. /**
  38. * Class responsible for implementation and management of endpoints.<br>
  39. * For details see [ApiController](https://oatpp.io/docs/components/api-controller/).
  40. */
  41. class ApiController : public oatpp::base::Countable {
  42. protected:
  43. typedef ApiController __ControllerType;
  44. public:
  45. /**
  46. * Convenience typedef for &id:oatpp::web::protocol::http::outgoing::ResponseFactory;.
  47. */
  48. typedef oatpp::web::protocol::http::outgoing::ResponseFactory ResponseFactory;
  49. /**
  50. * Convenience typedef for &id:oatpp::web::protocol::http::incoming::Request;.
  51. */
  52. typedef oatpp::web::protocol::http::incoming::Request IncomingRequest;
  53. /**
  54. * Convenience typedef for &id:oatpp::web::protocol::http::outgoing::Request;.
  55. */
  56. typedef oatpp::web::protocol::http::outgoing::Request OutgoingRequest;
  57. /**
  58. * Convenience typedef for &id:oatpp::web::protocol::http::incoming::Response;.
  59. */
  60. typedef oatpp::web::protocol::http::incoming::Response IncomingResponse;
  61. /**
  62. * Convenience typedef for &id:oatpp::web::protocol::http::outgoing::Response;.
  63. */
  64. typedef oatpp::web::protocol::http::outgoing::Response OutgoingResponse;
  65. /**
  66. * Convenience typedef for &id:oatpp::web::protocol::http::Status;.
  67. */
  68. typedef oatpp::web::protocol::http::Status Status;
  69. /**
  70. * Convenience typedef for &id:oatpp::web::protocol::http::Header;.
  71. */
  72. typedef oatpp::web::protocol::http::Header Header;
  73. /**
  74. * Convenience typedef for &id:oatpp::web::protocol::http::QueryParams;.
  75. */
  76. typedef oatpp::web::protocol::http::QueryParams QueryParams;
  77. /**
  78. * Convenience typedef for &id:oatpp::web::server::HttpRequestHandler;.
  79. */
  80. typedef oatpp::web::server::HttpRequestHandler RequestHandler;
  81. /**
  82. * Convenience typedef for &id:oatpp::web::server::handler::AuthorizationHandler;.
  83. */
  84. typedef oatpp::web::server::handler::AuthorizationHandler AuthorizationHandler;
  85. public:
  86. /**
  87. * Convenience typedef for &id:oatpp::data::mapping::ObjectMapper;.
  88. */
  89. typedef oatpp::data::mapping::ObjectMapper ObjectMapper;
  90. /**
  91. * Convenience typedef for &id:oatpp::data::mapping::type::String;.
  92. */
  93. typedef oatpp::String String;
  94. /**
  95. * Convenience typedef for &id:oatpp::data::mapping::type::Int8;.
  96. */
  97. typedef oatpp::Int8 Int8;
  98. /**
  99. * Convenience typedef for &id:oatpp::data::mapping::type::UInt8;.
  100. */
  101. typedef oatpp::UInt8 UInt8;
  102. /**
  103. * Convenience typedef for &id:oatpp::data::mapping::type::Int16;.
  104. */
  105. typedef oatpp::Int16 Int16;
  106. /**
  107. * Convenience typedef for &id:oatpp::data::mapping::type::UInt16;.
  108. */
  109. typedef oatpp::UInt16 UInt16;
  110. /**
  111. * Convenience typedef for &id:oatpp::data::mapping::type::Int32;.
  112. */
  113. typedef oatpp::Int32 Int32;
  114. /**
  115. * Convenience typedef for &id:oatpp::data::mapping::type::UInt32;.
  116. */
  117. typedef oatpp::UInt32 UInt32;
  118. /**
  119. * Convenience typedef for &id:oatpp::data::mapping::type::Int64;.
  120. */
  121. typedef oatpp::Int64 Int64;
  122. /**
  123. * Convenience typedef for &id:oatpp::data::mapping::type::UInt64;.
  124. */
  125. typedef oatpp::UInt64 UInt64;
  126. /**
  127. * Convenience typedef for &id:oatpp::data::mapping::type::Float32;.
  128. */
  129. typedef oatpp::Float32 Float32;
  130. /**
  131. * Convenience typedef for &id:atpp::data::mapping::type::Float64;.
  132. */
  133. typedef oatpp::Float64 Float64;
  134. /**
  135. * Convenience typedef for &id:oatpp::data::mapping::type::Boolean;.
  136. */
  137. typedef oatpp::Boolean Boolean;
  138. /*
  139. * Convenience typedef for std::function<std::shared_ptr<Endpoint::Info>()>.
  140. */
  141. typedef std::function<std::shared_ptr<Endpoint::Info>()> EndpointInfoBuilder;
  142. template <class T>
  143. using Object = oatpp::Object<T>;
  144. template <class T>
  145. using List = oatpp::List<T>;
  146. template <class Value>
  147. using Fields = oatpp::Fields<Value>;
  148. template <class T>
  149. using Enum = oatpp::data::mapping::type::Enum<T>;
  150. protected:
  151. /*
  152. * Endpoint Coroutine base class
  153. */
  154. template<class CoroutineT, class ControllerT>
  155. class HandlerCoroutine : public oatpp::async::CoroutineWithResult<CoroutineT, const std::shared_ptr<OutgoingResponse>&> {
  156. public:
  157. HandlerCoroutine(ControllerT* pController, const std::shared_ptr<IncomingRequest>& pRequest)
  158. : controller(pController)
  159. , request(pRequest)
  160. {}
  161. ControllerT* const controller;
  162. std::shared_ptr<IncomingRequest> request;
  163. };
  164. /*
  165. * Handler which subscribes to specific URL in Router and delegates calls endpoints
  166. */
  167. template<class T>
  168. class Handler : public RequestHandler {
  169. public:
  170. typedef std::shared_ptr<OutgoingResponse> (T::*Method)(const std::shared_ptr<IncomingRequest>&);
  171. typedef oatpp::async::CoroutineStarterForResult<const std::shared_ptr<OutgoingResponse>&>
  172. (T::*MethodAsync)(const std::shared_ptr<IncomingRequest>&);
  173. private:
  174. class ErrorHandlingCoroutine : public oatpp::async::CoroutineWithResult<ErrorHandlingCoroutine, const std::shared_ptr<OutgoingResponse>&> {
  175. private:
  176. Handler* m_handler;
  177. std::shared_ptr<IncomingRequest> m_request;
  178. public:
  179. ErrorHandlingCoroutine(Handler* handler, const std::shared_ptr<IncomingRequest>& request)
  180. : m_handler(handler)
  181. , m_request(request)
  182. {}
  183. async::Action act() override {
  184. return (m_handler->m_controller->*m_handler->m_methodAsync)(m_request)
  185. .callbackTo(&ErrorHandlingCoroutine::onResponse);
  186. }
  187. async::Action onResponse(const std::shared_ptr<OutgoingResponse>& response) {
  188. return this->_return(response);
  189. }
  190. async::Action handleError(async::Error* error) override {
  191. auto eptr = std::make_exception_ptr(*error);
  192. auto response = m_handler->m_controller->m_errorHandler->handleError(eptr);
  193. return this->_return(response);
  194. }
  195. };
  196. private:
  197. T* m_controller;
  198. Method m_method;
  199. MethodAsync m_methodAsync;
  200. public:
  201. Handler(T* controller, Method method, MethodAsync methodAsync)
  202. : m_controller(controller)
  203. , m_method(method)
  204. , m_methodAsync(methodAsync)
  205. {}
  206. public:
  207. static std::shared_ptr<Handler> createShared(T* controller, Method method, MethodAsync methodAsync){
  208. return std::make_shared<Handler>(controller, method, methodAsync);
  209. }
  210. std::shared_ptr<OutgoingResponse> handle(const std::shared_ptr<IncomingRequest>& request) override {
  211. if(m_method == nullptr) {
  212. if(m_methodAsync == nullptr) {
  213. throw protocol::http::HttpError(Status::CODE_500, "[ApiController]: Error. Handler method is nullptr.");;
  214. }
  215. throw protocol::http::HttpError(Status::CODE_500, "[ApiController]: Error. Non-async call to async endpoint.");;
  216. }
  217. try {
  218. return (m_controller->*m_method)(request);
  219. } catch (...) {
  220. auto response = m_controller->handleError(std::current_exception());
  221. if(response != nullptr) {
  222. return response;
  223. }
  224. throw;
  225. }
  226. }
  227. oatpp::async::CoroutineStarterForResult<const std::shared_ptr<OutgoingResponse>&>
  228. handleAsync(const std::shared_ptr<protocol::http::incoming::Request>& request) override {
  229. if(m_methodAsync == nullptr) {
  230. if(m_method == nullptr) {
  231. throw oatpp::web::protocol::http::HttpError(Status::CODE_500, "[ApiController]: Error. Handler method is nullptr.");
  232. }
  233. throw oatpp::web::protocol::http::HttpError(Status::CODE_500, "[ApiController]: Error. Async call to non-async endpoint.");
  234. }
  235. if(m_controller->m_errorHandler) {
  236. return ErrorHandlingCoroutine::startForResult(this, request);
  237. }
  238. return (m_controller->*m_methodAsync)(request);
  239. }
  240. Method setMethod(Method method) {
  241. auto prev = m_method;
  242. m_method = method;
  243. return prev;
  244. }
  245. Method getMethod() {
  246. return m_method;
  247. }
  248. MethodAsync setMethodAsync(MethodAsync methodAsync) {
  249. auto prev = m_methodAsync;
  250. m_methodAsync = methodAsync;
  251. return prev;
  252. }
  253. MethodAsync getMethodAsync() {
  254. return m_methodAsync;
  255. }
  256. };
  257. protected:
  258. /*
  259. * Set endpoint info by endpoint name. (Endpoint name is the 'NAME' parameter of the ENDPOINT macro)
  260. * Info should be set before call to addEndpointsToRouter();
  261. */
  262. void setEndpointInfo(const std::string& endpointName, const std::shared_ptr<Endpoint::Info>& info);
  263. /*
  264. * Get endpoint info by endpoint name. (Endpoint name is the 'NAME' parameter of the ENDPOINT macro)
  265. */
  266. std::shared_ptr<Endpoint::Info> getEndpointInfo(const std::string& endpointName);
  267. /*
  268. * Set endpoint Request handler.
  269. * @param endpointName
  270. * @param handler
  271. */
  272. void setEndpointHandler(const std::string& endpointName, const std::shared_ptr<RequestHandler>& handler);
  273. /*
  274. * Get endpoint Request handler.
  275. * @param endpointName
  276. * @return
  277. */
  278. std::shared_ptr<RequestHandler> getEndpointHandler(const std::string& endpointName);
  279. protected:
  280. Endpoints m_endpoints;
  281. std::shared_ptr<handler::ErrorHandler> m_errorHandler;
  282. std::shared_ptr<handler::AuthorizationHandler> m_defaultAuthorizationHandler;
  283. std::shared_ptr<oatpp::data::mapping::ObjectMapper> m_defaultObjectMapper;
  284. std::unordered_map<std::string, std::shared_ptr<Endpoint::Info>> m_endpointInfo;
  285. std::unordered_map<std::string, std::shared_ptr<RequestHandler>> m_endpointHandlers;
  286. const oatpp::String m_routerPrefix;
  287. public:
  288. ApiController(const std::shared_ptr<oatpp::data::mapping::ObjectMapper>& defaultObjectMapper, const oatpp::String &routerPrefix = nullptr)
  289. : m_defaultObjectMapper(defaultObjectMapper)
  290. , m_routerPrefix(routerPrefix)
  291. {}
  292. public:
  293. template<class T>
  294. static std::shared_ptr<Endpoint> createEndpoint(Endpoints& endpoints,
  295. const std::shared_ptr<Handler<T>>& handler,
  296. const EndpointInfoBuilder& infoBuilder)
  297. {
  298. auto endpoint = Endpoint::createShared(handler, infoBuilder);
  299. endpoints.append(endpoint);
  300. return endpoint;
  301. }
  302. /**
  303. * Get list of Endpoints created via ENDPOINT macro
  304. */
  305. const Endpoints& getEndpoints();
  306. /**
  307. * Set error handler to handle errors that occur during the endpoint's execution
  308. */
  309. void setErrorHandler(const std::shared_ptr<handler::ErrorHandler>& errorHandler);
  310. /**
  311. * Handle the exception using the registered ErrorHandler or if no handler has been set, uses the DefaultErrorHandler::handleError
  312. * @note Does not rethrow an exception anymore, OutgoingResponse has to be returned by the caller!
  313. * @note If this handler fails to handle the exception, it will be handled by the connection handlers ErrorHandler.
  314. */
  315. std::shared_ptr<OutgoingResponse> handleError(const std::exception_ptr& exceptionPtr) const;
  316. /**
  317. * [under discussion]
  318. * Set authorization handler to handle calls to handleAuthorization.
  319. * Must be called before controller is added to a router or swagger-doc if an endpoint uses the AUTHORIZATION macro
  320. */
  321. void setDefaultAuthorizationHandler(const std::shared_ptr<handler::AuthorizationHandler>& authorizationHandler);
  322. /**
  323. * Get authorization handler.
  324. * @return
  325. */
  326. std::shared_ptr<handler::AuthorizationHandler> getDefaultAuthorizationHandler();
  327. /**
  328. * [under discussion]
  329. * Do not use it directly. This method is under discussion.
  330. * Currently returns AuthorizationObject created by AuthorizationHandler or return DefaultAuthorizationObject by DefaultAuthorizationHandler if AuthorizationHandler is null
  331. */
  332. std::shared_ptr<handler::AuthorizationObject> handleDefaultAuthorization(const String &authHeader) const;
  333. const std::shared_ptr<oatpp::data::mapping::ObjectMapper>& getDefaultObjectMapper() const;
  334. // Helper methods
  335. std::shared_ptr<OutgoingResponse> createResponse(const Status& status,
  336. const oatpp::String& str) const;
  337. std::shared_ptr<OutgoingResponse> createResponse(const Status& status) const;
  338. std::shared_ptr<OutgoingResponse> createDtoResponse(const Status& status,
  339. const oatpp::Void& dto,
  340. const std::shared_ptr<oatpp::data::mapping::ObjectMapper>& objectMapper) const;
  341. std::shared_ptr<OutgoingResponse> createDtoResponse(const Status& status,
  342. const oatpp::Void& dto) const;
  343. public:
  344. template<typename T>
  345. struct TypeInterpretation {
  346. static T fromString(const oatpp::String& typeName, const oatpp::String& text, bool& success) {
  347. (void) text;
  348. success = false;
  349. OATPP_LOGE("[oatpp::web::server::api::ApiController::TypeInterpretation::fromString()]",
  350. "Error. No conversion from '%s' to '%s' is defined.", "oatpp::String", typeName->c_str());
  351. throw std::runtime_error("[oatpp::web::server::api::ApiController::TypeInterpretation::fromString()]: Error. "
  352. "No conversion from 'oatpp::String' to '" + *typeName + "' is defined. "
  353. "Please define type conversion.");
  354. }
  355. };
  356. };
  357. template<>
  358. struct ApiController::TypeInterpretation <oatpp::String> {
  359. static oatpp::String fromString(const oatpp::String& typeName, const oatpp::String& text, bool& success) {
  360. (void) typeName;
  361. success = true;
  362. return text;
  363. }
  364. };
  365. template<>
  366. struct ApiController::TypeInterpretation <oatpp::Int8> {
  367. static oatpp::Int8 fromString(const oatpp::String& typeName, const oatpp::String& text, bool& success) {
  368. (void) typeName;
  369. //TODO: check the range and perhaps throw an exception if the variable doesn't fit
  370. return static_cast<Int8::UnderlyingType>(utils::conversion::strToInt32(text, success));
  371. }
  372. };
  373. template<>
  374. struct ApiController::TypeInterpretation <oatpp::UInt8> {
  375. static oatpp::UInt8 fromString(const oatpp::String& typeName, const oatpp::String& text, bool& success) {
  376. (void) typeName;
  377. //TODO: check the range and perhaps throw an exception if the variable doesn't fit
  378. return static_cast<UInt8::UnderlyingType>(utils::conversion::strToUInt32(text, success));
  379. }
  380. };
  381. template<>
  382. struct ApiController::TypeInterpretation <oatpp::Int16> {
  383. static oatpp::Int16 fromString(const oatpp::String& typeName, const oatpp::String& text, bool& success) {
  384. (void) typeName;
  385. //TODO: check the range and perhaps throw an exception if the variable doesn't fit
  386. return static_cast<Int16::UnderlyingType>(utils::conversion::strToInt32(text, success));
  387. }
  388. };
  389. template<>
  390. struct ApiController::TypeInterpretation <oatpp::UInt16> {
  391. static oatpp::UInt16 fromString(const oatpp::String& typeName, const oatpp::String& text, bool& success) {
  392. (void) typeName;
  393. //TODO: check the range and perhaps throw an exception if the variable doesn't fit
  394. return static_cast<UInt16::UnderlyingType>(utils::conversion::strToUInt32(text, success));
  395. }
  396. };
  397. template<>
  398. struct ApiController::TypeInterpretation <oatpp::Int32> {
  399. static oatpp::Int32 fromString(const oatpp::String& typeName, const oatpp::String& text, bool& success) {
  400. (void) typeName;
  401. return utils::conversion::strToInt32(text, success);
  402. }
  403. };
  404. template<>
  405. struct ApiController::TypeInterpretation <oatpp::UInt32> {
  406. static oatpp::UInt32 fromString(const oatpp::String& typeName, const oatpp::String& text, bool& success) {
  407. (void) typeName;
  408. return utils::conversion::strToUInt32(text, success);
  409. }
  410. };
  411. template<>
  412. struct ApiController::TypeInterpretation <oatpp::Int64> {
  413. static oatpp::Int64 fromString(const oatpp::String& typeName, const oatpp::String& text, bool& success) {
  414. (void) typeName;
  415. return utils::conversion::strToInt64(text, success);
  416. }
  417. };
  418. template<>
  419. struct ApiController::TypeInterpretation <oatpp::UInt64> {
  420. static oatpp::UInt64 fromString(const oatpp::String& typeName, const oatpp::String& text, bool& success) {
  421. (void) typeName;
  422. return utils::conversion::strToUInt64(text, success);
  423. }
  424. };
  425. template<>
  426. struct ApiController::TypeInterpretation <oatpp::Float32> {
  427. static oatpp::Float32 fromString(const oatpp::String& typeName, const oatpp::String& text, bool& success) {
  428. (void) typeName;
  429. return utils::conversion::strToFloat32(text, success);
  430. }
  431. };
  432. template<>
  433. struct ApiController::TypeInterpretation <oatpp::Float64> {
  434. static oatpp::Float64 fromString(const oatpp::String& typeName, const oatpp::String& text, bool& success) {
  435. (void) typeName;
  436. return utils::conversion::strToFloat64(text, success);
  437. }
  438. };
  439. template<>
  440. struct ApiController::TypeInterpretation <oatpp::Boolean> {
  441. static oatpp::Boolean fromString(const oatpp::String& typeName, const oatpp::String& text, bool& success) {
  442. (void) typeName;
  443. return utils::conversion::strToBool(text, success);
  444. }
  445. };
  446. template<class T, class I>
  447. struct ApiController::TypeInterpretation <data::mapping::type::EnumObjectWrapper<T, I>> {
  448. typedef data::mapping::type::EnumObjectWrapper<T, I> EnumOW;
  449. typedef typename I::UnderlyingTypeObjectWrapper UTOW;
  450. static EnumOW fromString(const oatpp::String& typeName, const oatpp::String& text, bool& success) {
  451. const auto& parsedValue = ApiController::TypeInterpretation<UTOW>::fromString(typeName, text, success);
  452. if(success) {
  453. data::mapping::type::EnumInterpreterError error = data::mapping::type::EnumInterpreterError::OK;
  454. const auto& result = I::fromInterpretation(parsedValue, error);
  455. if(error == data::mapping::type::EnumInterpreterError::OK) {
  456. return result.template cast<EnumOW>();
  457. }
  458. success = false;
  459. }
  460. return nullptr;
  461. }
  462. };
  463. }}}}
  464. #endif /* oatpp_web_server_api_Controller_hpp */