Examples
A runnable catalog of every feature, extracted from
example/usage.cpp.
Each snippet is the body of a capy::task<> coroutine; the surrounding main
and codec setup is shown once in Quick Start. Each entry
links to the guide chapter that covers it in depth.
Basic GET Request
The type passed to as<T> selects how the body is parsed.
See Making Requests and Responses.
burl::client client(co_await capy::this_coro::executor, tls_ctx);
// Response body as a string
auto r1 = co_await client.get("https://example.com")
.as<std::string>();
std::cout << r1 << '\n';
// Response body as JSON
auto r2 = co_await client.get("https://postman-echo.com/get")
.as<json::value>();
std::cout << r2 << '\n';
Inspect Response Status and Headers
send returns the response with headers ready and the
body still unread.
See Responses.
burl::client client(co_await capy::this_coro::executor, tls_ctx);
// send() yields the response without reading the body, so the status
// and headers can be inspected before the body is consumed.
auto [ec, r] = co_await client.get("https://example.com").send();
if(ec)
throw std::system_error(ec);
std::cout << "status: " << r.status_int() << '\n';
std::cout << "reason: " << r.reason() << '\n';
std::cout << "headers: " << r.headers() << '\n';
std::cout << "body: " << co_await r.as<std::string>() << '\n';
Handle Error Status Codes
try_as<T> returns an error_code instead of throwing
on 4xx/5xx.
See Error Handling.
burl::client client(co_await capy::this_coro::executor, tls_ctx);
try
{
auto r1 = co_await client.get("https://example.com/not-found")
.as<std::string>();
}
catch(std::system_error const&e)
{
// HTTP 404 Not Found
std::cerr << e.what() << '\n';
}
// Or inspect the error code instead of throwing
auto [ec, r2] = co_await client.get("https://example.com/not-found")
.try_as<std::string>();
if(ec == burl::condition::client_error)
{
// HTTP 404 Not Found
std::cerr << ec.message() << '\n';
}
Add Query Parameters
query appends percent-encoded key/value pairs to the
URL.
See Query Parameters.
burl::client client(co_await capy::this_coro::executor, tls_ctx);
auto r = co_await client.get("https://postman-echo.com/get")
.query("category", "shoes")
.query("color", "blue")
.as<json::object>();
std::cout << r << '\n';
Set Request Headers
Client headers apply to every request; request headers apply to one.
See Headers.
burl::client client(co_await capy::this_coro::executor, tls_ctx);
// Default headers on the client, sent with every request
client.headers().set(http::field::user_agent, "BoostBurl/1.0");
// Per-request headers
auto r = co_await client.get("https://postman-echo.com/get")
.header(http::field::accept_language, "da, en-gb;q=0.8, en;q=0.7")
.header("X-Trace-Id", "abc123")
.as<json::object>();
std::cout << r << '\n';
Authentication
basic_auth/bearer_auth set
Authorization, on the client or per request.
See Authentication.
burl::client client(co_await capy::this_coro::executor, tls_ctx);
// Default auth, sent with every request
client.basic_auth("user", "pass");
// or client.bearer_auth("TOKEN");
auto r = co_await client.get("https://postman-echo.com/basic-auth")
.basic_auth("postman", "password") // per-request override
// or .bearer_auth("TOKEN")
.as<json::object>();
std::cout << r << '\n';
POST a String Body
A string body defaults to text/plain; override with a content_type header.
See Request Bodies.
burl::client client(co_await capy::this_coro::executor, tls_ctx);
auto r = co_await client.post("https://postman-echo.com/post")
// A string body defaults to Content-Type: text/plain; charset=utf-8
.body("<note>hi</note>")
// Override the Content-Type:
.header(http::field::content_type, "application/xml")
.as<json::object>();
std::cout << r << '\n';
POST a JSON Body
A json::value is serialized and sent as application/json.
See Request Bodies.
burl::client client(co_await capy::this_coro::executor, tls_ctx);
json::object body({ { "user", "John" }, { "lang", "En" } });
auto r1 = co_await client.post("https://postman-echo.com/post")
.body(body)
.as<json::object>();
std::cout << r1 << '\n';
// Or inline
auto r2 = co_await client.post("https://postman-echo.com/post")
.body<json::array>({ 1, 2, 3 })
.as<json::object>();
std::cout << r2 << '\n';
POST a URL-Encoded Form
urlencoded_form builds an application/x-www-form-urlencoded body.
See Request Bodies.
burl::client client(co_await capy::this_coro::executor, tls_ctx);
burl::urlencoded_form form;
form.append("user", "John");
form.append("lang", "En");
auto r1 = co_await client.post("https://postman-echo.com/post")
.body(form)
.as<json::object>();
std::cout << r1 << '\n';
// Or inline
auto r2 = co_await client.post("https://postman-echo.com/post")
.body(burl::urlencoded_form()
.append("user", "John")
.append("lang", "En"))
.as<json::object>();
std::cout << r2 << '\n';
POST a Multipart Form
multipart_form mixes file uploads and text fields as
multipart/form-data.
See Request Bodies.
burl::client client(co_await capy::this_coro::executor, tls_ctx);
burl::multipart_form form;
// filename and MIME type are deduced from the path (or can be passed in)
form.file("attachment", "./crash_report.log");
form.text("priority", "high");
auto r1 = co_await client.post("https://postman-echo.com/post")
.body(form)
.as<json::object>();
std::cout << r1 << '\n';
// Or inline
auto r2 = co_await client.post("https://postman-echo.com/post")
.body(burl::multipart_form()
.file("attachment", "./crash_report.log")
.text("priority", "high"))
.as<json::object>();
std::cout << r2 << '\n';
Upload and Download a File
body<fs::path> streams from a file;
as<fs::path> streams to one.
See Request Bodies and Responses.
namespace fs = std::filesystem;
burl::client client(co_await capy::this_coro::executor, tls_ctx);
fs::path r = co_await client.put("https://postman-echo.com/put")
.body<fs::path>("./crash_report.log") // Load the request body from a file
// Override the auto-deduced Content-Type:
// .header(http::field::content_type, "application/octet-stream")
.as<fs::path>("./resp.txt"); // Save the response body to a file
std::cout << "Response body saved to:" << r << '\n';
Stream a Response Body
pull the body in chunks instead of buffering it all in memory.
See Responses.
burl::client client(co_await capy::this_coro::executor, tls_ctx);
auto [ec, r] = co_await client.get("https://archives.boost.io/"
"release/1.91.0/source/boost_1_91_0.tar.bz2")
.send();
if(ec)
throw std::system_error(ec);
// Read the body incrementally instead of buffering it all in memory
auto source = r.as_buffer_source();
hash2::sha2_256 hash;
for(;;)
{
capy::const_buffer arr[8];
auto [ec, bufs] = co_await source.pull(arr);
if(ec == capy::cond::eof)
break;
if(ec)
throw std::system_error(ec);
for(auto const& buf : bufs)
{
hash.update(buf.data(), buf.size());
source.consume(buf.size());
}
}
std::cout << "sha256: " << hash.result() << '\n';
Read a Response Body In Place
When the body fits in response_inplace_buffer,
as_view reads it straight from the connection’s internal
buffer with no extra allocation.
See Responses.
burl::client::config cfg;
cfg.response_inplace_buffer = 1024 * 1024;
burl::client client(co_await capy::this_coro::executor, tls_ctx, cfg);
auto [ec, r] = co_await client.get("https://www.boost.org").send();
if(ec)
throw std::system_error(ec);
// Use the internal inplace buffer for reading the whole body
// the most efficient method if we know the body always fits.
std::cout << co_await r.as_view() << '\n';
Set Timeouts
Separate limits for connect, each I/O step, and the whole operation.
See Timeouts.
// Client timeouts, applied to every request
burl::client::config cfg;
// Connect timeout, including TLS handshake and proxy connect
cfg.connect_timeout = std::chrono::seconds(30);
// Per read/write timeout, for detecting unresponsive servers regardless
// of the request/response size
cfg.io_timeout = std::chrono::seconds(5);
// Timeout for the whole operation, including retrieving the response
cfg.timeout = std::chrono::seconds(60);
burl::client client(co_await capy::this_coro::executor, tls_ctx, cfg);
auto r = co_await client.get("https://example.com")
.timeout(std::chrono::seconds(3)) // per-request override
.as<std::string>();
std::cout << r << '\n';
Follow Redirects
Chase Location up to maxredirs hops; the response reports
the final URL.
See Redirects.
burl::client::config cfg;
// Follow redirects (enable by default)
cfg.followlocation = true;
cfg.maxredirs = 10;
burl::client client(co_await capy::this_coro::executor, tls_ctx, cfg);
auto [ec1, r1] = co_await client.get("http://boost.org").send();
if(ec1)
throw std::system_error(ec1);
// The final URL after following redirects
std::cout << r1.url() << '\n';
auto [ec2, r2] = co_await client.get("http://boost.org")
.followlocation(false) // per-request override
.send();
if(ec2)
throw std::system_error(ec2);
std::cout << r2.status_int() << '\n'; // e.g. 301
Enable Cookies
Set cookies to keep a jar that stores and replays cookies
per host.
See Cookies.
burl::client::config cfg;
// Cookies (disabled by default)
cfg.cookies = true;
burl::client client(co_await capy::this_coro::executor, tls_ctx, cfg);
auto r = co_await client.get("https://postman-echo.com/cookies/set?foo=bar")
.as<std::string>();
// Print the stored cookies in Netscape format
std::cout << client.cookie_jar().to_netscape();
Reuse Connections With the Pool
Idle connections are kept alive so later requests skip the handshakes.
See Connection Pool.
burl::client::config cfg;
cfg.pool_idle_timeout = std::chrono::seconds(60);
cfg.pool_max_idle_per_host = 10;
burl::client client(co_await capy::this_coro::executor, tls_ctx, cfg);
auto r1 = co_await client.get("https://www.boost.org")
.as<std::string>();
// Reuses the connection established by the first request
auto r2 = co_await client.get("https://www.boost.org")
.as<std::string>();
Use a Proxy
Set proxy to route requests through an HTTP or SOCKS5 proxy.
See Proxies.
burl::client::config cfg;
// SOCKS5 and HTTP proxies are supported
cfg.proxy = urls::url("socks5h://user:pass@localhost:8080");
burl::client client(co_await capy::this_coro::executor, tls_ctx, cfg);
// Sent through the proxy
auto r = co_await client.get("https://example.com")
.as<std::string>();
std::cout << r;
Build a Request and Execute It Later
See Making Requests.
burl::client client(co_await capy::this_coro::executor, tls_ctx);
// build() produces a request that can be stored and executed later
burl::request req = client.post("https://postman-echo.com/post")
.header("X-Debug", "1")
.body("payload")
.build();
auto [ec, r] = co_await client.execute(std::move(req));
if(ec)
throw std::system_error(ec);
std::cout << co_await r.as<json::value>() << '\n';
Next Steps
-
Quick Start — The skeleton, built up one step at a time
-
Making Requests — Where the guide tour begins
-
Testing — Exercising request code without a network