Skip to content

Commit e66a5c6

Browse files
Extend the ApiResponse type with optional payload (#1337)
Added `ExtendedResponse` and `ExtendedCallback` types that uses `olp::client::NetworkStatistics` as a payload. Enable the GetAggregatedData and QuadTreeIndex APIs to return the extended responses. Added NotFound, Unknown helper methods to `ApiError` class. Fixed a warning in `BackdownStrategy` class. Relates-To: OLPEDGE-2753 Signed-off-by: Mykhailo Kuchma <[email protected]>
1 parent a44d0ed commit e66a5c6

File tree

18 files changed

+438
-134
lines changed

18 files changed

+438
-134
lines changed

olp-cpp-sdk-core/include/olp/core/client/ApiError.h

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2019-2021 HERE Europe B.V.
2+
* Copyright (C) 2019-2022 HERE Europe B.V.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -85,6 +85,30 @@ class CORE_API ApiError {
8585
return {ErrorCode::InvalidArgument, message};
8686
}
8787

88+
/**
89+
* @brief Creates the `ApiError` instance with the not found error code and
90+
* description.
91+
*
92+
* @param description The optional description.
93+
*
94+
* @return The `ApiError` instance.
95+
*/
96+
static ApiError NotFound(const char* message = "Resource not found") {
97+
return {ErrorCode::NotFound, message};
98+
}
99+
100+
/**
101+
* @brief Creates the `ApiError` instance with the unknown error code and
102+
* description.
103+
*
104+
* @param description The optional description.
105+
*
106+
* @return The `ApiError` instance.
107+
*/
108+
static ApiError Unknown(const char* message = "Unknown") {
109+
return {ErrorCode::Unknown, message};
110+
}
111+
88112
ApiError() = default;
89113

90114
/**

olp-cpp-sdk-core/include/olp/core/client/ApiResponse.h

Lines changed: 120 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2019-2021 HERE Europe B.V.
2+
* Copyright (C) 2019-2022 HERE Europe B.V.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,13 +22,36 @@
2222
#include <future>
2323
#include <memory>
2424
#include <string>
25+
#include <type_traits>
2526
#include <utility>
2627

2728
#include "CancellationToken.h"
2829

2930
namespace olp {
3031
namespace client {
3132

33+
/// The `ApiResponse` extension class, used to carry the payload with the
34+
/// response.
35+
template <typename Payload>
36+
class ResponseExtension {
37+
public:
38+
ResponseExtension() = default;
39+
40+
explicit ResponseExtension(Payload payload) : payload_(std::move(payload)) {}
41+
42+
const Payload& GetPayload() const { return payload_; }
43+
44+
protected:
45+
Payload payload_{};
46+
};
47+
48+
/// The `ApiResponse` extension class specialization without any payload.
49+
template <>
50+
class ResponseExtension<void> {
51+
public:
52+
ResponseExtension() = default;
53+
};
54+
3255
/**
3356
* @brief Represents a request outcome.
3457
*
@@ -38,19 +61,78 @@ namespace client {
3861
* @tparam Result The result type.
3962
* @tparam Error The error type.
4063
*/
41-
template <typename Result, typename Error>
42-
class ApiResponse {
64+
template <typename Result, typename Error, typename Payload = void>
65+
class ApiResponse : public ResponseExtension<Payload> {
4366
public:
67+
/// The type of result.
68+
using ResultType = Result;
69+
70+
/// The type of error.
71+
using ErrorType = Error;
72+
73+
/// The type of additional payload.
74+
using PayloadType = Payload;
75+
76+
ApiResponse() = default;
77+
4478
/**
45-
* @brief The type of result.
79+
* @brief Creates the `ApiResponse` instance from a similar response type
80+
* without payload. The payload is default initialized.
81+
*
82+
* @note Enabled only for the use cases when the input response type has no
83+
* payload.
84+
*
85+
* Used for moving the successfully executed request.
86+
*
87+
* @param other The `ApiResponse` instance.
4688
*/
47-
using ResultType = Result;
89+
template <typename P = Payload, typename = typename std::enable_if<
90+
!std::is_same<P, void>::value>::type>
91+
ApiResponse(const ApiResponse<Result, Error, void>& other) // NOLINT
92+
: ResponseExtension<P>(),
93+
result_(other.GetResult()),
94+
error_(other.GetError()),
95+
success_(other.IsSuccessful()) {}
96+
4897
/**
49-
* @brief The type of error.
98+
* @brief Creates the `ApiResponse` instance from a similar response type
99+
* without payload, and a separate payload.
100+
*
101+
* @note Enabled only for the use cases when the input response type has no
102+
* payload.
103+
*
104+
* Used for moving the successfully executed request.
105+
*
106+
* @param other The `ApiResponse` instance.
107+
* @param payload The `Payload` value.
50108
*/
51-
using ErrorType = Error;
109+
template <typename P = Payload, typename = typename std::enable_if<
110+
!std::is_same<P, void>::value>::type>
111+
ApiResponse(const ApiResponse<Result, Error, void>& other, P payload)
112+
: ResponseExtension<P>(std::move(payload)),
113+
result_(other.GetResult()),
114+
error_(other.GetError()),
115+
success_(other.IsSuccessful()) {}
52116

53-
ApiResponse() = default;
117+
/**
118+
* @brief Creates the `ApiResponse` instance from a similar request with a
119+
* payload.
120+
*
121+
* @note Enabled only for the use cases when the input with a payload is
122+
* sliced to the response without payload.
123+
*
124+
* Used for moving the successfully executed request.
125+
*
126+
* @param other The `ApiResponse` instance.
127+
*/
128+
template <
129+
typename U, typename P = Payload,
130+
typename = typename std::enable_if<std::is_same<P, void>::value>::type>
131+
ApiResponse(const ApiResponse<Result, Error, U>& other)
132+
: ResponseExtension<P>(),
133+
result_(other.GetResult()),
134+
error_(other.GetError()),
135+
success_(other.IsSuccessful()) {}
54136

55137
/**
56138
* @brief Creates the `ApiResponse` instance.
@@ -60,7 +142,24 @@ class ApiResponse {
60142
* @param result The `ResultType` instance.
61143
*/
62144
ApiResponse(ResultType result) // NOLINT
63-
: result_(std::move(result)), success_(true) {}
145+
: ResponseExtension<Payload>(),
146+
result_(std::move(result)),
147+
success_(true) {}
148+
149+
/**
150+
* @brief Creates the `ApiResponse` instance with payload.
151+
*
152+
* Used for moving the successfully executed request.
153+
*
154+
* @param result The `ResultType` instance.
155+
* @param payload The payload.
156+
*/
157+
template <typename P = Payload, typename = typename std::enable_if<
158+
!std::is_same<P, void>::value>::type>
159+
ApiResponse(ResultType result, P payload)
160+
: ResponseExtension<Payload>(std::move(payload)),
161+
result_(std::move(result)),
162+
success_(true) {}
64163

65164
/**
66165
* @brief Creates the `ApiResponse` instance if the request is not successful.
@@ -70,6 +169,18 @@ class ApiResponse {
70169
ApiResponse(const ErrorType& error) // NOLINT
71170
: error_(error), success_(false) {}
72171

172+
/**
173+
* @brief Creates the `ApiResponse` instance if the request is not successful.
174+
*
175+
* @param error The `ErrorType` instance.
176+
*/
177+
template <typename P = Payload, typename = typename std::enable_if<
178+
!std::is_same<P, void>::value>::type>
179+
ApiResponse(const ErrorType& error, P payload)
180+
: ResponseExtension<Payload>(std::move(payload)),
181+
error_(error),
182+
success_(false) {}
183+
73184
/**
74185
* @brief Checks the status of the request attempt.
75186
*

olp-cpp-sdk-core/include/olp/core/client/BackdownStrategy.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2020 HERE Europe B.V.
2+
* Copyright (C) 2020-2022 HERE Europe B.V.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -105,7 +105,7 @@ struct CORE_API EqualJitterBackdownStrategy {
105105
constexpr size_t max_retry_count = 30u;
106106
retry_count = std::min<size_t>(retry_count, max_retry_count);
107107
const int64_t exponential_wait_time =
108-
initial_backdown_period.count() * (1 << retry_count);
108+
initial_backdown_period.count() * (1ull << retry_count);
109109
static thread_local std::mt19937 kGenerator(std::random_device{}());
110110
const auto temp = std::min<int64_t>(cap_.count(), exponential_wait_time);
111111
std::uniform_int_distribution<int64_t> dist(0, temp / 2);

olp-cpp-sdk-core/include/olp/core/client/HttpResponse.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2019-2021 HERE Europe B.V.
2+
* Copyright (C) 2019-2022 HERE Europe B.V.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -70,6 +70,13 @@ class NetworkStatistics {
7070
return *this;
7171
}
7272

73+
/// An overloaded addition operator for accumulating statistics.
74+
NetworkStatistics operator+(const NetworkStatistics& other) const {
75+
NetworkStatistics statistics(*this);
76+
statistics += other;
77+
return statistics;
78+
}
79+
7380
private:
7481
uint64_t bytes_uploaded_{0};
7582
uint64_t bytes_downloaded_{0};

olp-cpp-sdk-core/tests/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (C) 2019-2021 HERE Europe B.V.
1+
# Copyright (C) 2019-2022 HERE Europe B.V.
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@ set(OLP_CPP_SDK_CORE_TESTS_SOURCES
2525
./cache/ProtectedKeyListTest.cpp
2626

2727
./client/ApiLookupClientImplTest.cpp
28+
./client/ApiResponseTest.cpp
2829
./client/BackdownStrategyTest.cpp
2930
./client/CancellationContextTest.cpp
3031
./client/ConditionTest.cpp
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* Copyright (C) 2022 HERE Europe B.V.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
* License-Filename: LICENSE
18+
*/
19+
20+
#include <olp/core/client/ApiResponse.h>
21+
22+
#include <gtest/gtest.h>
23+
24+
namespace {
25+
26+
struct PayloadT {
27+
int v;
28+
};
29+
30+
struct PrivateClass {
31+
explicit PrivateClass(int v) : v_(v) {}
32+
PrivateClass(const PrivateClass&) = delete;
33+
PrivateClass(PrivateClass&&) = default;
34+
35+
int v_;
36+
};
37+
38+
using ResultType = int;
39+
using ErrorType = std::string;
40+
41+
using olp::client::ApiResponse;
42+
43+
using IntResponse = ApiResponse<ResultType, ErrorType>;
44+
using ExtendedIntResponse = ApiResponse<ResultType, ErrorType, PayloadT>;
45+
46+
inline bool operator==(const PayloadT& l, const PayloadT& r) {
47+
return l.v == r.v;
48+
}
49+
50+
TEST(ApiResponseTest, Payload) {
51+
ExtendedIntResponse extended_response_1(1, PayloadT{2});
52+
ExtendedIntResponse extended_response_2 = extended_response_1;
53+
EXPECT_EQ(extended_response_1.GetPayload(), extended_response_2.GetPayload());
54+
ExtendedIntResponse extended_response_3(IntResponse(2),
55+
extended_response_2.GetPayload());
56+
EXPECT_EQ(extended_response_1.GetPayload(), extended_response_3.GetPayload());
57+
}
58+
59+
TEST(ApiResponseTest, ResponseSlicing) {
60+
ExtendedIntResponse extended_response_1(1, PayloadT{2});
61+
62+
IntResponse sliced_response_1(extended_response_1);
63+
EXPECT_EQ(sliced_response_1.GetResult(), 1);
64+
EXPECT_EQ(sliced_response_1.IsSuccessful(),
65+
extended_response_1.IsSuccessful());
66+
67+
IntResponse sliced_response_2 = extended_response_1;
68+
EXPECT_EQ(sliced_response_2.GetResult(), 1);
69+
EXPECT_EQ(sliced_response_2.IsSuccessful(),
70+
extended_response_1.IsSuccessful());
71+
72+
ExtendedIntResponse extended_response_2("error", PayloadT{2});
73+
74+
IntResponse sliced_response_3(extended_response_2);
75+
EXPECT_EQ(sliced_response_3.GetError(), "error");
76+
EXPECT_EQ(sliced_response_3.IsSuccessful(),
77+
extended_response_2.IsSuccessful());
78+
79+
IntResponse sliced_response_4 = extended_response_2;
80+
EXPECT_EQ(sliced_response_4.GetError(), "error");
81+
EXPECT_EQ(sliced_response_4.IsSuccessful(),
82+
extended_response_2.IsSuccessful());
83+
}
84+
85+
TEST(ApiResponseTest, ResponseExtention) {
86+
IntResponse normal_response_1(123);
87+
88+
ExtendedIntResponse extended_response_1(normal_response_1);
89+
EXPECT_EQ(extended_response_1.GetResult(), 123);
90+
EXPECT_EQ(extended_response_1.IsSuccessful(),
91+
normal_response_1.IsSuccessful());
92+
93+
ExtendedIntResponse extended_response_2 = normal_response_1;
94+
EXPECT_EQ(extended_response_2.GetResult(), 123);
95+
EXPECT_EQ(extended_response_2.IsSuccessful(),
96+
normal_response_1.IsSuccessful());
97+
98+
ExtendedIntResponse extended_response_3(normal_response_1, PayloadT{234});
99+
EXPECT_EQ(extended_response_3.GetResult(), 123);
100+
EXPECT_EQ(extended_response_3.GetPayload(), PayloadT{234});
101+
102+
IntResponse normal_response_2("error");
103+
104+
ExtendedIntResponse extended_response_4(normal_response_2);
105+
EXPECT_EQ(extended_response_4.GetError(), "error");
106+
EXPECT_EQ(extended_response_4.IsSuccessful(),
107+
normal_response_2.IsSuccessful());
108+
109+
ExtendedIntResponse extended_response_5 = normal_response_2;
110+
EXPECT_EQ(extended_response_5.GetError(), "error");
111+
EXPECT_EQ(extended_response_5.IsSuccessful(),
112+
normal_response_2.IsSuccessful());
113+
114+
ExtendedIntResponse extended_response_6(normal_response_2, PayloadT{234});
115+
EXPECT_EQ(extended_response_6.GetError(), "error");
116+
EXPECT_EQ(extended_response_6.GetPayload(), PayloadT{234});
117+
}
118+
119+
TEST(ApiResponseTest, ResultWithoutCopyCtor) {
120+
using ProvateResponse = ApiResponse<PrivateClass, ErrorType, PayloadT>;
121+
// move constructed
122+
ProvateResponse response_1(PrivateClass(1));
123+
// move asigned
124+
ProvateResponse response_2 = PrivateClass(1);
125+
// response can be moved
126+
ProvateResponse response_3 = std::move(response_2);
127+
}
128+
} // namespace

0 commit comments

Comments
 (0)