restcl is a header-only REST client library for modern C++23 that provides a clean, JSON-first API for interacting with RESTful servers. It abstracts platform-specific HTTP implementations (WinHTTP on Windows, libcurl on Unix/Linux/macOS) behind a unified, modern C++ interface. The library prioritizes simplicity and instructional clarity over performance, making it ideal for applications that need straightforward REST communication without the complexity of lower-level HTTP libraries.
- JSON-First API: JSON is a first-class citizen in the API design
- Modern C++23: Leverages C++23 features including
std::expected,std::format, and user-defined literals - Header-Only: Easy integration with no compilation overhead
- Cross-Platform: Native implementations for Windows (WinHTTP) and Unix/Linux/macOS (libcurl)
- User-Defined Literals: Convenient syntax like
"https://api.example.com"_GET - Async Support: Non-blocking async operations with optional automatic retry and callback-based responses
- Error Handling: Uses
std::expected<T, E>for robust error handling without exceptions for IO operations - Comprehensive Testing: Extensive test suite with unit, integration, and stress tests
- Type-Safe: Template-based design with support for custom character types
- Quick Start
- Documentation
- Installation
- Usage Examples
- Architecture
- Dependencies
- Building
- Testing
- Best Practices
- Contributing
- License
#include <siddiqsoft/restcl.hpp>
using namespace siddiqsoft::restcl_literals;
int main() {
auto client = siddiqsoft::GetRESTClient();
auto request = "https://api.example.com/users"_GET;
auto response = client->send(request);
if (response) {
std::cout << "Status: " << response->statusCode() << "\n";
std::cout << "Body: " << response->body() << "\n";
} else {
std::cerr << "Error: " << response.error() << "\n";
}
return 0;
}#include <siddiqsoft/restcl.hpp>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
using namespace siddiqsoft::restcl_literals;
int main() {
auto client = siddiqsoft::GetRESTClient();
auto request = "https://api.example.com/users"_POST;
json payload = {
{"name", "John Doe"},
{"email", "john@example.com"}
};
request.setBody(payload.dump());
request.setHeader("Content-Type", "application/json");
auto response = client->send(request);
if (response) {
auto result = json::parse(response->body());
std::cout << "Created user: " << result["id"] << "\n";
}
return 0;
}#include <siddiqsoft/restcl.hpp>
#include <atomic>
using namespace siddiqsoft::restcl_literals;
int main() {
auto client = siddiqsoft::GetRESTClient();
std::atomic<bool> done{false};
auto request = "https://api.example.com/data"_GET;
client->sendAsync(request, [&done](const auto& req, auto response) {
if (response) {
std::cout << "Async response: " << response->statusCode() << "\n";
} else {
std::cerr << "Async error: " << response.error() << "\n";
}
done = true;
});
// Wait for async operation to complete
while (!done) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
return 0;
}The library includes comprehensive documentation to help you get started and understand all features:
| Document | Purpose | Best For |
|---|---|---|
| docs/API.md | Complete API reference with 50+ examples | Learning the API, method reference, advanced usage |
| docs/TESTING.md | Comprehensive testing guide | Running tests, writing tests, debugging |
| docs/AUTO_RETRY.md | Auto-retry feature documentation | Resilient applications, retry configuration |
| docs/INDEX.md | Documentation navigation index | Finding what you need quickly |
I want to...
- Get started quickly → docs/API.md - Quick Start
- Understand the API → docs/API.md - API Reference
- Use auto-retry → docs/AUTO_RETRY.md - Quick Start
- Run tests → docs/TESTING.md - Running Tests
- Write tests → docs/TESTING.md - Writing New Tests
- See examples → docs/API.md - Examples
- Understand retry → docs/AUTO_RETRY.md - Feature Overview
nuget install SiddiqSoft.restclAdd to your CMakeLists.txt:
include(FetchContent)
FetchContent_Declare(restcl
GIT_REPOSITORY https://github.com/SiddiqSoft/restcl.git
GIT_TAG main
)
FetchContent_MakeAvailable(restcl)
target_link_libraries(your_target PRIVATE restcl::restcl)- Clone the repository
- Copy the
include/siddiqsoftdirectory to your project - Ensure your compiler supports C++23
- Link against platform-specific libraries:
- Windows: WinHTTP (included in Windows SDK)
- Unix/Linux/macOS: libcurl (make sure to install the development libraries for curl and openssl)
The library provides user-defined literals for all standard HTTP methods:
using namespace siddiqsoft::restcl_literals;
auto get_req = "https://api.example.com/resource"_GET;
auto post_req = "https://api.example.com/resource"_POST;
auto put_req = "https://api.example.com/resource/123"_PUT;
auto delete_req = "https://api.example.com/resource/123"_DELETE;
auto patch_req = "https://api.example.com/resource/123"_PATCH;
auto head_req = "https://api.example.com/resource"_HEAD;
auto options_req = "https://api.example.com/resource"_OPTIONS;auto request = "https://api.example.com/data"_GET;
request.setHeader("Authorization", "Bearer token123");
request.setHeader("Accept", "application/json");
request.setHeader("User-Agent", "MyApp/1.0");
// Access headers
auto auth = request.getHeader("Authorization");auto client = siddiqsoft::GetRESTClient({
{"connectTimeout", 3000}, // Connection timeout in ms
{"timeout", 5000}, // Overall timeout in ms
{"userAgent", "MyApp/1.0"}, // Custom user agent
{"trace", false} // Enable/disable tracing
});The library uses std::expected<T, E> for error handling:
auto response = client->send(request);
if (response) {
// Success path
std::cout << "Status: " << response->statusCode() << "\n";
} else {
// Error path
int error_code = response.error();
std::cerr << "Request failed with error: " << error_code << "\n";
}#include <nlohmann/json.hpp>
using json = nlohmann::json;
// Parse response as JSON
auto response = client->send(request);
if (response && response->statusCode() == 200) {
auto data = json::parse(response->body());
// Access JSON data
std::string name = data["name"];
int age = data["age"];
}For comprehensive API documentation, see API.md.
restcl/
├── include/siddiqsoft/
│ ├── restcl.hpp # Main public header (platform dispatcher)
│ └── private/
│ ├── basic_restclient.hpp # Abstract base class for REST clients
│ ├── http_frame.hpp # Base class for HTTP requests/responses
│ ├── rest_request.hpp # REST request model with literals support
│ ├── rest_response.hpp # REST response model with parsing
│ ├── restcl_unix.hpp # libcurl-based implementation
│ └── restcl_win.hpp # WinHTTP-based implementation
├── tests/ # Comprehensive test suite
│ ├── test_validation.cpp # Validation and error handling tests
│ ├── test_restcl.cpp # Core functionality tests
│ ├── test_serializers.cpp # JSON serialization tests
│ ├── test_postbin.cpp # Integration tests with external services
│ ├── test_libcurl_helpers.cpp # Unix/Linux-specific tests
│ └── test_mock_and_coverage.cpp # Mock and coverage tests
├── docs/ # Documentation
├── .ci/ # CI/CD pipeline templates
│ ├── az-build-windows.yml # Windows build template (x64, arm64)
│ ├── az-build-linux.yml # Linux build template (Clang, GCC)
│ ├── az-publish-nuget.yml # NuGet package publishing
│ └── az-publish-github.yml # GitHub release creation
├── pack/ # NuGet packaging and build helpers
├── CMakeLists.txt # Main CMake configuration
├── CMakePresets.json # CMake presets for builds
├── .clang-format # Code formatting rules
├── .clang-tidy # Static analysis configuration
├── best_practices.md # Comprehensive development guidelines
├── azure-pipelines.yml # Main CI/CD pipeline orchestration
└── README.md # This file
The project uses Azure Pipelines for automated building, testing, and publishing:
- Main Pipeline (
azure-pipelines.yml): Orchestrates three stages - Windows builds, Linux builds, and publication - Build Templates (
.ci/az-build-*.yml): Platform-specific build configurations with comprehensive inline documentation - Publish Templates (
.ci/az-publish-*.yml): Handles NuGet and GitHub release publishing - Multi-Platform: Builds on Windows (MSVC, x64/arm64) and Linux (Clang/GCC)
- Automatic Publishing: Publishes to NuGet and GitHub on main/master branches
- Comprehensive Documentation: All pipeline files include detailed inline comments explaining configuration and troubleshooting
Abstract interface defining the REST client contract with send() and sendAsync() methods.
Base class providing common HTTP functionality including headers, content, and protocol version management.
Extends http_frame with request-specific encoding and HTTP method support.
Extends http_frame with response parsing, status codes, and reason phrases.
HttpRESTClient: Unix/Linux/macOS implementation using libcurlWinHttpRESTClient: Windows implementation using WinHTTP with HTTP/2 support
| Dependency | Version | Purpose |
|---|---|---|
| nlohmann/json | v3.12.0 | JSON parsing and serialization |
| SplitUri | v3.0.0 | URI parsing and manipulation |
| AzureCppUtils | v3.2.5 | Azure-specific utilities |
| string2map | v2.5.0 | String-to-map conversion utilities |
| RunOnEnd | v1.4.2 | RAII-based cleanup utilities |
| asynchrony | v2.1.1 | Asynchronous operation helpers |
| acw32h | v2.7.4 | Windows-specific C++ wrapper for WinHTTP (Windows only) |
| CURL | v8.7+ | libcurl for Unix/Linux/macOS |
| Tool | Version | Purpose |
|---|---|---|
| CMake | v3.29+ | Build system |
| Clang-Format | Latest | Code formatting |
| Clang-Tidy | Latest | Static analysis |
| Google Test | v1.17.0 | Testing framework |
- C++23 Standard: Required
- Visual Studio 2022/2026: For Windows builds (MSVC)
- Clang 18+: For Linux Builds
- GCC 13+: Disabled due to gcc crashes when using ninja
- Clang (LLVM) on macOS: Use homebrew install LLVM
- Clang (XCode) on macOS: Use Apple Clang 21.x.x
NOTE
GCC builds are disabled as part of the CI process due to frequent lock up during compilation using ninja.
- CMake 3.29 or later
- C++23 compatible compiler
- Platform-specific dependencies:
- Windows: Windows SDK (includes WinHTTP)
- Linux: libcurl development libraries (
libcurl-develorlibcurl4-openssl-dev) - macOS: libcurl (usually pre-installed)
# Clone the repository
git clone https://github.com/SiddiqSoft/restcl.git
cd restcl
# Configure with CMake
cmake --preset default -DRESTCL_BUILD_TESTS=ON
# Build the project
cmake --build --preset default
# Run tests (optional)
ctest --preset defaultRESTCL_BUILD_TESTS: Enable/disable test suite (default: OFF)CMAKE_BUILD_TYPE: Debug or Release (default: Release)
The library includes a comprehensive test suite covering:
- Unit Tests (
test_validation.cpp): Request/response validation, error handling, edge cases - Core Tests (
test_restcl.cpp): Core functionality, async operations, multiple HTTP verbs, stress tests - Serialization Tests (
test_serializers.cpp): JSON serialization and deserialization - Integration Tests (
test_postbin.cpp): Real HTTP calls to external services - Platform-Specific Tests (
test_libcurl_helpers.cpp): Unix/Linux-specific libcurl tests - Mock Tests (
test_mock_and_coverage.cpp): Mock objects and code coverage validation - R&D and daily development is on the MacOS while the CI is on Linux (fedora) and Windows (Windows 11).
- All the tests work on the MacOS using LLVM as well as AppleClang
# Build with tests enabled
cmake --preset default -DRESTCL_BUILD_TESTS=ON
cmake --build --preset default
# Run all tests
ctest --preset default
# Run specific test
ctest --preset default -R test_restcl- ASAN (Address Sanitizer) and leak detection enabled for Debug builds on Linux/Clang
- Code coverage instrumentation enabled for Debug builds
- Tests pass on both Windows (MSVC) and Unix/Linux (Clang/GCC)
For comprehensive guidance on code style, testing strategies, common patterns, and best practices when working with or extending this library, see best_practices.md.
- Use
std::expected<T, E>for IO operations instead of exceptions - Throw
std::invalid_argumentfor validation errors - Different platforms return different error codes:
- Windows: WinHTTP error codes (12001, 12002, 12029, etc.)
- Unix/Linux: POSIX error codes (ECONNRESET, etc.)
- Leverage C++23 features:
std::expected,std::format,std::atomic, concepts - Use move semantics extensively
- Prefer
std::shared_ptrfor shared ownership - Use
[[nodiscard]]on functions returning important values
- Use callbacks for async operations:
std::function<void(rest_request<>&, std::expected<rest_response<>, int>)> - Callbacks receive both request and response (or error code)
- Register global callbacks via
configure()and override per-request - Use
std::atomic<bool>with.wait()and.notify_all()for test synchronization
- Classes: PascalCase (e.g.,
rest_request,HttpRESTClient) - Functions: camelCase (e.g.,
setMethod(),getUri()) - Constants: UPPER_SNAKE_CASE (e.g.,
HTTP_NEWLINE) - Private members: Prefix with underscore (e.g.,
_statusCode) - Namespaces: lowercase (e.g.,
siddiqsoft,restcl_literals)
- Use Doxygen comments (
///or/**) for public APIs - Include
@brief,@param,@return,@throwtags - Comment non-obvious algorithms or platform-specific code
- Guard debug output with
#if defined(DEBUG)
Design a library where JSON is a first-class API metaphor for interacting with RESTful servers.
-
Focused Scope: REST interactions with JSON only. This limitation allows us to simplify usage and make it feel very C++ instead of the C-like API of Win32 or LibCURL.
-
Modern C++: C++23 is required, enabling:
- Visual Studio 2022 on Windows
- WinHTTP library with HTTP/2 support
- Modern language features and idioms
-
Header-Only: Easy integration with no compilation overhead for the library itself.
-
Native Implementations: Use platform-specific libraries for actual IO:
- Windows: WinHTTP library
- Unix/Linux/macOS: libcurl
-
User-Defined Literals: Support for convenient syntax like
_GET,_DELETE, etc. via thesiddiqsoft::restcl_literalsnamespace. -
Instructional: Use as little code as necessary and be clear about intent.
-
Interface-Focused: The focus is on the interface to the end user, not internal complexity.
-
Simplicity Over Performance: Hide the underlying implementation and prioritize clarity.
- Performance optimizations
- Additional test coverage
- Extended documentation with more examples
- Support for additional content types
- Enhanced error diagnostics