# Oat++ 1.2.5 Previous release - [1.2.0](1.2.0.md) Feel free to ask questions - [Chat on Gitter!](https://gitter.im/oatpp-framework/Lobby) Contents: - [Introduce ResponseInterceptor](#introduce-responseinterceptor) - [Enable Global CORS](#enable-global-cors) - [Headers Multimap](#headers-multimap) - [Better Router API](#better-router-api) - [ORM Clean Section](#orm-clean-section) - [ORM PostgreSQL - Arrays Support](#orm-postgresql---arrays-support) - [Swagger-UI Example Values](#swagger-ui-example-values) - [New Modules](#new-modules) ## Introduce ResponseInterceptor ### Declare Response Interceptor ```cpp #include "oatpp/web/server/interceptor/ResponseInterceptor.hpp" class MyResponseInterceptor : public ResponseInterceptor { public: std::shared_ptr intercept(const std::shared_ptr& request, const std::shared_ptr& response) override { // TODO modify response or create a new one return response; // return modified response // returning nullptr will result in an error } }; ``` ### Register global request interceptor ```cpp OATPP_CREATE_COMPONENT(std::shared_ptr, serverConnectionHandler)([] { OATPP_COMPONENT(std::shared_ptr, router); auto connectionHandler = oatpp::web::server::HttpConnectionHandler::createShared(router); /* Add MyResponseInterceptor */ connectionHandler->addResponseInterceptor(std::make_shared()); return connectionHandler; }()); ``` ## Enable Global CORS To enable global CORS for all endpoints: - Add **Request** Interceptor - `oatpp::web::server::interceptor::AllowOptionsGlobal` to `ConnectionHandler`. - Add **Response** Interceptor - `atpp::web::server::interceptor::AllowCorsGlobal` to `ConnectionHandler`. ```cpp #include "oatpp/web/server/interceptor/AllowCorsGlobal.hpp" ... OATPP_CREATE_COMPONENT(std::shared_ptr, serverConnectionHandler)([] { OATPP_COMPONENT(std::shared_ptr, router); // get Router component auto connectionHandler = oatpp::web::server::HttpConnectionHandler::createShared(router); /* Add CORS-enabling interceptors */ connectionHandler->addRequestInterceptor(std::make_shared()); connectionHandler->addResponseInterceptor(std::make_shared()); return connectionHandler; }()); ``` ## Headers Multimap Now headers are stored using [std::multimap](https://en.cppreference.com/w/cpp/container/multimap) and can store multiple entries with the same key. Put multiple headers: ```cpp auto response = createResponse(Status::CODE_200, ""); response->putHeader("Set-Cookie", "..."); response->putHeader("Set-Cookie", "..."); return response; ``` Log all "Set-Cookie" headers: ```cpp const auto& map = headers.getAll(); auto itlow = map.lower_bound("Set-Cookie"); auto itup = map.upper_bound("Set-Cookie"); for(auto it = itlow; it != itup; it ++) { oatpp::String value = it->second.toString(); OATPP_LOGD("Header", "Set-Cookie: %s", value->c_str()); } ``` ## Better Router API Now Router class is a template and can store any value-types and not only `RequestHandler`s. Example use-case - check if endpoint should require authorization: **Add Routs** ```cpp oatpp::web::server::HttpRouterTemplate authEndpoints; authEndpoint.route("POST", "login", false); // DO NOT require auth for /login path authEndpoint.route("POST", "auth", false); // DO NOT require auth for /auth path authEndpoint.route("GET", "*", true); // require auth for all GET authEndpoint.route("POST", "*", true); // require auth for all POST authEndpoint.route("OPTIONS", "*", false); // DO NOT require auth for OPTIONS ``` **Check Auth** ```cpp auto r = authEndpoints.getRoute(request->getStartingLine().method, request->getStartingLine().path); if(r && r.getEndpoint() == true) { // check auth } ``` ## ORM Clean Section For modules: - [oatpp-sqlite](https://github.com/oatpp/oatpp-sqlite) - [oatpp-postgresql](https://github.com/oatpp/oatpp-postgresql) Now it's possible to declare a "clean section" - a section that is untouched by DSL processor. Clean section begins with ``. **Note:** `` char sequences are ignored inside string. ### Example Such query: ```cpp QUERY(selectUserName, "SELECT FROM users WHERE userId=:userId", PARAM(String, userId)) ``` Will be processed as follows: ```sql SELECT name::varchar FROM users WHERE userId="" ``` Note: unlike the `:userId` the `:varchar` char-sequence wasn't interpreted as a template parameter (unlike the `:userId`). ## ORM PostgreSQL - Arrays Support [oatpp-postgresql](https://github.com/oatpp/oatpp-postgresql) now supports arrays. More about PostgreSQL arrays - read [here](https://www.postgresql.org/docs/13/arrays.html) ## Swagger-UI Example Values Now it's possible to add example-values to `RequestBody`, `Response`, and `Parameters` (Path, Headers, Queries) ### Add Consumes Examples ```cpp ENDPOINT_INFO(myEndpoint) { info->addConsumes>("application/json") .addExample("example_1", MyDto::createShared(... /* params here */ )) .addExample("example_2", MyDto::createShared(... /* params here */ )) .addExample("example_3", MyDto::createShared(... /* params here */ )); } ``` ### Add Response Examples ```cpp ENDPOINT_INFO(myEndpoint) { info->addResponse>(Status::CODE_200, "application/json") .addExample("Successful Response_1", MyDto::createShared(... /* params */ )); info->addResponse>(Status::CODE_404, "application/json") .addExample("Error - Not found", ErrorDto::createShared(404, "Not Found")); info->addResponse>(Status::CODE_500, "application/json") .addExample("Error - DB Connection", ErrorDto::createShared(500, "Can't connect to DB")) .addExample("Error - Unknown", ErrorDto::createShared(500, "Unknown Error")); } ``` ### Add Parameter Examples ```cpp ENDPOINT_INFO(myEndpoint) { info->pathParams["userRole"] .addExample("Admin", oatpp::Enum(UserRole::ADMIN)) .addExample("Guest", oatpp::Enum(UserRole::GUEST)); } ``` ## New Modules - [oatpp-openssl](https://github.com/oatpp/oatpp-openssl) - TLS adaptor for OpenSSL (Recommended to use).