Skip to content

Commit f56aa7c

Browse files
committed
MOD: Switch C++ client to use POST requests
1 parent 3647f20 commit f56aa7c

File tree

6 files changed

+56
-37
lines changed

6 files changed

+56
-37
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
- Added preliminary support for Windows
77
- Added `LiveThreaded::BlockForStop` to make it easier to wait for one or more records
88
before closing the session
9+
- Switch `BatchSubmitJob` to use form data to avoid query param length limit
10+
- Switch `SymbologyResolve` to use POST request with form data to avoid query param
11+
length limit
912

1013
## 0.9.1 - 2023-07-11
1114

src/detail/http_client.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,9 @@ nlohmann::json HttpClient::GetJson(const std::string& path,
4141
}
4242

4343
nlohmann::json HttpClient::PostJson(const std::string& path,
44-
const httplib::Params& params) {
45-
// need to fully specify, otherwise sent as application/x-www-form-urlencoded
46-
const std::string full_path = httplib::append_query_params(path, params);
47-
httplib::Result res = client_.Post(full_path);
44+
const httplib::Params& form_params) {
45+
// params will be encoded as form data
46+
httplib::Result res = client_.Post(path, {}, form_params);
4847
return HttpClient::CheckAndParseResponse(path, std::move(res));
4948
}
5049

src/historical.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,7 @@ databento::SymbologyResolution Historical::SymbologyResolve(
846846
{"stype_out", ToString(stype_out)}};
847847
detail::SetIfNotEmpty(&params, "end_date", date_range.end);
848848
detail::SetIfNotEmpty(&params, "default_value", default_value);
849-
const nlohmann::json json = client_.GetJson(kPath, params);
849+
const nlohmann::json json = client_.PostJson(kPath, params);
850850
if (!json.is_object()) {
851851
throw JsonResponseError::TypeMismatch(kEndpoint, "object", json);
852852
}

test/include/mock/mock_http_server.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ class MockHttpServer {
4040
private:
4141
static void CheckParams(const std::map<std::string, std::string>& params,
4242
const httplib::Request& req);
43+
static void CheckFormParams(const std::map<std::string, std::string>& params,
44+
const httplib::Request& req);
4345

4446
httplib::Server server_{};
4547
const int port_{};

test/src/historical_tests.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -647,16 +647,16 @@ TEST_F(HistoricalTests, TestSymbologyResolve) {
647647
{"status", 0},
648648
};
649649

650-
mock_server_.MockGetJson("/v0/symbology.resolve",
651-
{
652-
{"dataset", dataset::kGlbxMdp3},
653-
{"start_date", "2022-06-06"},
654-
{"end_date", "2022-06-10"},
655-
{"symbols", "ESM2"},
656-
{"stype_in", "raw_symbol"},
657-
{"stype_out", "instrument_id"},
658-
},
659-
kResp);
650+
mock_server_.MockPostJson("/v0/symbology.resolve",
651+
{
652+
{"dataset", dataset::kGlbxMdp3},
653+
{"start_date", "2022-06-06"},
654+
{"end_date", "2022-06-10"},
655+
{"symbols", "ESM2"},
656+
{"stype_in", "raw_symbol"},
657+
{"stype_out", "instrument_id"},
658+
},
659+
kResp);
660660
const auto port = mock_server_.ListenOnThread();
661661

662662
databento::Historical target{logger_.get(), kApiKey, "localhost",

test/src/mock_http_server.cpp

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
#include "mock/mock_http_server.hpp"
22

3-
#include <fstream> // ifstream
4-
#include <ios> // streamsize
5-
#include <iostream> // cerr
6-
#include <sstream> // ostringstream
7-
#include <stdexcept> // runtime_error
3+
#include <gtest/gtest.h> // EXPECT_*
4+
#include <httplib.h>
5+
6+
#include <fstream> // ifstream
7+
#include <ios> // streamsize
8+
#include <iostream> // cerr
9+
#include <sstream> // ostringstream
810
#include <vector>
911

1012
using databento::mock::MockHttpServer;
@@ -54,16 +56,17 @@ void MockHttpServer::MockGetJson(
5456
}
5557

5658
void MockHttpServer::MockPostJson(
57-
const std::string& path, const std::map<std::string, std::string>& params,
59+
const std::string& path,
60+
const std::map<std::string, std::string>& form_params,
5861
const nlohmann::json& json) {
59-
server_.Post(path, [json, params](const httplib::Request& req,
60-
httplib::Response& resp) {
62+
server_.Post(path, [json, form_params](const httplib::Request& req,
63+
httplib::Response& resp) {
6164
if (!req.has_header("Authorization")) {
6265
resp.status = 401;
6366
return;
6467
}
6568
auto _auth = req.get_header_value("Authorization");
66-
CheckParams(params, req);
69+
CheckFormParams(form_params, req);
6770
resp.set_content(json.dump(), "application/json");
6871
resp.status = 200;
6972
});
@@ -110,19 +113,31 @@ void MockHttpServer::CheckParams(
110113
const std::map<std::string, std::string>& params,
111114
const httplib::Request& req) {
112115
for (const auto& param : params) {
113-
if (!req.has_param(param.first)) {
114-
std::ostringstream err_msg;
115-
err_msg << "Missing query param " << param.first;
116-
std::cerr << err_msg.str() << '\n';
117-
throw std::runtime_error{err_msg.str()};
118-
}
119-
if (req.get_param_value(param.first) != param.second) {
120-
std::ostringstream err_msg;
121-
err_msg << "Incorrect query param value for " << param.first
122-
<< ". Expected " << param.second << ", found "
123-
<< req.get_param_value(param.first);
124-
std::cerr << err_msg.str() << '\n';
125-
throw std::runtime_error{err_msg.str()};
116+
EXPECT_TRUE(req.has_param(param.first))
117+
<< "Missing query param " << param.first;
118+
EXPECT_EQ(req.get_param_value(param.first), param.second)
119+
<< "Incorrect query param value for " << param.first << ". Expected "
120+
<< param.second << ", found " << req.get_param_value(param.first);
121+
}
122+
}
123+
124+
void MockHttpServer::CheckFormParams(
125+
const std::map<std::string, std::string>& params,
126+
const httplib::Request& req) {
127+
EXPECT_EQ(req.get_header_value("content-type"),
128+
"application/x-www-form-urlencoded")
129+
<< "Request body is not form data";
130+
httplib::Params form_params;
131+
httplib::detail::parse_query_text(req.body, form_params);
132+
for (const auto& param : params) {
133+
const auto param_it = form_params.find(param.first);
134+
if (param_it == form_params.end()) {
135+
EXPECT_NE(param_it, form_params.end())
136+
<< "Missing for mparam " << param.first;
137+
} else {
138+
EXPECT_EQ(param_it->second, param.second)
139+
<< "Incorrect form param value for " << param.first << ". Expected "
140+
<< param.second << ", found " << param_it->second;
126141
}
127142
}
128143
}

0 commit comments

Comments
 (0)