-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexample_net.cpp
More file actions
70 lines (62 loc) · 2.9 KB
/
Copy pathexample_net.cpp
File metadata and controls
70 lines (62 loc) · 2.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/*
* Copyright (C) 2025-2026 Toilettrauma
*
* Author: Toilettrauma <macosinternal@gmail.com>
*/
// example_net — the networking half of the toolkit. It makes real HTTP requests
// through the default curl-backed client and shows the three ways a parser
// reaches the network:
// - context.request() -> raw ResponseData (status, headers, effective_url, body)
// - context.request_html() -> a parsed HTML document (fetch + status check + parse)
// - context.request_json() -> a parsed JSON value
// Everything above the client is backend-neutral: swap AsyncClient for another
// ClientContext (e.g. an NSURLSession-backed one) and this code is unchanged.
//
// Unlike example_parse this one needs network access; each call reports its own
// error through the expected channel, so a failure just prints and moves on.
#include <aniparse/net/Client.hpp>
#include <aniparse/ClientContext.hpp>
#include <aniparse/html/HTMLDocument.hpp>
#include <boost/json.hpp>
#include <coro/sync_wait.hpp>
#include <print>
using namespace aniparse;
int main() {
// The default client is curl-backed. Wrapping it in a RequestorContext is all
// a parser ever sees; no logger or config is needed for a plain request.
auto client = std::make_shared<AsyncClient>();
RequestorContext context(client, nullptr, nullptr);
// 1. Raw request: the escape hatch for the low-level response. Note that the
// status, response headers and effective_url are all available here.
std::println("GET https://example.com");
if (auto response = coro::sync_wait(context.request(GetRequest{ .url = "https://example.com" }))) {
std::println(" status: {}", response->status_code);
std::println(" effective_url: {}", response->effective_url.value_or("(none)"));
if (response->headers.contains("content-type")) {
std::println(" content-type: {}", response->headers.get("content-type"));
}
std::println(" body bytes: {}", response->body.size());
} else {
std::println(" failed: {}", response.error().message);
}
// 2. request_html: fetch + 2xx check + parse, all folded into one expected.
std::println("\nrequest_html https://example.com");
if (auto document = coro::sync_wait(context.request_html(GetRequest{ .url = "https://example.com" }))) {
std::println(" <title>: {}", document->title());
} else {
std::println(" failed: {}", document.error().message);
}
// 3. request_json: same, but the body is parsed as JSON.
std::println("\nrequest_json https://jsonplaceholder.typicode.com/users/1");
if (auto json = coro::sync_wait(context.request_json(GetRequest{ .url = "https://jsonplaceholder.typicode.com/users/1" }))) {
if (json->is_object()) {
const boost::json::object& user = json->as_object();
if (auto name = user.if_contains("name"); name && name->is_string()) {
std::println(" user name: {}", name->as_string().c_str());
}
}
} else {
std::println(" failed: {}", json.error().message);
}
return 0;
}