Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added ability to handle error codes from all Api requests #289

Merged
merged 1 commit into from
Dec 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/tgbot/Api.h
Original file line number Diff line number Diff line change
Expand Up @@ -1989,7 +1989,7 @@ friend class Bot;

const HttpClient& _httpClient;

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

const std::string _token;
Expand Down
16 changes: 15 additions & 1 deletion include/tgbot/TgException.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,21 @@ namespace TgBot {
class TGBOT_API TgException : public std::runtime_error {

public:
explicit TgException(const std::string& description);

/**
* @brief Enum of possible errors from Api requests
*/
enum class ErrorCode : size_t {
Undefined = 0,
BadRequest = 400, Unauthorized = 401,
Forbidden = 403, NotFound = 404,
Flood = 402, Internal = 500,
HtmlResponse = 100, InvalidJson = 101
};

explicit TgException(const std::string& description, ErrorCode errorCode);

const ErrorCode errorCode;
};

}
Expand Down
25 changes: 17 additions & 8 deletions src/Api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2513,19 +2513,28 @@ boost::property_tree::ptree Api::sendRequest(const std::string& method, const st
{
try {
std::string serverResponse = _httpClient.makeRequest(url, args);

if (!serverResponse.compare(0, 6, "<html>")) {
throw TgException("tgbot-cpp library have got html page instead of json response. Maybe you entered wrong bot token.");
std::string message = "tgbot-cpp library have got html page instead of json response. Maybe you entered wrong bot token.";
throw TgException(message, TgException::ErrorCode::HtmlResponse);
}

boost::property_tree::ptree result = _tgTypeParser.parseJson(serverResponse);
boost::property_tree::ptree result;
try {
if (result.get<bool>("ok", false)) {
return result.get_child("result");
} else {
throw TgException(result.get("description", ""));
}
result = _tgTypeParser.parseJson(serverResponse);
} catch (boost::property_tree::ptree_error& e) {
throw TgException("tgbot-cpp library can't parse json response. " + std::string(e.what()));
std::string message = "tgbot-cpp library can't parse json response. " + std::string(e.what());

throw TgException(message, TgException::ErrorCode::InvalidJson);
}

if (result.get<bool>("ok", false)) {
return result.get_child("result");
} else {
std::string message = result.get("description", "");
size_t errorCode = result.get<size_t>("error_code", 0u);

throw TgException(message, static_cast<TgException::ErrorCode>(errorCode));
}
} catch (...) {
int max_retries = _httpClient.getRequestMaxRetries();
Expand Down
4 changes: 3 additions & 1 deletion src/TgException.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

namespace TgBot {

TgBot::TgException::TgException(const std::string& description) : runtime_error(description) {
TgException::TgException(const std::string& description, ErrorCode errorCode)
: runtime_error(description), errorCode(errorCode)
{
}

}
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
set(TEST_SRC_LIST
main.cpp
tgbot/Api.cpp
tgbot/net/Url.cpp
tgbot/net/HttpParser.cpp
tgbot/tools/StringTools.cpp
Expand Down
64 changes: 64 additions & 0 deletions test/tgbot/Api.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#include <string>
#include <vector>

#include <boost/test/unit_test.hpp>

#include "tgbot/net/HttpClient.h"
#include "tgbot/Api.h"
#include "tgbot/TgException.h"

using namespace std;
using namespace TgBot;

typedef TgException::ErrorCode TgErrorCode;

class TestableApi : public Api {
public:
using Api::Api;
using Api::sendRequest;
};

class HttpClientMock : public HttpClient {
public:
std::string makeRequest(const Url& url, const std::vector<HttpReqArg>& args) const override
{return response;};

int getRequestMaxRetries() const override { return 0;};
int getRequestBackoff() const override {return 1;};

string response;
};

bool Request(TgErrorCode expectedCode, const string& response) {
HttpClientMock httpClientMock;
httpClientMock.response = response;

TestableApi api("token", httpClientMock, "url");

try {
api.sendRequest("", vector<HttpReqArg>());
} catch (TgException& exception) {
return exception.errorCode == expectedCode;
}

return false;
}

BOOST_AUTO_TEST_SUITE(tApi)

BOOST_AUTO_TEST_CASE(sendRequest) {
BOOST_CHECK(Request(TgErrorCode::HtmlResponse, "<html>"));
BOOST_CHECK(Request(TgErrorCode::Undefined, "{\"ok\": false}"));
BOOST_CHECK(Request(TgErrorCode::Undefined, "{\"ok\": false, \"error_code\":0}"));

BOOST_CHECK(Request(TgErrorCode::BadRequest, "{\"ok\": false, \"error_code\":400}"));
BOOST_CHECK(Request(TgErrorCode::Unauthorized, "{\"ok\": false, \"error_code\":401}"));
BOOST_CHECK(Request(TgErrorCode::Forbidden, "{\"ok\": false, \"error_code\":403}"));
BOOST_CHECK(Request(TgErrorCode::NotFound, "{\"ok\": false, \"error_code\":404}"));
BOOST_CHECK(Request(TgErrorCode::Flood, "{\"ok\": false, \"error_code\":402}"));
BOOST_CHECK(Request(TgErrorCode::Internal, "{\"ok\": false, \"error_code\":500}"));

BOOST_CHECK(Request(TgErrorCode::InvalidJson, "error_code:101"));
}

BOOST_AUTO_TEST_SUITE_END()
Loading