Skip to content

HTTP Methods Reference — Rust 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 Rust implementation — the same logic the interactive tool runs, in a shareable, citable form.

// Source file: rust.rs
// Language: Rust
//
// 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.
//
// Display source — part of CosmoDev's polyglot tool pages.

//! HTTP request-method reference — pure data + lookups.
//!
//! The canonical [`METHODS`] table holds the nine RFC 9110 / 9111 methods with
//! their semantic property flags. All helpers are read-only and return
//! borrowed references into that single source of truth.

/// One HTTP request method and its semantic properties.
///
/// Fields use `&'static str` so the canonical table can live as a `const`
/// slice with no allocation.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MethodEntry {
    /// Uppercase method name, e.g. `"GET"`.
    pub method: &'static str,
    /// Read-only semantics — no server state change.
    pub safe: bool,
    /// Repeating the call has the same effect as a single call.
    pub idempotent: bool,
    /// Responses may be stored by a cache (RFC 9110 / MDN).
    pub cacheable: bool,
    /// The method conventionally carries a request body.
    pub has_body: bool,
    pub description: &'static str,
    pub typical_use: &'static str,
}

/// The nine HTTP request methods (RFC 9110 / 9111), in canonical order.
///
/// `pub const` lets callers treat this as a compile-time constant; the
/// helpers borrow from it via `'static` references.
pub const METHODS: &[MethodEntry] = &[
    MethodEntry {
        method: "GET",
        safe: true,
        idempotent: true,
        cacheable: true,
        has_body: false,
        description: "Retrieves a representation of the target resource; a read-only request.",
        typical_use: "Fetching a web page, reading an API resource, loading an image.",
    },
    MethodEntry {
        method: "POST",
        safe: false,
        idempotent: false,
        cacheable: true,
        has_body: true,
        description: "Submits data to be processed, typically creating a new resource or triggering an action.",
        typical_use: "Submitting a form, creating a record, publishing a message.",
    },
    MethodEntry {
        method: "PUT",
        safe: false,
        idempotent: true,
        cacheable: false,
        has_body: true,
        description: "Replaces the target resource entirely with the request body.",
        typical_use: "Updating a full record at a known URL, uploading a file by its path.",
    },
    MethodEntry {
        method: "PATCH",
        safe: false,
        idempotent: false,
        cacheable: false,
        has_body: true,
        description: "Applies a partial modification to the target resource.",
        typical_use: "Updating one field of a record, toggling a flag.",
    },
    MethodEntry {
        method: "DELETE",
        safe: false,
        idempotent: true,
        cacheable: false,
        has_body: false,
        description: "Removes the target resource.",
        typical_use: "Deleting a record or file by its URL.",
    },
    MethodEntry {
        method: "HEAD",
        safe: true,
        idempotent: true,
        cacheable: true,
        has_body: false,
        description: "Identical to GET but returns only the response headers, no body.",
        typical_use: "Checking existence, size, or freshness before downloading.",
    },
    MethodEntry {
        method: "OPTIONS",
        safe: true,
        idempotent: true,
        cacheable: false,
        has_body: false,
        description: "Describes the communication options for the target resource.",
        typical_use: "CORS preflight requests, discovering allowed methods.",
    },
    MethodEntry {
        method: "CONNECT",
        safe: false,
        idempotent: false,
        cacheable: false,
        has_body: false,
        description: "Establishes a tunnel to the server (used with TLS/HTTPS proxies).",
        typical_use: "Proxying encrypted connections through an intermediary.",
    },
    MethodEntry {
        method: "TRACE",
        safe: true,
        idempotent: true,
        cacheable: false,
        has_body: false,
        description: "Performs a message loop-back test along the path to the target (debugging only).",
        typical_use: "Diagnosing request transformations by intermediaries.",
    },
];

/// Filter options. Each boolean is `Option<bool>` so callers can distinguish
/// "constrain to `false`" (`Some(false)`) from "no constraint" (`None`) — a
/// tri-state a bare `bool` cannot express.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct MethodFilter {
    pub safe: Option<bool>,
    pub idempotent: Option<bool>,
    pub cacheable: Option<bool>,
    /// Free text matched case-insensitively against method, description, and
    /// typical_use. Ignored when empty after trimming.
    pub query: Option<String>,
}

/// Case-insensitive single-method lookup.
///
/// Returns a static borrow of the canonical entry, or `None` when unknown —
/// the Rust analogue of TS's `MethodEntry | null`.
pub fn get_method(name: &str) -> Option<&'static MethodEntry> {
    // ASCII method names: `to_ascii_uppercase` matches TS `toUpperCase` for
    // the alphabetic method tokens without paying for full Unicode case-folding.
    let n = name.trim().to_ascii_uppercase();
    METHODS.iter().find(|m| m.method == n)
}

/// Returns the methods satisfying every present flag and, when `query` is
/// non-empty, matching it in at least one of {method, description, typical_use}.
///
/// Borrows from [`METHODS`] — no allocation of the records themselves, only
/// of the returned `Vec` of references.
pub fn filter_methods(opts: &MethodFilter) -> Vec<&'static MethodEntry> {
    let q = opts
        .query
        .as_deref()
        .map(|q| q.trim().to_ascii_lowercase())
        .unwrap_or_default();

    METHODS
        .iter()
        .filter(|m| {
            // Each present flag acts as an AND constraint; `None` means skip.
            if let Some(want) = opts.safe {
                if m.safe != want {
                    return false;
                }
            }
            if let Some(want) = opts.idempotent {
                if m.idempotent != want {
                    return false;
                }
            }
            if let Some(want) = opts.cacheable {
                if m.cacheable != want {
                    return false;
                }
            }

            if q.is_empty() {
                return true;
            }
            m.method.to_ascii_lowercase().contains(&q)
                || m.description.to_ascii_lowercase().contains(&q)
                || m.typical_use.to_ascii_lowercase().contains(&q)
        })
        .collect()
}

/// Semantic diff between two methods.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MethodComparison {
    /// Both methods share the `safe` flag.
    pub same_safety: bool,
    /// Both methods share the `idempotent` flag.
    pub same_idempotence: bool,
    /// One sentence per mismatched property (safe, idempotent, cacheable, has_body).
    pub differences: Vec<String>,
}

/// Surfaces where two methods' semantics agree and differ.
///
/// `differences` lists every mismatched property as a human-readable sentence,
/// reproducing the canonical phrasing verbatim so output stays identical to
/// the TypeScript original and the other polyglot ports.
pub fn compare_methods(a: &MethodEntry, b: &MethodEntry) -> MethodComparison {
    let mut differences = Vec::new();

    if a.safe != b.safe {
        differences.push(format!(
            "{} is {}, {} is {}.",
            a.method,
            safe_word(a.safe),
            b.method,
            safe_word(b.safe),
        ));
    }
    if a.idempotent != b.idempotent {
        differences.push(format!(
            "{} is {}, {} is {}.",
            a.method,
            idempotent_word(a.idempotent),
            b.method,
            idempotent_word(b.idempotent),
        ));
    }
    if a.cacheable != b.cacheable {
        differences.push(format!(
            "{} is {}, {} is {}.",
            a.method,
            cacheable_word(a.cacheable),
            b.method,
            cacheable_word(b.cacheable),
        ));
    }
    if a.has_body != b.has_body {
        differences.push(format!(
            "{} {}, {} {}.",
            a.method,
            body_word(a.has_body),
            b.method,
            body_word(b.has_body),
        ));
    }

    MethodComparison {
        same_safety: a.safe == b.safe,
        same_idempotence: a.idempotent == b.idempotent,
        differences,
    }
}

// Phrasing helpers keep the difference-sentence wording in one place, so the
// output stays in lock-step across every polyglot port.
fn safe_word(v: bool) -> &'static str {
    if v { "safe" } else { "not safe" }
}

fn idempotent_word(v: bool) -> &'static str {
    if v { "idempotent" } else { "not idempotent" }
}

fn cacheable_word(v: bool) -> &'static str {
    if v { "cacheable" } else { "not cacheable" }
}

fn body_word(v: bool) -> &'static str {
    if v { "takes a body" } else { "does not take a body" }
}

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 →