Skip to content

Commit 4099778

Browse files
committed
Add enum for specified error types (Closes #17)
1 parent 3d8a8fe commit 4099778

File tree

8 files changed

+76
-32
lines changed

8 files changed

+76
-32
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ if (COMPILE_TESTS)
3030
target_compile_options(coverage_config INTERFACE -O0 -g --coverage)
3131
target_link_libraries(coverage_config INTERFACE --coverage)
3232
endif ()
33-
add_executable(jsonrpccpp-test test/main.cpp test/client.cpp test/typemapper.cpp test/dispatcher.cpp test/server.cpp test/batchclient.cpp test/testclientconnector.hpp examples/warehouse/warehouseapp.cpp test/warehouseapp.cpp)
33+
add_executable(jsonrpccpp-test test/main.cpp test/client.cpp test/typemapper.cpp test/dispatcher.cpp test/server.cpp test/batchclient.cpp test/testclientconnector.hpp examples/warehouse/warehouseapp.cpp test/warehouseapp.cpp test/common.cpp)
3434
target_compile_options(jsonrpccpp-test PUBLIC "${_warning_opts}")
3535
target_include_directories(jsonrpccpp-test PRIVATE vendor examples)
3636
target_link_libraries(jsonrpccpp-test coverage_config json-rpc-cxx)

include/jsonrpccxx/batchclient.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,12 @@ namespace jsonrpccxx {
6464
try {
6565
return response[results[id]]["result"].get<T>();
6666
} catch (json::type_error &e) {
67-
throw JsonRpcException(-32700, "invalid return type: " + std::string(e.what()));
67+
throw JsonRpcException(parse_error, "invalid return type: " + std::string(e.what()));
6868
}
6969
} else if (errors.find(id) != errors.end()) {
7070
throw JsonRpcException::fromJson(response[errors[id]]["error"]);
7171
}
72-
throw JsonRpcException(-32700, std::string("no result found for id ") + id.dump());
72+
throw JsonRpcException(parse_error, std::string("no result found for id ") + id.dump());
7373
}
7474

7575
bool HasErrors() { return !errors.empty() || !nullIds.empty(); }
@@ -90,11 +90,11 @@ namespace jsonrpccxx {
9090
try {
9191
json response = json::parse(connector.Send(request.Build().dump()));
9292
if (!response.is_array()) {
93-
throw JsonRpcException(-32700, std::string("invalid JSON response from server: expected array"));
93+
throw JsonRpcException(parse_error, std::string("invalid JSON response from server: expected array"));
9494
}
9595
return BatchResponse(std::move(response));
9696
} catch (json::parse_error &e) {
97-
throw JsonRpcException(-32700, std::string("invalid JSON response from server: ") + e.what());
97+
throw JsonRpcException(parse_error, std::string("invalid JSON response from server: ") + e.what());
9898
}
9999
}
100100
};

include/jsonrpccxx/client.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,17 @@ namespace jsonrpccxx {
6060
if (has_key_type(response, "error", json::value_t::object)) {
6161
throw JsonRpcException::fromJson(response["error"]);
6262
} else if (has_key_type(response, "error", json::value_t::string)) {
63-
throw JsonRpcException(-32603, response["error"]);
63+
throw JsonRpcException(internal_error, response["error"]);
6464
}
6565
if (has_key(response, "result") && has_key(response, "id")) {
6666
if (response["id"].type() == json::value_t::string)
6767
return JsonRpcResponse{response["id"].get<std::string>(), response["result"].get<json>()};
6868
else
6969
return JsonRpcResponse{response["id"].get<int>(), response["result"].get<json>()};
7070
}
71-
throw JsonRpcException(-32603, R"(invalid server response: neither "result" nor "error" fields found)");
71+
throw JsonRpcException(internal_error, R"(invalid server response: neither "result" nor "error" fields found)");
7272
} catch (json::parse_error &e) {
73-
throw JsonRpcException(-32700, std::string("invalid JSON response from server: ") + e.what());
73+
throw JsonRpcException(parse_error, std::string("invalid JSON response from server: ") + e.what());
7474
}
7575
}
7676

include/jsonrpccxx/common.hpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,32 @@ namespace jsonrpccxx {
1313
}
1414
static inline bool valid_id_not_null(const json &request) { return has_key(request, "id") && (request["id"].is_number() || request["id"].is_string()); }
1515

16+
enum error_type {
17+
parse_error = -32700,
18+
invalid_request = -32600,
19+
method_not_found = -32601,
20+
invalid_params = -32602,
21+
internal_error = -32603,
22+
server_error,
23+
invalid
24+
};
25+
1626
class JsonRpcException : public std::exception {
1727
public:
1828
JsonRpcException(int code, const std::string &message) noexcept : code(code), message(message), data(nullptr), err(std::to_string(code) + ": " + message) {}
1929
JsonRpcException(int code, const std::string &message, const json &data) noexcept
2030
: code(code), message(message), data(data), err(std::to_string(code) + ": " + message + ", data: " + data.dump()) {}
2131

32+
error_type Type() const {
33+
if (code >= -32603 && code <= -32600)
34+
return static_cast<error_type>(code);
35+
if (code >= -32099 && code <= -32000)
36+
return server_error;
37+
if (code == -32700)
38+
return parse_error;
39+
return invalid;
40+
}
41+
2242
int Code() const { return code; }
2343
const std::string &Message() const { return message; }
2444
const json &Data() const { return data; }
@@ -36,7 +56,7 @@ namespace jsonrpccxx {
3656
return JsonRpcException(value["code"], value["message"]);
3757
}
3858
}
39-
return JsonRpcException(-32603, R"(invalid error response: "code" (negative number) and "message" (string) are required)");
59+
return JsonRpcException(internal_error, R"(invalid error response: "code" (negative number) and "message" (string) are required)");
4060
}
4161

4262
private:

include/jsonrpccxx/dispatcher.hpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,12 @@ namespace jsonrpccxx {
5353
json InvokeMethod(const std::string &name, const json &params) {
5454
auto method = methods.find(name);
5555
if (method == methods.end()) {
56-
throw JsonRpcException(-32601, "method not found: " + name);
56+
throw JsonRpcException(method_not_found, "method not found: " + name);
5757
}
5858
try {
5959
return method->second(normalize_parameter(name, params));
6060
} catch (json::type_error &e) {
61-
throw JsonRpcException(-32602, "invalid parameter: " + std::string(e.what()));
61+
throw JsonRpcException(invalid_params, "invalid parameter: " + std::string(e.what()));
6262
} catch (JsonRpcException &e) {
6363
throw process_type_error(name, e);
6464
}
@@ -67,12 +67,12 @@ namespace jsonrpccxx {
6767
void InvokeNotification(const std::string &name, const json &params) {
6868
auto notification = notifications.find(name);
6969
if (notification == notifications.end()) {
70-
throw JsonRpcException(-32601, "notification not found: " + name);
70+
throw JsonRpcException(method_not_found, "notification not found: " + name);
7171
}
7272
try {
7373
notification->second(normalize_parameter(name, params));
7474
} catch (json::type_error &e) {
75-
throw JsonRpcException(-32602, "invalid parameter: " + std::string(e.what()));
75+
throw JsonRpcException(invalid_params, "invalid parameter: " + std::string(e.what()));
7676
} catch (JsonRpcException &e) {
7777
throw process_type_error(name, e);
7878
}
@@ -89,18 +89,18 @@ namespace jsonrpccxx {
8989
return params;
9090
} else if (params.type() == json::value_t::object) {
9191
if (mapping.find(name) == mapping.end()) {
92-
throw JsonRpcException(-32602, "invalid parameter: procedure doesn't support named parameter");
92+
throw JsonRpcException(invalid_params, "invalid parameter: procedure doesn't support named parameter");
9393
}
9494
json result;
9595
for (auto const &p : mapping[name]) {
9696
if (params.find(p) == params.end()) {
97-
throw JsonRpcException(-32602, "invalid parameter: missing named parameter \"" + p + "\"");
97+
throw JsonRpcException(invalid_params, "invalid parameter: missing named parameter \"" + p + "\"");
9898
}
9999
result.push_back(params[p]);
100100
}
101101
return result;
102102
}
103-
throw JsonRpcException(-32600, "invalid request: params field must be an array, object");
103+
throw JsonRpcException(invalid_request, "invalid request: params field must be an array, object");
104104
}
105105
};
106106
} // namespace jsonrpccxx

include/jsonrpccxx/server.hpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ namespace jsonrpccxx {
5151
return "";
5252
}
5353
} else {
54-
return json{{"id", nullptr}, {"error", {{"code", -32600}, {"message", "invalid request: expected array or object"}}}, {"jsonrpc", "2.0"}}.dump();
54+
return json{{"id", nullptr}, {"error", {{"code", invalid_request}, {"message", "invalid request: expected array or object"}}}, {"jsonrpc", "2.0"}}.dump();
5555
}
5656
} catch (json::parse_error &e) {
57-
return json{{"id", nullptr}, {"error", {{"code", -32700}, {"message", std::string("parse error: ") + e.what()}}}, {"jsonrpc", "2.0"}}.dump();
57+
return json{{"id", nullptr}, {"error", {{"code", parse_error}, {"message", std::string("parse error: ") + e.what()}}}, {"jsonrpc", "2.0"}}.dump();
5858
}
5959
}
6060

@@ -73,24 +73,24 @@ namespace jsonrpccxx {
7373
}
7474
return json{{"id", id}, {"error", error}, {"jsonrpc", "2.0"}};
7575
} catch (std::exception &e) {
76-
return json{{"id", id}, {"error", {{"code", -32603}, {"message", std::string("internal server error: ") + e.what()}}}, {"jsonrpc", "2.0"}};
76+
return json{{"id", id}, {"error", {{"code", internal_error}, {"message", std::string("internal server error: ") + e.what()}}}, {"jsonrpc", "2.0"}};
7777
} catch (...) {
78-
return json{{"id", id}, {"error", {{"code", -32603}, {"message", std::string("internal server error")}}}, {"jsonrpc", "2.0"}};
78+
return json{{"id", id}, {"error", {{"code", internal_error}, {"message", std::string("internal server error")}}}, {"jsonrpc", "2.0"}};
7979
}
8080
}
8181

8282
json ProcessSingleRequest(json &request) {
8383
if (!has_key_type(request, "jsonrpc", json::value_t::string) || request["jsonrpc"] != "2.0") {
84-
throw JsonRpcException(-32600, R"(invalid request: missing jsonrpc field set to "2.0")");
84+
throw JsonRpcException(invalid_request, R"(invalid request: missing jsonrpc field set to "2.0")");
8585
}
8686
if (!has_key_type(request, "method", json::value_t::string)) {
87-
throw JsonRpcException(-32600, "invalid request: method field must be a string");
87+
throw JsonRpcException(invalid_request, "invalid request: method field must be a string");
8888
}
8989
if (has_key(request, "id") && !valid_id(request)) {
90-
throw JsonRpcException(-32600, "invalid request: id field must be a number, string or null");
90+
throw JsonRpcException(invalid_request, "invalid request: id field must be a number, string or null");
9191
}
9292
if (has_key(request, "params") && !(request["params"].is_array() || request["params"].is_object() || request["params"].is_null())) {
93-
throw JsonRpcException(-32600, "invalid request: params field must be an array, object or null");
93+
throw JsonRpcException(invalid_request, "invalid request: params field must be an array, object or null");
9494
}
9595
if (!has_key(request, "params") || has_key_type(request, "params", json::value_t::null)) {
9696
request["params"] = json::array();
@@ -99,7 +99,7 @@ namespace jsonrpccxx {
9999
try {
100100
dispatcher.InvokeNotification(request["method"], request["params"]);
101101
return json();
102-
} catch (std::exception &e) {
102+
} catch (std::exception &) {
103103
return json();
104104
}
105105
} else {

include/jsonrpccxx/typemapper.hpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,25 +67,25 @@ namespace jsonrpccxx {
6767
inline void check_param_type(size_t index, const json &x, json::value_t expectedType, typename std::enable_if<std::is_arithmetic<T>::value>::type * = 0) {
6868
if (expectedType == json::value_t::number_unsigned && x.type() == json::value_t::number_integer) {
6969
if (x.get<long long int>() < 0)
70-
throw JsonRpcException(-32602, "invalid parameter: must be " + type_name(expectedType) + ", but is " + type_name(x.type()), index);
70+
throw JsonRpcException(invalid_params, "invalid parameter: must be " + type_name(expectedType) + ", but is " + type_name(x.type()), index);
7171
} else if (x.type() == json::value_t::number_unsigned && expectedType == json::value_t::number_integer) {
7272
if (x.get<long long unsigned>() > std::numeric_limits<T>::max()) {
73-
throw JsonRpcException(-32602, "invalid parameter: exceeds value range of " + type_name(expectedType), index);
73+
throw JsonRpcException(invalid_params, "invalid parameter: exceeds value range of " + type_name(expectedType), index);
7474
}
7575
}
7676
else if ((x.type() == json::value_t::number_unsigned || x.type() == json::value_t::number_integer) && expectedType == json::value_t::number_float) {
7777
if (static_cast<long long int>(x.get<double>()) != x.get<long long int>()) {
78-
throw JsonRpcException(-32602, "invalid parameter: exceeds value range of " + type_name(expectedType), index);
78+
throw JsonRpcException(invalid_params, "invalid parameter: exceeds value range of " + type_name(expectedType), index);
7979
}
8080
} else if (x.type() != expectedType) {
81-
throw JsonRpcException(-32602, "invalid parameter: must be " + type_name(expectedType) + ", but is " + type_name(x.type()), index);
81+
throw JsonRpcException(invalid_params, "invalid parameter: must be " + type_name(expectedType) + ", but is " + type_name(x.type()), index);
8282
}
8383
}
8484

8585
template <typename T>
8686
inline void check_param_type(size_t index, const json &x, json::value_t expectedType, typename std::enable_if<!std::is_arithmetic<T>::value>::type * = 0) {
8787
if (x.type() != expectedType) {
88-
throw JsonRpcException(-32602, "invalid parameter: must be " + type_name(expectedType) + ", but is " + type_name(x.type()), index);
88+
throw JsonRpcException(invalid_params, "invalid parameter: must be " + type_name(expectedType) + ", but is " + type_name(x.type()), index);
8989
}
9090
}
9191

@@ -99,7 +99,7 @@ namespace jsonrpccxx {
9999
size_t formalSize = sizeof...(ParamTypes);
100100
// TODO: add lenient mode for backwards compatible additional params
101101
if (actualSize != formalSize) {
102-
throw JsonRpcException(-32602, "invalid parameter: expected " + std::to_string(formalSize) + " argument(s), but found " + std::to_string(actualSize));
102+
throw JsonRpcException(invalid_params, "invalid parameter: expected " + std::to_string(formalSize) + " argument(s), but found " + std::to_string(actualSize));
103103
}
104104
(check_param_type<typename std::decay<ParamTypes>::type>(index, params[index], GetType(type<typename std::decay<ParamTypes>::type>())), ...);
105105
return method(params[index].get<typename std::decay<ParamTypes>::type>()...);
@@ -133,7 +133,7 @@ namespace jsonrpccxx {
133133
// TODO: add lenient mode for backwards compatible additional params
134134
// if ((!allow_unkown_params && actualSize != formalSize) || (allow_unkown_params && actualSize < formalSize)) {
135135
if (actualSize != formalSize) {
136-
throw JsonRpcException(-32602, "invalid parameter: expected " + std::to_string(formalSize) + " argument(s), but found " + std::to_string(actualSize));
136+
throw JsonRpcException(invalid_params, "invalid parameter: expected " + std::to_string(formalSize) + " argument(s), but found " + std::to_string(actualSize));
137137
}
138138
(check_param_type<typename std::decay<ParamTypes>::type>(index, params[index], GetType(type<typename std::decay<ParamTypes>::type>())), ...);
139139
method(params[index].get<typename std::decay<ParamTypes>::type>()...);

test/common.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include "catch/catch.hpp"
2+
#include <iostream>
3+
#include <jsonrpccxx/common.hpp>
4+
5+
#define TEST_MODULE "[common]"
6+
7+
using namespace std;
8+
using namespace jsonrpccxx;
9+
using namespace Catch::Matchers;
10+
11+
TEST_CASE("exception error type", TEST_MODULE) {
12+
CHECK(JsonRpcException(-32700, "").Type() == parse_error);
13+
CHECK(JsonRpcException(-32600, "").Type() == invalid_request);
14+
CHECK(JsonRpcException(-32601, "").Type() == method_not_found);
15+
CHECK(JsonRpcException(-32602, "").Type() == invalid_params);
16+
CHECK(JsonRpcException(-32603, "").Type() == internal_error);
17+
18+
for(int c = -32000; c >= -32099; c--)
19+
CHECK(JsonRpcException(c, "").Type() == server_error);
20+
21+
CHECK(JsonRpcException(0, "").Type() == invalid);
22+
CHECK(JsonRpcException(32700, "").Type() == invalid);
23+
CHECK(JsonRpcException(33000, "").Type() == invalid);
24+
}

0 commit comments

Comments
 (0)