HTTP Methods Reference — C++ source
A searchable reference for every HTTP request method - GET, POST, PUT, PATCH, DELETE, and more. See at a glance which are safe, idempotent, and cacheable, then compare any two methods side by side.
This is the C++ implementation — the same logic the interactive tool runs, in a shareable, citable form.
// Source: cpp.cpp
// Language: C++ (C++17, standard library only)
//
// HTTP request-method reference — pure, deterministic data + lookups.
//
// CosmoDev polyglot showcase port of the `http-methods` tool, ported from
// src/lib/http-methods.ts. Functionally equivalent to the TypeScript original:
// identical inputs yield identical outputs (case-insensitive lookup, flag +
// free-text filtering, and a human-readable semantic comparison report).
//
// Property flags (safe / idempotent / cacheable / hasBody) follow RFC 9110
// and the MDN reference table.
//
// License: display source — part of CosmoDev's polyglot tool pages.
#include <algorithm>
#include <array>
#include <cctype>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
namespace {
/// One HTTP request method and its semantic properties.
///
/// Fields use `std::string_view` so the canonical table can live as a
/// `constexpr` array with no allocation.
struct MethodEntry {
std::string_view method; ///< Uppercase method name, e.g. "GET".
bool safe; ///< Read-only semantics — no server state change.
bool idempotent; ///< Repeating the call has the same effect as a single call.
bool cacheable; ///< Responses may be stored by a cache (RFC 9110 / MDN).
bool has_body; ///< The method conventionally carries a request body.
std::string_view description;
std::string_view typical_use;
};
/// The nine HTTP request methods (RFC 9110 / 9111), in canonical order.
///
/// `inline constexpr` lets callers treat this as a compile-time constant;
/// the helpers hand out pointers into it.
inline constexpr std::array<MethodEntry, 9> METHODS{{
{ "GET",
true, true, true, false,
"Retrieves a representation of the target resource; a read-only request.",
"Fetching a web page, reading an API resource, loading an image." },
{ "POST",
false, false, true, true,
"Submits data to be processed, typically creating a new resource or triggering an action.",
"Submitting a form, creating a record, publishing a message." },
{ "PUT",
false, true, false, true,
"Replaces the target resource entirely with the request body.",
"Updating a full record at a known URL, uploading a file by its path." },
{ "PATCH",
false, false, false, true,
"Applies a partial modification to the target resource.",
"Updating one field of a record, toggling a flag." },
{ "DELETE",
false, true, false, false,
"Removes the target resource.",
"Deleting a record or file by its URL." },
{ "HEAD",
true, true, true, false,
"Identical to GET but returns only the response headers, no body.",
"Checking existence, size, or freshness before downloading." },
{ "OPTIONS",
true, true, false, false,
"Describes the communication options for the target resource.",
"CORS preflight requests, discovering allowed methods." },
{ "CONNECT",
false, false, false, false,
"Establishes a tunnel to the server (used with TLS/HTTPS proxies).",
"Proxying encrypted connections through an intermediary." },
{ "TRACE",
true, true, false, false,
"Performs a message loop-back test along the path to the target (debugging only).",
"Diagnosing request transformations by intermediaries." },
}};
/// Filter options. Each boolean is `std::optional<bool>` so callers can
/// distinguish "constrain to `false`" from "no constraint" — a tri-state a
/// bare `bool` cannot express.
struct MethodFilter {
std::optional<bool> safe;
std::optional<bool> idempotent;
std::optional<bool> cacheable;
/// Free text matched case-insensitively against method, description, and
/// typical_use. Ignored when empty after trimming.
std::optional<std::string> query;
};
/// Semantic diff between two methods.
struct MethodComparison {
bool same_safety = false; ///< Both methods share the `safe` flag.
bool same_idempotence = false; ///< Both methods share the `idempotent` flag.
/// One sentence per mismatched property (safe, idempotent, cacheable, has_body).
std::vector<std::string> differences;
};
std::string to_ascii_lower(std::string_view s)
{
std::string out{s};
std::transform(out.begin(), out.end(), out.begin(), [](unsigned char c) {
return static_cast<char>(std::tolower(c));
});
return out;
}
std::string to_ascii_upper(std::string_view s)
{
std::string out{s};
std::transform(out.begin(), out.end(), out.begin(), [](unsigned char c) {
return static_cast<char>(std::toupper(c));
});
return out;
}
std::string_view trim(std::string_view s)
{
while (!s.empty() && std::isspace(static_cast<unsigned char>(s.front()))) {
s.remove_prefix(1);
}
while (!s.empty() && std::isspace(static_cast<unsigned char>(s.back()))) {
s.remove_suffix(1);
}
return s;
}
/// Does `hay` contain the already-lowercased `needle`? Case-insensitive for
/// ASCII — method names, descriptions, and queries are ASCII text.
bool contains_ci(std::string_view hay, const std::string& lowered_needle)
{
return to_ascii_lower(hay).find(lowered_needle) != std::string::npos;
}
// Phrasing helpers keep the difference-sentence wording in one place, so the
// output stays in lock-step across every polyglot port.
const char* safe_word(bool v)
{
return v ? "safe" : "not safe";
}
const char* idempotent_word(bool v)
{
return v ? "idempotent" : "not idempotent";
}
const char* cacheable_word(bool v)
{
return v ? "cacheable" : "not cacheable";
}
const char* body_word(bool v)
{
return v ? "takes a body" : "does not take a body";
}
} // namespace
/// Case-insensitive single-method lookup.
///
/// Returns a pointer into the canonical table, or null when unknown — the
/// C++ analogue of Rust's `Option<&MethodEntry>` / TS's `MethodEntry | null`.
const MethodEntry* get_method(std::string_view name)
{
// ASCII method names: to_ascii_upper matches TS toUpperCase for the
// alphabetic tokens without paying for full Unicode case-folding.
const std::string n = to_ascii_upper(trim(name));
const auto it = std::find_if(METHODS.begin(), METHODS.end(),
[&](const MethodEntry& m) { return m.method == n; });
return it == METHODS.end() ? nullptr : &*it;
}
/// Returns the methods satisfying every present flag and, when `query` is
/// non-empty after trimming, matching it in at least one of
/// {method, description, typical_use}.
///
/// Returns pointers into the canonical table — no allocation of the records
/// themselves, only of the returned vector.
std::vector<const MethodEntry*> filter_methods(const MethodFilter& opts = {})
{
const std::string q = to_ascii_lower(trim(opts.query.value_or("")));
std::vector<const MethodEntry*> out;
for (const MethodEntry& m : METHODS) {
// Each present flag is an AND constraint; nullopt means skip.
if (opts.safe.has_value() && m.safe != *opts.safe) {
continue;
}
if (opts.idempotent.has_value() && m.idempotent != *opts.idempotent) {
continue;
}
if (opts.cacheable.has_value() && m.cacheable != *opts.cacheable) {
continue;
}
if (!q.empty() && !contains_ci(m.method, q) && !contains_ci(m.description, q) &&
!contains_ci(m.typical_use, q)) {
continue;
}
out.push_back(&m);
}
return out;
}
/// Surfaces where two methods' semantics agree and differ.
///
/// `differences` lists every mismatched property (safe, idempotent,
/// cacheable, has_body) as a human-readable sentence, reproducing the
/// canonical phrasing verbatim so output stays identical to the TypeScript
/// original and the other polyglot ports.
MethodComparison compare_methods(const MethodEntry& a, const MethodEntry& b)
{
MethodComparison out;
out.same_safety = a.safe == b.safe;
out.same_idempotence = a.idempotent == b.idempotent;
if (a.safe != b.safe) {
out.differences.push_back(std::string(a.method) + " is " + safe_word(a.safe) + ", " +
std::string(b.method) + " is " + safe_word(b.safe) + ".");
}
if (a.idempotent != b.idempotent) {
out.differences.push_back(std::string(a.method) + " is " + idempotent_word(a.idempotent) +
", " + std::string(b.method) + " is " +
idempotent_word(b.idempotent) + ".");
}
if (a.cacheable != b.cacheable) {
out.differences.push_back(std::string(a.method) + " is " + cacheable_word(a.cacheable) +
", " + std::string(b.method) + " is " +
cacheable_word(b.cacheable) + ".");
}
if (a.has_body != b.has_body) {
out.differences.push_back(std::string(a.method) + " " + body_word(a.has_body) + ", " +
std::string(b.method) + " " + body_word(b.has_body) + ".");
}
return out;
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →