# 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<OutgoingResponse> intercept(const std::shared_ptr<IncomingRequest>& request,
                                              const std::shared_ptr<OutgoingResponse>& 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<oatpp::network::ConnectionHandler>, serverConnectionHandler)([] {

    OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router); 

    auto connectionHandler = oatpp::web::server::HttpConnectionHandler::createShared(router);

    /* Add MyResponseInterceptor */
    connectionHandler->addResponseInterceptor(std::make_shared<MyResponseInterceptor>());

    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<oatpp::network::ConnectionHandler>, serverConnectionHandler)([] {

    OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router); // get Router component

    auto connectionHandler = oatpp::web::server::HttpConnectionHandler::createShared(router);

    /* Add CORS-enabling interceptors */
    connectionHandler->addRequestInterceptor(std::make_shared<oatpp::web::server::interceptor::AllowOptionsGlobal>());
    connectionHandler->addResponseInterceptor(std::make_shared<oatpp::web::server::interceptor::AllowCorsGlobal>());

    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<bool> 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 `<!!` and ends with `!!>`. 
**Note:** `<!!` and `!!>` char sequences are ignored inside string. 

### Example

Such query:

```cpp
QUERY(selectUserName, 
      "SELECT <!! name::varchar !!> FROM users WHERE userId=:userId", 
      PARAM(String, userId))
```

Will be processed as follows:

```sql
SELECT  name::varchar  FROM users WHERE userId="<user-id-value>"
```

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<Object<MyDto>>("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<Object<MyDto>>(Status::CODE_200, "application/json")
    .addExample("Successful Response_1", MyDto::createShared(... /* params */ ));

  info->addResponse<Object<ErrorDto>>(Status::CODE_404, "application/json")
    .addExample("Error - Not found", ErrorDto::createShared(404, "Not Found"));

  info->addResponse<Object<ErrorDto>>(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>(UserRole::ADMIN))
    .addExample("Guest", oatpp::Enum<UserRole>(UserRole::GUEST));

}
```

## New Modules

- [oatpp-openssl](https://github.com/oatpp/oatpp-openssl) - TLS adaptor for OpenSSL (Recommended to use).
