An open API service indexing awesome lists of open source software.

https://github.com/SSARCandy/cofetch

Chainable, high-performance async HTTP client for modern C++ event loops.
https://github.com/SSARCandy/cofetch

asio async coroutines cpp17 cpp20 curl http-client libcurl

Last synced: 1 day ago
JSON representation

Chainable, high-performance async HTTP client for modern C++ event loops.

Awesome Lists containing this project

README

          

# cofetch: async HTTP client for C++.

[![CI](https://github.com/SSARCandy/cofetch/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/SSARCandy/cofetch/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/SSARCandy/cofetch/graph/badge.svg)](https://codecov.io/gh/SSARCandy/cofetch)
[![Documentation](https://img.shields.io/badge/docs-online-informational?style=flat&link=https://ssarcandy.tw/cofetch)](https://ssarcandy.tw/cofetch)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

Requests **build as a chain**, setters flow off `request()` and the HTTP verb fires the transfer, without blocking the thread:

```cpp
http
.request("https://api.example.com/orders")
.headers({"content-type: application/json"})
.body(R"({"qty": 1})")
.timeout(std::chrono::seconds(2))
.post([](std::error_code ec, cofetch::Response res) {
// transport errors in ec; HTTP status in res.http_code_
});
```

On C++20 that includes coroutines: dependent requests in linear code, no nesting:

```cpp
const auto user = co_await http.async_get(api + "/user", asio::use_awaitable);
const auto posts = co_await http.async_post(api + "/posts", user.data_, asio::use_awaitable);
```

## Why cofetch

- **Header-only.** One file, bring libcurl (linked) and ASIO (include path), then `#include `.
- **Chainable syntax.** Build a request with setters, fire it with the HTTP verb. The same chain works with callbacks, futures, or coroutines.
- **ASIO-native.** Requests run on the `asio::io_context`. Drive it with `run()`, or `poll()` it from a busy loop that must never block.
- **C++17-friendly.** Works on C++17; C++20 adds the `co_await` interface.
- **libcurl underneath.** HTTP/1.1 and HTTP/2 multiplexing, TLS, compression, connection pooling, redirects. For anything cofetch does not wrap, `.curl([](CURL* h) { ... })` exposes the raw handle per request.

## Benchmarks

Same workload for every client: 20,000 GETs against a local nginx. [cpr](https://github.com/libcpr/cpr) and [cpp-httplib](https://github.com/yhirose/cpp-httplib) are synchronous (one request per thread); cofetch keeps 100 in flight requests on a single thread, and wins every scenario: **+35%** single-thread throughput over the fastest sync client, **+31%** with one event loop per core against equal-sized thread pools, **+16%** on sequential chains driven from a busy-poll loop.


cofetch benchmark results

Exact numbers, environment, and how to reproduce:
[bench/README.md](bench/README.md).

## Quick start

```cpp
#include
#include
#include

int main() {
asio::io_context io;
cofetch::Client http(io);

http
.request("https://postman-echo.com/post")
.body("hello=cofetch")
.post([](std::error_code ec, cofetch::Response res) {
if (ec) {
std::cerr << ec.message() << "\n"; // DNS, TLS, timeout...
return;
}
std::cout << res.http_code_ << " " << res.data_ << "\n";
});

io.run(); // or io.poll() from your own loop — examples/example_reactors.cpp
}
```

On C++20 the same flow reads linearly with `co_await` (`examples/example_coroutine.cpp`); the full set lives in [examples/](examples/README.md). Every public symbol at a glance: the [API reference](docs/api-reference.md) cheatsheet.

Prefer a plain value? `cofetch::Request` holds the same fields and fires later via `http.async_perform(std::move(req), token)`.

## Installation

Requirements:
- libcurl ≥ 7.55 (dev headers)
- C++17 compiler (the `co_await` interface needs C++20)
- [ASIO](https://github.com/chriskohlhoff/asio) or Boost.Asio, via `-DCOFETCH_USE_BOOST_ASIO=ON`

### vcpkg

cofetch is in the [vcpkg registry](https://github.com/microsoft/vcpkg/tree/master/ports/cofetch); `asio` and `curl` come along as dependencies, so this is the turnkey path:

```bash
vcpkg install cofetch
```

```cmake
find_package(cofetch CONFIG REQUIRED)
target_link_libraries(your_app PRIVATE cofetch::cofetch)
```

### CMake (FetchContent)

```cmake
include(FetchContent)
FetchContent_Declare(cofetch
GIT_REPOSITORY https://github.com/SSARCandy/cofetch.git
GIT_TAG v0.1.2
)
FetchContent_MakeAvailable(cofetch)
target_link_libraries(your_app PRIVATE cofetch::cofetch)
```

cofetch does not impose an ASIO on consumers: point it at yours (any include path providing ``), or enable the vendored submodule with `-DCOFETCH_USE_VENDORED_ASIO=ON`.

### Manual

Copy `include/cofetch.h`, add asio to your include path, link `libcurl`.

## What cofetch is not

- **Not a server.** Client only. For a server (or a tiny zero-dependency client), use [cpp-httplib](https://github.com/yhirose/cpp-httplib).
- **Not thread-safe.** One `Client` per `io_context` thread by design, no locks on the hot path. The client must outlive its in-flight requests.

## Development

```bash
git submodule update --init # asio + googletest (dev only)
./build.sh -t # Debug build + tests + coverage
./linter.sh # clang-format check (v19 pinned in CI)
doxygen Doxyfile # API reference -> docs/api/html/
```