Skip to content

HTTP

HttpClient is an application service backed by the current platform transport. Requests are explicit value objects and return Task<HttpResult<HttpResponse>>.

Task<void> LoadFeed(std::shared_ptr<HttpClient> http, State<std::string> output) {
auto result = co_await http->SendAsync({
.url = "https://example.com/feed.json",
.method = HttpMethod::Get,
});
if (result.Succeeded()) {
const auto& response = result.Value();
output = "HTTP " + std::to_string(response.status_code) + ": " +
std::to_string(response.body.size()) + " bytes";
} else {
output = result.Error().message;
}
}
[[huxerui::composable]]
View LoadFeedButton(State<std::string> output) {
auto http = UseService<HttpClient>();
auto tasks = UseTaskScope();
return Button("Load feed").OnClick([http, tasks, output] {
tasks.Launch(LoadFeed(http, output));
});
}

Resolve the root service and task scope during composition, then capture those stable handles in the event. Cancellation follows the component that requested the data.

Specify method, headers, body, and optional timeout in HttpRequest. Use HttpMethod for standard methods; the body is owned Bytes, so set the corresponding content type and encoding explicitly when sending text or arbitrary bytes.

The transport follows platform networking policy. Browser CORS, application transport security, Android network security, certificate trust, redirects, and proxy behavior remain platform concerns rather than shared-runtime bypasses.

A response contains final URL, status code, headers, and body. HTTP status codes, including 4xx and 5xx, are valid responses and remain available through Value(). DNS, connection, timeout, and unavailable-transport failures before the requested result use HttpError. Invalid request declarations throw synchronously. Task cancellation suppresses completion; it is not a returned HTTP error.

Inspect Succeeded() before accessing a response and preserve an error message appropriate for the user instead of displaying low-level transport diagnostics directly.

Treat HttpResponse::body as untrusted data. Check the status code and any required content type before decoding, validate the decoded shape, and translate it into an application model before updating UI state. Keep JSON, authentication, retry, and caching policy outside components that only present the result.

Redirect handling is reflected in HttpResponse::url when the platform transport supplies it. Do not use the original request origin as proof that the final response came from the same origin. Apply application limits before retaining large bodies, especially on mobile and Web.

Launch one request from a TaskScope owned by the feature that presents it. User cancellation and unmount should not be shown as a server error. Timeout, transport failure, and an HTTP error status are different outcomes and may deserve different retry policy.

Automatic retries are application policy. Only retry idempotent operations by default, include backoff, and ensure a newer request cannot be overwritten by an older completion. The shared client deliberately does not hide these choices behind implicit global behavior.

The runtime installs HttpClient as a root service; obtain it with UseService<HttpClient>() while composing the owning component. Capture the shared service and controlled state by value in a task. Never put credentials in documentation, client source literals, or generated Web output.

Browser CORS and cookie rules, Apple transport security, Android network security configuration, system proxy settings, and certificate stores remain native policy. The same C++ request can therefore be accepted on one platform and rejected by another configuration; surface HttpError rather than bypassing that policy.

See the HTTP API for exact request and result methods and Tasks for cancellation ownership.

Use SendAsync for bounded JSON or small assets. Use SendStreamAsync when processing a large response incrementally; inspect final status/headers first, then await one Body().ReadAsync(maximum_bytes) at a time. Keep the stream alive until EOF, or let destruction cancel an unfinished response.

Failures before headers appear in HttpResult<HttpResponseStream>; failures during the body appear in IoResult<Bytes>. Test Succeeded() before Value(). An empty successful chunk is EOF, not failure. An HTTP 404 remains a response, not a transport error. Chunks are binary fragments and can split characters or records.

The optional progress callback reports transferred bytes and a total only when meaningful. Display an indeterminate state when the total is unknown. Awaited HTTP and its progress already return to the UI thread; adding RunWorker or TaskScope::Post is unnecessary.

See the complete stream reader for ownership and end-of-stream handling.