HTTP Methods Reference — Ruby 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 Ruby implementation — the same logic the interactive tool runs, in a shareable, citable form.
# Source: ruby.rb
# Language: Ruby (Ruby 3.2, 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.
# frozen_string_literal: true
module HttpMethods
# One HTTP request method and its semantic properties.
#
# A Struct with keyword_init keeps construction explicit at the call site
# (mirroring the named-argument constructors of the other ports).
MethodEntry = Struct.new(
:method, # Uppercase method name, e.g. "GET".
:safe, # Read-only semantics — no server state change.
:idempotent, # Repeating the call has the same effect as a single call.
:cacheable, # Responses may be stored by a cache (RFC 9110 / MDN).
:has_body, # The method conventionally carries a request body.
:description,
:typical_use,
keyword_init: true
)
# The nine HTTP request methods (RFC 9110 / 9111), in canonical order.
# Frozen so the table is a single immutable source of truth; the helpers
# hand out references into it.
METHODS = [
MethodEntry.new(
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.new(
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.new(
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.new(
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.new(
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.new(
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.new(
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.new(
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.new(
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.'
)
].freeze
# Narrowing options for .filter_methods.
#
# Each boolean is tri-state: nil means "no constraint", true/false
# constrains to that value — a distinction a bare Boolean cannot express.
MethodFilter = Struct.new(
:safe,
:idempotent,
:cacheable,
# Free text matched case-insensitively against method, description,
# and typical_use. Ignored when empty after trimming.
:query,
keyword_init: true
)
# Semantic diff between two methods.
MethodComparison = Struct.new(
:same_safety, # Both methods share the `safe` flag.
:same_idempotence, # Both methods share the `idempotent` flag.
:differences, # One sentence per mismatched property (safe, idempotent, cacheable, has_body).
keyword_init: true
)
module_function
# Case-insensitive single-method lookup.
#
# Returns the entry, or nil when unknown — the Ruby analogue of TS's
# `MethodEntry | null`.
def get_method(name)
n = name.strip.upcase
METHODS.find { |m| m.method == n }
end
# Filter the method set by boolean flags and an optional text query.
#
# A method must satisfy *every* present flag AND, when a query is given,
# match it in at least one of {method, description, typical_use}.
def filter_methods(opts = MethodFilter.new)
q = opts.query.to_s.strip.downcase
METHODS.select do |m|
# Each present flag is an AND constraint; nil means skip.
next false unless opts.safe.nil? || m.safe == opts.safe
next false unless opts.idempotent.nil? || m.idempotent == opts.idempotent
next false unless opts.cacheable.nil? || m.cacheable == opts.cacheable
next true if q.empty?
[m.method, m.description, m.typical_use].any? { |field| field.downcase.include?(q) }
end
end
# Compare two methods, surfacing where their 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 across ports.
def compare_methods(a, b)
differences = []
if a.safe != b.safe
differences << "#{a.method} is #{safe_word(a.safe)}, #{b.method} is #{safe_word(b.safe)}."
end
if a.idempotent != b.idempotent
differences << "#{a.method} is #{idempotent_word(a.idempotent)}, #{b.method} is #{idempotent_word(b.idempotent)}."
end
if a.cacheable != b.cacheable
differences << "#{a.method} is #{cacheable_word(a.cacheable)}, #{b.method} is #{cacheable_word(b.cacheable)}."
end
if a.has_body != b.has_body
differences << "#{a.method} #{body_word(a.has_body)}, #{b.method} #{body_word(b.has_body)}."
end
MethodComparison.new(
same_safety: a.safe == b.safe,
same_idempotence: a.idempotent == b.idempotent,
differences: differences
)
end
# Phrasing helpers keep the difference-sentence wording in one place, so
# the output stays in lock-step across every polyglot port.
def safe_word(value) = value ? 'safe' : 'not safe'
def idempotent_word(value) = value ? 'idempotent' : 'not idempotent'
def cacheable_word(value) = value ? 'cacheable' : 'not cacheable'
def body_word(value) = value ? 'takes a body' : 'does not take a body'
end
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 →