Skip to content

Commit 658f37f

Browse files
committed
Added ability to handle error codes from all Api requests
1 parent 7825962 commit 658f37f

File tree

6 files changed

+101
-11
lines changed

6 files changed

+101
-11
lines changed

include/tgbot/Api.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1989,7 +1989,7 @@ friend class Bot;
19891989

19901990
const HttpClient& _httpClient;
19911991

1992-
private:
1992+
protected:
19931993
boost::property_tree::ptree sendRequest(const std::string& method, const std::vector<HttpReqArg>& args = std::vector<HttpReqArg>()) const;
19941994

19951995
const std::string _token;

include/tgbot/TgException.h

+15-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,21 @@ namespace TgBot {
1616
class TGBOT_API TgException : public std::runtime_error {
1717

1818
public:
19-
explicit TgException(const std::string& description);
19+
20+
/**
21+
* @brief Enum of possible errors from Api requests
22+
*/
23+
enum class ErrorCode : size_t {
24+
Undefined = 0,
25+
BadRequest = 400, Unauthorized = 401,
26+
Forbidden = 403, NotFound = 404,
27+
Flood = 402, Internal = 500,
28+
HtmlResponse = 100, InvalidJson = 101
29+
};
30+
31+
explicit TgException(const std::string& description, ErrorCode errorCode);
32+
33+
const ErrorCode errorCode;
2034
};
2135

2236
}

src/Api.cpp

+17-8
Original file line numberDiff line numberDiff line change
@@ -2513,19 +2513,28 @@ boost::property_tree::ptree Api::sendRequest(const std::string& method, const st
25132513
{
25142514
try {
25152515
std::string serverResponse = _httpClient.makeRequest(url, args);
2516+
25162517
if (!serverResponse.compare(0, 6, "<html>")) {
2517-
throw TgException("tgbot-cpp library have got html page instead of json response. Maybe you entered wrong bot token.");
2518+
std::string message = "tgbot-cpp library have got html page instead of json response. Maybe you entered wrong bot token.";
2519+
throw TgException(message, TgException::ErrorCode::HtmlResponse);
25182520
}
25192521

2520-
boost::property_tree::ptree result = _tgTypeParser.parseJson(serverResponse);
2522+
boost::property_tree::ptree result;
25212523
try {
2522-
if (result.get<bool>("ok", false)) {
2523-
return result.get_child("result");
2524-
} else {
2525-
throw TgException(result.get("description", ""));
2526-
}
2524+
result = _tgTypeParser.parseJson(serverResponse);
25272525
} catch (boost::property_tree::ptree_error& e) {
2528-
throw TgException("tgbot-cpp library can't parse json response. " + std::string(e.what()));
2526+
std::string message = "tgbot-cpp library can't parse json response. " + std::string(e.what());
2527+
2528+
throw TgException(message, TgException::ErrorCode::InvalidJson);
2529+
}
2530+
2531+
if (result.get<bool>("ok", false)) {
2532+
return result.get_child("result");
2533+
} else {
2534+
std::string message = result.get("description", "");
2535+
size_t errorCode = result.get<size_t>("error_code", 0u);
2536+
2537+
throw TgException(message, static_cast<TgException::ErrorCode>(errorCode));
25292538
}
25302539
} catch (...) {
25312540
int max_retries = _httpClient.getRequestMaxRetries();

src/TgException.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
namespace TgBot {
66

7-
TgBot::TgException::TgException(const std::string& description) : runtime_error(description) {
7+
TgException::TgException(const std::string& description, ErrorCode errorCode)
8+
: runtime_error(description), errorCode(errorCode)
9+
{
810
}
911

1012
}

test/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
set(TEST_SRC_LIST
22
main.cpp
3+
tgbot/Api.cpp
34
tgbot/net/Url.cpp
45
tgbot/net/HttpParser.cpp
56
tgbot/tools/StringTools.cpp

test/tgbot/Api.cpp

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#include <string>
2+
#include <vector>
3+
4+
#include <boost/test/unit_test.hpp>
5+
6+
#include "tgbot/net/HttpClient.h"
7+
#include "tgbot/Api.h"
8+
#include "tgbot/TgException.h"
9+
10+
using namespace std;
11+
using namespace TgBot;
12+
13+
typedef TgException::ErrorCode TgErrorCode;
14+
15+
class TestableApi : public Api {
16+
public:
17+
using Api::Api;
18+
using Api::sendRequest;
19+
};
20+
21+
class HttpClientMock : public HttpClient {
22+
public:
23+
std::string makeRequest(const Url& url, const std::vector<HttpReqArg>& args) const override
24+
{return response;};
25+
26+
int getRequestMaxRetries() const override { return 0;};
27+
int getRequestBackoff() const override {return 1;};
28+
29+
string response;
30+
};
31+
32+
bool Request(TgErrorCode expectedCode, const string& response) {
33+
HttpClientMock httpClientMock;
34+
httpClientMock.response = response;
35+
36+
TestableApi api("token", httpClientMock, "url");
37+
38+
try {
39+
api.sendRequest("", vector<HttpReqArg>());
40+
} catch (TgException& exception) {
41+
return exception.errorCode == expectedCode;
42+
}
43+
44+
return false;
45+
}
46+
47+
BOOST_AUTO_TEST_SUITE(tApi)
48+
49+
BOOST_AUTO_TEST_CASE(sendRequest) {
50+
BOOST_CHECK(Request(TgErrorCode::HtmlResponse, "<html>"));
51+
BOOST_CHECK(Request(TgErrorCode::Undefined, "{\"ok\": false}"));
52+
BOOST_CHECK(Request(TgErrorCode::Undefined, "{\"ok\": false, \"error_code\":0}"));
53+
54+
BOOST_CHECK(Request(TgErrorCode::BadRequest, "{\"ok\": false, \"error_code\":400}"));
55+
BOOST_CHECK(Request(TgErrorCode::Unauthorized, "{\"ok\": false, \"error_code\":401}"));
56+
BOOST_CHECK(Request(TgErrorCode::Forbidden, "{\"ok\": false, \"error_code\":403}"));
57+
BOOST_CHECK(Request(TgErrorCode::NotFound, "{\"ok\": false, \"error_code\":404}"));
58+
BOOST_CHECK(Request(TgErrorCode::Flood, "{\"ok\": false, \"error_code\":402}"));
59+
BOOST_CHECK(Request(TgErrorCode::Internal, "{\"ok\": false, \"error_code\":500}"));
60+
61+
BOOST_CHECK(Request(TgErrorCode::InvalidJson, "error_code:101"));
62+
}
63+
64+
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)