Making Requests
Every request begins at a client and is assembled by a
request_builder. This section covers both, and the three ways a builder is
finished.
The Client
A client is the entry point for performing requests. It owns the
configuration, a connection pool, a set of default headers, and a cookie jar,
all shared by every request made through it. Construct one client and reuse it:
that is what lets connections to the same origin be kept alive and reused
across requests.
burl::client client(co_await capy::this_coro::executor, tls_ctx);
The constructor takes the executor that asynchronous operations run on and a
corosio::tls_context for https connections. A third argument, a
client::config, customizes behavior.
A client is movable but not copyable. It is not safe to use a single client concurrently from operations running on different threads.
Verbs
Six member functions create a builder for the common methods:
| Function | Method |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
For any other method, client::request takes an http::method and the URL:
auto rb = client.request(http::method::options, "https://example.com");
Only the http and https schemes are supported; any other scheme fails
the request with error::unsupported_url_scheme.
The Request Builder
The verb functions return a request_builder. Its member functions
configure the request and return the builder again, so calls chain:
auto r = co_await client.get("https://example.com/search")
.query("q", "boost")
.header(http::field::accept, "application/json")
.timeout(std::chrono::seconds(10))
.send();
The builder holds a reference to the client, which must stay alive until the
request has been sent. The configuration calls —
query, header,
basic_auth,
bearer_auth,
timeout,
followlocation, and
body — are each documented in the section for their
feature. A chain is finished by one of three terminal calls.
Finishing: send
send() sends the request and reads the status line
and headers, leaving the body unread. It yields (error_code, response):
auto [ec, r] = co_await client.get("https://example.com").send();
if(ec)
throw std::system_error(ec);
// inspect r.status_int(), r.headers(), then read the body
Use send when a decision depends on the status or headers before the body is
consumed — choosing how to parse it, or short-circuiting on an error. A 4xx or
5xx status sets ec but still returns the response, so the error body remains
readable. The responses section covers what the
returned response offers.
Finishing: as and try_as
When the goal is simply the body as a particular type,
as<T> and try_as<T>
combine sending and reading into one step:
// throws on failure
auto body = co_await client.get("https://example.com").as<std::string>();
// yields (error_code, T)
auto [ec, v] = co_await client.get("https://example.com").try_as<json::value>();
as<T> throws a std::system_error on any failure;
try_as<T> reports it as an error code. The type T
selects the conversion through tag_invoke. These are the same conversions
offered by response, so
co_await client.get(url).as<T>();
is shorthand for send-ing the request and calling response::as<T> on the
result. The exact failure semantics — in particular what happens on a 4xx or 5xx
status — are the subject of the
error handling section.
Finishing: build and execute
build() does not send anything. It returns a
request — a plain value holding the method, URL, headers, body, and
per-request options — that can be stored, passed around, and executed later
through client::execute:
burl::request req = client.post("https://example.com/post")
.header("X-Debug", "1")
.body("payload")
.build();
auto [ec, r] = co_await client.execute(std::move(req));
execute behaves exactly like send: it yields
(error_code, response) with the body unread. Separating construction from
execution is useful for building a request in one place and running it in
another, for queuing requests, or for retrying the same request after a failure.
A built request is independent of the builder and of any particular
client; it can be executed by whichever client is convenient.
Next Steps
-
Request Bodies — Attaching a payload
-
Responses — Reading the result
-
Error Handling — What the error code means
-
Headers and Query Parameters — Shaping the request