clawdforge/clients/cpp/include/clawdforge/error.hpp
Kayos bae34a7701 clients/cpp: initial C++ SDK for clawdforge
Modern C++20 SDK targeting CMake 3.20+. Library is RAII / move-only,
backed by a libcurl easy handle per Client. Public surface is throwing;
exception hierarchy under clawdforge::Error covers AuthError, APIError
(carries status_code + body), TransportError, and ProtocolError.

Dependencies: libcurl + nlohmann/json (FetchContent or find_package).
Tests use cpp-httplib's in-process server + doctest. 12 test cases /
70 assertions cover healthz, run with JSON / text / 502 / files,
multipart upload, full token CRUD, transport failure, URL normalization,
and bad-input rejection. Clean under -Wall -Wextra -Wpedantic -Werror,
ASan + UBSan clean (no leaks, no UB).

upload_file streams via curl_mime_filedata — no in-memory buffering.

Install path produces clawdforge::clawdforge target consumable via
target_link_libraries; FetchContent path mirrors the existing Rust /
Go SDK ergonomics. MIT licensed.
2026-04-28 23:02:51 -07:00

79 lines
2.2 KiB
C++

// SPDX-License-Identifier: MIT
//
// Exception hierarchy for the clawdforge C++ SDK.
//
// All exceptions thrown by `clawdforge::Client` derive from `clawdforge::Error`,
// which itself derives from `std::runtime_error`. Catch `Error` for the
// catch-all path; catch the more specific subclasses when you need to branch.
#pragma once
#include <stdexcept>
#include <string>
#include <utility>
namespace clawdforge {
/// Abstract base for every exception this SDK throws.
///
/// Inherits from `std::runtime_error`, so a top-level `catch (const std::exception&)`
/// will pick these up too.
class Error : public std::runtime_error {
public:
using std::runtime_error::runtime_error;
protected:
// Marker to keep this class abstract — instantiate one of the subclasses.
virtual void anchor_() const = 0;
};
/// Thrown for HTTP 401 / 403 responses or when a required token is missing on
/// the client side.
class AuthError final : public Error {
public:
using Error::Error;
private:
void anchor_() const override {}
};
/// Thrown for any non-2xx HTTP response that isn't an auth failure.
///
/// `status_code` is the HTTP status. `body` is the raw response body (already
/// truncated to a reasonable size by the SDK to keep error logs sane).
class APIError final : public Error {
public:
APIError(int status_code, std::string body, const std::string& msg)
: Error(msg), status_code_(status_code), body_(std::move(body)) {}
[[nodiscard]] int status_code() const noexcept { return status_code_; }
[[nodiscard]] const std::string& body() const noexcept { return body_; }
private:
int status_code_;
std::string body_;
void anchor_() const override {}
};
/// Thrown for libcurl-level transport problems (connect refused, DNS failure,
/// timeout, TLS handshake error, etc.).
class TransportError final : public Error {
public:
using Error::Error;
private:
void anchor_() const override {}
};
/// Thrown for malformed JSON in a response, or when the SDK can't construct a
/// valid HTTP request from caller input (bad URL, missing required field, …).
class ProtocolError final : public Error {
public:
using Error::Error;
private:
void anchor_() const override {}
};
} // namespace clawdforge