2021-08-04 06:23:29 +08:00
# Oat++ 1.3.0
Previous release - [1.2.5 ](1.2.5.md )
Feel free to ask questions - [Chat on Gitter! ](https://gitter.im/oatpp-framework/Lobby )
Contents:
- [The New oatpp::String ](#the-new-oatppstring )
- [ConnectionPool::get() Timeout ](#connectionpoolget-timeout )
- [JSON Serializer Escape Flags ](#json-serializer-escape-flags )
2021-10-13 08:03:42 +08:00
- [ConnectionMonitor ](#connectionmonitor )
2021-10-15 06:50:18 +08:00
- [Request Data Bundle ](#request-data-bundle )
2021-10-21 05:42:22 +08:00
- [ConnectionProviderSwitch ](#connectionproviderswitch )
2021-08-17 22:42:44 +08:00
- [Response::getBody() ](#responsegetbody )
2021-08-18 15:20:18 +08:00
- [data::stream::FIFOStream ](#datastreamfifostream )
- [data::stream::BufferedInputStream ](#datastreambufferedinputstream )
2021-10-21 05:42:22 +08:00
- [oatpp::parser::json::mapping::Serializer::Config::alwaysIncludeRequired ](#oatppparserjsonmappingserializerconfigalwaysincluderequired )
2021-08-04 06:23:29 +08:00
## The New oatpp::String
Now it's much easier to use `oatpp::String` since `oatpp::String` is now wrapper over `std::string`
```cpp
{
std::string s1 = Hello;
oatpp::String s2 = s1;
}
{
oatpp::String s1 = "Hello";
2021-08-24 18:54:50 +08:00
std::string s2 = *s1; // *s1 returns a refernce to the internal std::string object
2021-08-04 06:23:29 +08:00
}
2021-08-24 18:54:50 +08:00
{
oatpp::String s1 = "Hello";
std::string s2 = s1; // s1 is used a l-value with a typecast operator
}
2021-08-04 06:23:29 +08:00
{
oatpp::String s1 = "Hello";
bool b = s1 == "Hello"; // compare s1 with const char*
assert(b);
}
{
oatpp::String s1 = "Hello";
std::stringg s2 = "Hello";
bool b = s1 == s2; // compare s1 with std::string
assert(b);
}
{
oatpp::String s1 = "Hello";
std::string s2 = "World";
oatpp::String s3 = s1 + " " + s2; // concat oatpp::String with const char* and std::string directly
OATPP_LOGD("TEST", "str='%s'", s3->c_str()); // prints 'Hello World'
}
```
## ConnectionPool::get() Timeout
[#408 ](https://github.com/oatpp/oatpp/issues/408 )
```cpp
2021-08-04 06:38:44 +08:00
{
auto connectionProvider = oatpp::network::tcp::client::ConnectionProvider::createShared({"httpbin.org", 80});
auto pool = oatpp::network::ClientConnectionPool::createShared(connectionProvider,
1,
std::chrono::seconds(10),
std::chrono::seconds(5));
OATPP_LOGD("TEST", "start")
auto c1 = pool->get(); //< --- this one will succeed
OATPP_LOGD("TEST", "c1=%llu", c1.get())
auto c2 = pool->get(); //< --- this one will fail in 5 sec . Since Max-Resources is 1 , Pool timeout is 5 sec . And c1 is not freed .
OATPP_LOGD("TEST", "c2=%llu", c2.get())
}
```
Output:
```
D |2021-08-04 01:32:56 1628029976986744| TEST:start
D |2021-08-04 01:32:57 1628029977126940| TEST:c1=140716915331208
D |2021-08-04 01:33:02 1628029982128324| TEST:c2=0
2021-08-04 06:23:29 +08:00
```
## JSON Serializer Escape Flags
[#381 ](https://github.com/oatpp/oatpp/issues/381 )
Now you can control if solidus is escaped or not.
### Default Behavior
```cpp
oatpp::parser::json::mapping::ObjectMapper mapper;
// mapper.getSerializer()->getConfig()->escapeFlags = 0; // by default FLAG_ESCAPE_SOLIDUS is ON
auto res = mapper.writeToString(oatpp::String("https://oatpp.io/"));
OATPP_LOGD("TEST", "res='%s'", res->c_str());
```
Output:
```
res='"https:\/\/oatpp.io\/"' # by default, solidus is escaped
```
### Clear Escape Flags
```cpp
oatpp::parser::json::mapping::ObjectMapper mapper;
mapper.getSerializer()->getConfig()->escapeFlags = 0;
auto res = mapper.writeToString(oatpp::String("https://oatpp.io/"));
OATPP_LOGD("TEST", "res='%s'", res->c_str());
```
Output:
```
res='"https://oatpp.io/"' # solidus isn't escaped
```
2021-10-13 08:03:42 +08:00
## ConnectionMonitor
`oatpp::network::monitor::ConnectionMonitor` is a middleman who's able to monitor provided connections and close those ones that not satisfy selected rules.
```cpp
OATPP_CREATE_COMPONENT(std::shared_ptr< oatpp::network::ServerConnectionProvider > , serverConnectionProvider)([] {
auto connectionProvider = oatpp::network::tcp::server::ConnectionProvider::createShared({"0.0.0.0", 8000, oatpp::network::Address::IP_4});
auto monitor = std::make_shared< oatpp::network::monitor::ConnectionMonitor > (connectionProvider);
/* close all connections that stay opened for more than 120 seconds */
monitor->addMetricsChecker(
std::make_shared< oatpp::network::monitor::ConnectionMaxAgeChecker > (
std::chrono::seconds(120)
)
);
/* close all connections that have had no successful reads and writes for longer than 5 seconds */
monitor->addMetricsChecker(
std::make_shared< oatpp::network::monitor::ConnectionInactivityChecker > (
std::chrono::seconds(5),
std::chrono::seconds(5),
)
);
return monitor;
}());
```
**Note:** `ConnectionMonitor` also works with `ClientConnectionProvider` as well.
2021-10-15 06:50:18 +08:00
## Request Data Bundle
Now there is a data bundle associated with the Request and the Response which makes it easy to pass data through middleware interceptors and endpoints.
Example:
```cpp
class MyAuthInterceptor : public oatpp::web::server::interceptor::RequestInterceptor {
public:
std::shared_ptr< OutgoingResponse > intercept(const std::shared_ptr< IncomingRequest > & request) override {
/* authorize request and get auth data */
oatpp::Object< AuthDto > authData = authorize(request);
if(!authData) {
return OutgoingResponse::createShared(Status::CODE_401, nullptr);
}
/* put auth data to bundle for later use at an endpoint */
request->putBundleData("auth", authData);
return nullptr; // continue processing
}
};
...
ENDPOINT("GET", "videos/{videoId}", getVideoById,
PATH(String, videoId),
BUNDLE(oatpp::Object< AuthDto > , authData, "auth"))
{
...
}
```
2021-10-21 05:42:22 +08:00
## ConnectionProviderSwitch
[#483 ](https://github.com/oatpp/oatpp/issues/483 )
`oatpp::network::ConnectionProviderSwitch` can be used to change connection providers on the go, ex.: when you want to reload an SSL certificate without stopping the server.
```cpp
/* create server connection provider component */
/* use ConnectionProviderSwitch instead of a regular ServerConnectionProvider */
OATPP_CREATE_COMPONENT(std::shared_ptr< oatpp::network::ConnectionProviderSwitch > , serverConnectionProvider)([this] {
/* create SSL provider */
auto sslProvider = oatpp::libressl::server::ConnectionProvider::createShared(...);
/* create oatpp::network::ConnectionProviderSwitch*/
return std::make_shared< oatpp::network::ConnectionProviderSwitch > (sslProvider /* current provider */);
}());
...
void reloadCert() {
/* get server connection provider component */
OATPP_COMPONENT(std::shared_ptr< oatpp::network::ConnectionProviderSwitch > , providerSwitch);
/* create new SSL provider with new cert */
auto sslProvider = oatpp::libressl::server::ConnectionProvider::createShared(...);
/* set new provider */
providerSwitch->resetProvider(sslProvider);
}
```
2021-08-17 22:42:44 +08:00
## Response::getBody()
2021-10-19 14:24:02 +08:00
`oatpp::web::protocol::http::outgoing::Response` has a new method `getBody()` to retreive the body of the response.
This is handy for response interceptors.
2021-08-18 15:22:30 +08:00
2021-08-18 15:20:18 +08:00
## data::stream::FIFOStream
The new `FIFOStream` stream is a buffered
2021-08-24 18:54:50 +08:00
[`InputStream` ](https://oatpp.io/api/latest/oatpp/core/data/stream/Stream/#inputstream ) with an
2021-08-18 15:20:18 +08:00
[`WriteCallback` ](https://oatpp.io/api/latest/oatpp/core/data/stream/Stream/#writecallback ).
Check the corresponding documentation on how to use these interfaces.
Instead of using a static buffer like `BufferInputStream` it is build upon `data::buffer::FIFOBuffer` and is able to
dynamically grow when data is written to it that would surpass its capacity.
It is especially useful if you need to buffer data from a stream upfront or have multiple data sources that should be
buffered in a single stream.
However, it is not synchronized, so be careful when using `FIFOStream` in a multithreaded manner.
You need to implement your own locking.
2021-08-18 15:22:30 +08:00
2021-08-18 15:20:18 +08:00
## data::stream::BufferedInputStream
`FIFOStream` also introduced a new interface
[`BufferedInputStream` ](https://oatpp.io/api/latest/oatpp/core/data/stream/Stream/#bufferedinputstream ) which unifies
the bufferd-stream-interface all existing buffered streams (`InputStreamBufferedProxy`, `BufferInputStream` ,
`FIFOStream` ) to allow for generalisation.
2021-10-19 14:24:02 +08:00
## oatpp::parser::json::mapping::Serializer::Config::alwaysIncludeRequired
If `oatpp::parser::json::mapping::Serializer::Config::includeNullFields == false` there might still be the requirement
to include some fields even if they are `nullptr` , because they are required by the deserializing end.
Consider the following DTO and endpoint-snippet.
```c++
class StatusDto : public oatpp::DTO {
DTO_INIT(StatusDto, DTO)
DTO_FIELD_INFO(status) {
info->required = true;
}
DTO_FIELD(String, status);
DTO_FIELD(Int32, code);
DTO_FIELD(String, message);
};
// endpoint code:
ENDPOINT("GET", "/status", status) {
auto dto = StatusDto::createShared();
dto->code = 200;
return createDtoResponse(Status::CODE_200, dto);
}
```
With a serializer with its config set to `Serializer::Config::includeNullFields = false` , the snippet would just yield `{"code":200}` .
However, `status` is a required field.
Now, one can set `Serializer::Config::alwaysIncludeRequired = true` .
With `alwaysIncludeRequired == true` , the same snippet would yield `{"status":null,"code":200}` , even with `includeNullFields == false` .