Skip to content

Commit 9b00634

Browse files
authored
Merge pull request #8 from ahuarte47/main-http_get-header-and-params
Add new http_get extra function with header & params
2 parents 640fc62 + 9f3871c commit 9b00634

File tree

2 files changed

+100
-14
lines changed

2 files changed

+100
-14
lines changed

src/http_client_extension.cpp

+68-14
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,25 @@ static std::string GetHttpErrorMessage(const duckdb_httplib_openssl::Result &res
125125
return err_message;
126126
}
127127

128+
// Helper function to convert list of entries to a map of parameters.
129+
template <class T>
130+
static int ConvertListEntryToMap(const list_entry_t& list_entry, const duckdb::Vector& input, T& result) {
131+
for (idx_t i = list_entry.offset; i < list_entry.offset + list_entry.length; i++) {
132+
const auto &child_value = input.GetValue(i);
133+
134+
Vector tmp(child_value);
135+
auto &children = StructVector::GetEntries(tmp);
136+
137+
if (children.size() == 2) {
138+
auto name = FlatVector::GetData<string_t>(*children[0]);
139+
auto data = FlatVector::GetData<string_t>(*children[1]);
140+
std::string key = name->GetString();
141+
std::string val = data->GetString();
142+
result.emplace(key, val);
143+
}
144+
}
145+
return result.size();
146+
}
128147

129148
static void HTTPGetRequestFunction(DataChunk &args, ExpressionState &state, Vector &result) {
130149
D_ASSERT(args.data.size() == 1);
@@ -149,6 +168,50 @@ static void HTTPGetRequestFunction(DataChunk &args, ExpressionState &state, Vect
149168
});
150169
}
151170

171+
static void HTTPGetExRequestFunction(DataChunk &args, ExpressionState &state, Vector &result) {
172+
D_ASSERT(args.data.size() == 3);
173+
174+
using STRING_TYPE = PrimitiveType<string_t>;
175+
using LENTRY_TYPE = PrimitiveType<list_entry_t>;
176+
177+
auto &url_vector = args.data[0];
178+
auto &headers_vector = args.data[1];
179+
auto &headers_entry = ListVector::GetEntry(headers_vector);
180+
auto &params_vector = args.data[2];
181+
auto &params_entry = ListVector::GetEntry(params_vector);
182+
183+
GenericExecutor::ExecuteTernary<STRING_TYPE, LENTRY_TYPE, LENTRY_TYPE, STRING_TYPE>(
184+
url_vector, headers_vector, params_vector, result, args.size(),
185+
[&](STRING_TYPE url, LENTRY_TYPE headers, LENTRY_TYPE params) {
186+
std::string url_str = url.val.GetString();
187+
188+
// Use helper to setup client and parse URL
189+
auto client_and_path = SetupHttpClient(url_str);
190+
auto &client = client_and_path.first;
191+
auto &path = client_and_path.second;
192+
193+
// Prepare headers
194+
duckdb_httplib_openssl::Headers header_map;
195+
auto header_list = headers.val;
196+
ConvertListEntryToMap<duckdb_httplib_openssl::Headers>(header_list, headers_entry, header_map);
197+
198+
// Prepare params
199+
duckdb_httplib_openssl::Params param_map;
200+
auto params_list = params.val;
201+
ConvertListEntryToMap<duckdb_httplib_openssl::Params>(params_list, params_entry, param_map);
202+
203+
// Make the POST request with headers and params
204+
auto res = client.Get(path.c_str(), param_map, header_map);
205+
if (res) {
206+
std::string response = GetJsonResponse(res->status, res->reason, res->body);
207+
return StringVector::AddString(result, response);
208+
} else {
209+
std::string response = GetJsonResponse(-1, GetHttpErrorMessage(res, "GET"), "");
210+
return StringVector::AddString(result, response);
211+
}
212+
});
213+
}
214+
152215
static void HTTPPostRequestFunction(DataChunk &args, ExpressionState &state, Vector &result) {
153216
D_ASSERT(args.data.size() == 3);
154217

@@ -173,20 +236,7 @@ static void HTTPPostRequestFunction(DataChunk &args, ExpressionState &state, Vec
173236
// Prepare headers
174237
duckdb_httplib_openssl::Headers header_map;
175238
auto header_list = headers.val;
176-
for (idx_t i = header_list.offset; i < header_list.offset + header_list.length; i++) {
177-
const auto &child_value = headers_entry.GetValue(i);
178-
179-
Vector tmp(child_value);
180-
auto &children = StructVector::GetEntries(tmp);
181-
182-
if (children.size() == 2) {
183-
auto name = FlatVector::GetData<string_t>(*children[0]);
184-
auto data = FlatVector::GetData<string_t>(*children[1]);
185-
std::string key = name->GetString();
186-
std::string val = data->GetString();
187-
header_map.emplace(key, val);
188-
}
189-
}
239+
ConvertListEntryToMap<duckdb_httplib_openssl::Headers>(header_list, headers_entry, header_map);
190240

191241
// Make the POST request with headers and body
192242
auto res = client.Post(path.c_str(), header_map, body.val.GetString(), "application/json");
@@ -204,6 +254,10 @@ static void HTTPPostRequestFunction(DataChunk &args, ExpressionState &state, Vec
204254
static void LoadInternal(DatabaseInstance &instance) {
205255
ScalarFunctionSet http_get("http_get");
206256
http_get.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::JSON(), HTTPGetRequestFunction));
257+
http_get.AddFunction(ScalarFunction(
258+
{LogicalType::VARCHAR, LogicalType::MAP(LogicalType::VARCHAR, LogicalType::VARCHAR),
259+
LogicalType::MAP(LogicalType::VARCHAR, LogicalType::VARCHAR)},
260+
LogicalType::JSON(), HTTPGetExRequestFunction));
207261
ExtensionUtil::RegisterFunction(instance, http_get);
208262

209263
ScalarFunctionSet http_post("http_post");

test/sql/httpclient.test

+32
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,38 @@ FROM
3939
----
4040
200 OK httpbin.org
4141

42+
# Confirm the GET extension works with headers and params
43+
query III
44+
WITH __input AS (
45+
SELECT
46+
http_get(
47+
'https://httpbin.org/delay/0',
48+
headers => MAP {
49+
'accept': 'application/json',
50+
},
51+
params => MAP {
52+
'limit': 10
53+
}
54+
) AS res
55+
),
56+
__response AS (
57+
SELECT
58+
(res->>'status')::INT AS status,
59+
(res->>'reason') AS reason,
60+
unnest( from_json(((res->>'body')::JSON)->'headers', '{"Host": "VARCHAR"}') ) AS features
61+
FROM
62+
__input
63+
)
64+
SELECT
65+
__response.status,
66+
__response.reason,
67+
__response.Host AS host
68+
FROM
69+
__response
70+
;
71+
----
72+
200 OK httpbin.org
73+
4274
# Confirm the POST extension works
4375
query III
4476
WITH __input AS (

0 commit comments

Comments
 (0)