Skip to content

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

// Source: kotlin.kt
// Language: Kotlin (Kotlin 1.9, 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.

package cosmodev.httpmethods

/**
 * One HTTP request method and its semantic properties.
 */
data class MethodEntry(
    val method: String,       // Uppercase method name, e.g. "GET".
    val safe: Boolean,        // Read-only semantics — no server state change.
    val idempotent: Boolean,  // Repeating the call has the same effect as a single call.
    val cacheable: Boolean,   // Responses may be stored by a cache (RFC 9110 / MDN).
    val hasBody: Boolean,     // The method conventionally carries a request body.
    val description: String,
    val typicalUse: String,
)

/**
 * The nine HTTP request methods (RFC 9110 / 9111), in canonical order.
 *
 * An immutable [List] — the single source of truth the helpers hand out
 * references into.
 */
val METHODS: List<MethodEntry> = listOf(
    MethodEntry(
        method = "GET",
        safe = true,
        idempotent = true,
        cacheable = true,
        hasBody = false,
        description = "Retrieves a representation of the target resource; a read-only request.",
        typicalUse = "Fetching a web page, reading an API resource, loading an image.",
    ),
    MethodEntry(
        method = "POST",
        safe = false,
        idempotent = false,
        cacheable = true,
        hasBody = true,
        description = "Submits data to be processed, typically creating a new resource or triggering an action.",
        typicalUse = "Submitting a form, creating a record, publishing a message.",
    ),
    MethodEntry(
        method = "PUT",
        safe = false,
        idempotent = true,
        cacheable = false,
        hasBody = true,
        description = "Replaces the target resource entirely with the request body.",
        typicalUse = "Updating a full record at a known URL, uploading a file by its path.",
    ),
    MethodEntry(
        method = "PATCH",
        safe = false,
        idempotent = false,
        cacheable = false,
        hasBody = true,
        description = "Applies a partial modification to the target resource.",
        typicalUse = "Updating one field of a record, toggling a flag.",
    ),
    MethodEntry(
        method = "DELETE",
        safe = false,
        idempotent = true,
        cacheable = false,
        hasBody = false,
        description = "Removes the target resource.",
        typicalUse = "Deleting a record or file by its URL.",
    ),
    MethodEntry(
        method = "HEAD",
        safe = true,
        idempotent = true,
        cacheable = true,
        hasBody = false,
        description = "Identical to GET but returns only the response headers, no body.",
        typicalUse = "Checking existence, size, or freshness before downloading.",
    ),
    MethodEntry(
        method = "OPTIONS",
        safe = true,
        idempotent = true,
        cacheable = false,
        hasBody = false,
        description = "Describes the communication options for the target resource.",
        typicalUse = "CORS preflight requests, discovering allowed methods.",
    ),
    MethodEntry(
        method = "CONNECT",
        safe = false,
        idempotent = false,
        cacheable = false,
        hasBody = false,
        description = "Establishes a tunnel to the server (used with TLS/HTTPS proxies).",
        typicalUse = "Proxying encrypted connections through an intermediary.",
    ),
    MethodEntry(
        method = "TRACE",
        safe = true,
        idempotent = true,
        cacheable = false,
        hasBody = false,
        description = "Performs a message loop-back test along the path to the target (debugging only).",
        typicalUse = "Diagnosing request transformations by intermediaries.",
    ),
)

/**
 * Narrowing options for [filterMethods].
 *
 * Each boolean is `Boolean?` so callers can distinguish "constrain to
 * `false`" from "no constraint" — a tri-state a bare [Boolean] cannot
 * express. `null` (the default) means *no constraint*.
 */
data class MethodFilter(
    val safe: Boolean? = null,
    val idempotent: Boolean? = null,
    val cacheable: Boolean? = null,
    // Free text matched case-insensitively against method, description,
    // and typicalUse. Ignored when empty after trimming.
    val query: String? = null,
)

/**
 * Semantic diff between two methods.
 */
data class MethodComparison(
    val sameSafety: Boolean,       // Both methods share the `safe` flag.
    val sameIdempotence: Boolean,  // Both methods share the `idempotent` flag.
    // One sentence per mismatched property (safe, idempotent, cacheable, hasBody).
    val differences: List<String>,
)

/**
 * Case-insensitive single-method lookup.
 *
 * Returns the entry, or `null` when unknown — the Kotlin analogue of TS's
 * `MethodEntry | null`.
 */
fun getMethod(name: String): MethodEntry? {
    // ASCII method names: uppercase() is locale-invariant and matches the
    // TypeScript original for the alphabetic tokens.
    val n = name.trim().uppercase()
    return METHODS.firstOrNull { it.method == n }
}

/**
 * Filter the method set by boolean flags and an optional text query.
 *
 * A method must satisfy *every* present flag AND, when [MethodFilter.query]
 * is non-empty after trimming, match it in at least one of
 * {method, description, typicalUse}.
 */
fun filterMethods(opts: MethodFilter = MethodFilter()): List<MethodEntry> {
    val q = opts.query?.trim()?.lowercase().orEmpty()

    return METHODS.filter { m ->
        // Each present flag is an AND constraint; null means skip.
        (opts.safe == null || m.safe == opts.safe) &&
            (opts.idempotent == null || m.idempotent == opts.idempotent) &&
            (opts.cacheable == null || m.cacheable == opts.cacheable) &&
            (
                q.isEmpty() ||
                    m.method.lowercase().contains(q) ||
                    m.description.lowercase().contains(q) ||
                    m.typicalUse.lowercase().contains(q)
                )
    }
}

/**
 * Compare two methods, surfacing where their semantics agree and differ.
 *
 * [MethodComparison.differences] lists every mismatched property (safe,
 * idempotent, cacheable, hasBody) as a human-readable sentence, reproducing
 * the canonical phrasing verbatim so output stays identical across ports.
 */
fun compareMethods(a: MethodEntry, b: MethodEntry): MethodComparison {
    val differences = buildList {
        if (a.safe != b.safe) {
            add("${a.method} is ${safeWord(a.safe)}, ${b.method} is ${safeWord(b.safe)}.")
        }
        if (a.idempotent != b.idempotent) {
            add("${a.method} is ${idempotentWord(a.idempotent)}, ${b.method} is ${idempotentWord(b.idempotent)}.")
        }
        if (a.cacheable != b.cacheable) {
            add("${a.method} is ${cacheableWord(a.cacheable)}, ${b.method} is ${cacheableWord(b.cacheable)}.")
        }
        if (a.hasBody != b.hasBody) {
            add("${a.method} ${bodyWord(a.hasBody)}, ${b.method} ${bodyWord(b.hasBody)}.")
        }
    }

    return MethodComparison(
        sameSafety = a.safe == b.safe,
        sameIdempotence = a.idempotent == b.idempotent,
        differences = differences,
    )
}

// Phrasing helpers keep the difference-sentence wording in one place, so the
// output stays in lock-step across every polyglot port.
private fun safeWord(value: Boolean): String = if (value) "safe" else "not safe"

private fun idempotentWord(value: Boolean): String = if (value) "idempotent" else "not idempotent"

private fun cacheableWord(value: Boolean): String = if (value) "cacheable" else "not cacheable"

private fun bodyWord(value: Boolean): String = if (value) "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 →