Skip to content

HTTP Status Codes — Ruby source

Searchable reference of all HTTP status codes with meaning, category, and usage notes.

This is the Ruby implementation — the same logic the interactive tool runs, in a shareable, citable form.

# HTTP Status Codes reference — pure, deterministic data + filter.
#
# Language: Ruby 3.2 — standard library only, no third-party gems.
# Source: CosmoDev polyglot showcase port of http-status-codes,
#         ported from src/lib/httpStatus.ts.
# License: display source — part of CosmoDev's polyglot tool pages.
#
# Pure logic — no I/O. Behavior matches the TypeScript lib: same inputs
# produce identical outputs.

# frozen_string_literal: true

module HttpStatusCodes
  # The five broad families an HTTP status code can belong to.
  #
  # Ruby has no enum construct, so the family is a Symbol (:informational ..
  # :server_error) and this frozen map carries the canonical display string
  # used across HTTP tooling — the category can be resolved from free text by
  # inverting the map.
  CATEGORIES = {
    informational: 'Informational',
    success: 'Success',
    redirection: 'Redirection',
    client_error: 'Client Error',
    server_error: 'Server Error'
  }.freeze

  # Resolve a category Symbol from its display name, or nil when the name is
  # unknown. The filter turns nil into an empty result, exactly as the
  # TypeScript version does.
  def self.category_from_name(name)
    CATEGORIES.key(name)
  end

  # A single HTTP status code entry.
  #
  # Data (Ruby 3.2) — the immutable counterpart of Struct, mirroring the
  # frozen dataclass of the Python port: instances cannot be mutated, so the
  # table is safe to share as constant reference data.
  StatusCode = Data.define(:code, :reason, :category, :description)

  # Standard + widely-implemented HTTP status codes across 1xx-5xx.
  #
  # A frozen Array of immutable Data instances — the whole table is constant.
  # Order is grouped by category, ascending within each group.
  STATUS_CODES = [
    # --- 1xx Informational ---
    StatusCode.new(100, 'Continue', :informational, 'The server has received the request headers and the client should proceed to send the request body.'),
    StatusCode.new(101, 'Switching Protocols', :informational, 'The requester has asked the server to switch protocols and the server has agreed to do so.'),
    StatusCode.new(103, 'Early Hints', :informational, 'Used to return some response headers before the final HTTP message so the browser can start preloading resources.'),

    # --- 2xx Success ---
    StatusCode.new(200, 'OK', :success, 'Standard response for a successful HTTP request.'),
    StatusCode.new(201, 'Created', :success, 'The request succeeded and a new resource was created.'),
    StatusCode.new(202, 'Accepted', :success, 'The request has been accepted for processing but is not yet complete.'),
    StatusCode.new(203, 'Non-Authoritative Information', :success, 'The returned metadata originated from a local or third-party copy rather than the origin server.'),
    StatusCode.new(204, 'No Content', :success, 'The server processed the request successfully but is not returning any content.'),
    StatusCode.new(205, 'Reset Content', :success, 'The server asks the client to reset the document view that sent the request.'),
    StatusCode.new(206, 'Partial Content', :success, 'The server is delivering only part of the resource because the client requested a byte range.'),
    StatusCode.new(207, 'Multi-Status', :success, 'WebDAV: conveys information about multiple resources in a single XML response.'),
    StatusCode.new(208, 'Already Reported', :success, 'WebDAV: the members of a DAV binding have already been enumerated in a previous reply.'),
    StatusCode.new(226, 'IM Used', :success, 'The server fulfilled a GET request using an instance-manipulation applied to the current instance.'),

    # --- 3xx Redirection ---
    StatusCode.new(300, 'Multiple Choices', :redirection, 'The request has more than one possible response; the user agent can choose among them.'),
    StatusCode.new(301, 'Moved Permanently', :redirection, 'This and all future requests should be directed to the given URL.'),
    StatusCode.new(302, 'Found', :redirection, 'The resource resides temporarily under a different URL; the method may be changed to GET.'),
    StatusCode.new(303, 'See Other', :redirection, 'The response to the request can be found under another URI using a GET request.'),
    StatusCode.new(304, 'Not Modified', :redirection, 'The resource has not been modified since the version specified by the request headers.'),
    StatusCode.new(305, 'Use Proxy', :redirection, 'The requested resource is available only through a proxy (deprecated).'),
    StatusCode.new(306, 'Switch Proxy', :redirection, 'No longer used; originally meant subsequent requests should use a specified proxy.'),
    StatusCode.new(307, 'Temporary Redirect', :redirection, 'The request should be repeated with another URL; the request method must not change.'),
    StatusCode.new(308, 'Permanent Redirect', :redirection, 'This and all future requests should use another URL; the request method must not change.'),

    # --- 4xx Client Error ---
    StatusCode.new(400, 'Bad Request', :client_error, 'The server cannot process the request due to a client error such as malformed syntax.'),
    StatusCode.new(401, 'Unauthorized', :client_error, 'Authentication is required and has either failed or not been provided.'),
    StatusCode.new(402, 'Payment Required', :client_error, 'Reserved for future use; sometimes used for paywalled resources.'),
    StatusCode.new(403, 'Forbidden', :client_error, 'The server understood the request but refuses to authorize it.'),
    StatusCode.new(404, 'Not Found', :client_error, 'The requested resource could not be found on the server.'),
    StatusCode.new(405, 'Method Not Allowed', :client_error, 'The request method is not supported for the requested resource.'),
    StatusCode.new(406, 'Not Acceptable', :client_error, 'The requested resource can only generate content not acceptable per the Accept headers.'),
    StatusCode.new(407, 'Proxy Authentication Required', :client_error, 'The client must first authenticate itself with the proxy.'),
    StatusCode.new(408, 'Request Timeout', :client_error, 'The server timed out waiting for the client to send the request.'),
    StatusCode.new(409, 'Conflict', :client_error, 'The request could not be processed because of a conflict with the current state of the resource.'),
    StatusCode.new(410, 'Gone', :client_error, 'The resource is no longer available and will not be available again.'),
    StatusCode.new(411, 'Length Required', :client_error, 'The request did not specify the length of its content, which is required by the resource.'),
    StatusCode.new(412, 'Precondition Failed', :client_error, 'The server does not meet one of the preconditions given in the request headers.'),
    StatusCode.new(413, 'Content Too Large', :client_error, 'The request payload is larger than the server is willing or able to process.'),
    StatusCode.new(414, 'URI Too Long', :client_error, 'The URI provided was too long for the server to process.'),
    StatusCode.new(415, 'Unsupported Media Type', :client_error, 'The request uses a media type the server does not support for the resource.'),
    StatusCode.new(416, 'Range Not Satisfiable', :client_error, 'The portion of the resource requested in the Range header cannot be supplied by the server.'),
    StatusCode.new(417, 'Expectation Failed', :client_error, 'The server cannot meet the requirements of the Expect request header field.'),
    StatusCode.new(418, "I'm a Teapot", :client_error, 'RFC 2324 joke status: the server refuses to brew coffee because it is, permanently, a teapot.'),
    StatusCode.new(421, 'Misdirected Request', :client_error, 'The request was directed at a server that is not able to produce a response.'),
    StatusCode.new(422, 'Unprocessable Content', :client_error, 'The server understands the content type and syntax but cannot process the contained instructions (WebDAV).'),
    StatusCode.new(423, 'Locked', :client_error, 'WebDAV: the source or destination resource of the method is locked.'),
    StatusCode.new(424, 'Failed Dependency', :client_error, 'WebDAV: the method could not be performed because the requested action depended on another action that failed.'),
    StatusCode.new(425, 'Too Early', :client_error, 'The server is unwilling to risk processing a request that might be a replay.'),
    StatusCode.new(428, 'Precondition Required', :client_error, 'The origin server requires the request to be conditional.'),
    StatusCode.new(429, 'Too Many Requests', :client_error, 'The user has sent too many requests in a given time (rate limiting).'),
    StatusCode.new(431, 'Request Header Fields Too Large', :client_error, 'The server is unwilling to process the request because its header fields are too large.'),
    StatusCode.new(451, 'Unavailable For Legal Reasons', :client_error, 'The resource is unavailable due to legal demands such as government censorship or a takedown.'),

    # --- 5xx Server Error ---
    StatusCode.new(500, 'Internal Server Error', :server_error, 'A generic error message: the server encountered an unexpected condition.'),
    StatusCode.new(501, 'Not Implemented', :server_error, 'The server does not support the functionality required to fulfill the request.'),
    StatusCode.new(502, 'Bad Gateway', :server_error, 'The server, acting as a gateway, received an invalid response from an upstream server.'),
    StatusCode.new(503, 'Service Unavailable', :server_error, 'The server is currently unavailable, typically because it is overloaded or down for maintenance.'),
    StatusCode.new(504, 'Gateway Timeout', :server_error, 'The server, acting as a gateway, timed out waiting for an upstream response.'),
    StatusCode.new(505, 'HTTP Version Not Supported', :server_error, 'The server does not support the HTTP protocol version used in the request.'),
    StatusCode.new(506, 'Variant Also Negotiates', :server_error, 'Transparent content negotiation for the request resulted in a circular reference.'),
    StatusCode.new(507, 'Insufficient Storage', :server_error, 'WebDAV: the server is unable to store the representation needed to complete the request.'),
    StatusCode.new(508, 'Loop Detected', :server_error, 'WebDAV: the server detected an infinite loop while processing the request.'),
    StatusCode.new(510, 'Not Extended', :server_error, 'Further extensions to the request are required for the server to fulfill it.'),
    StatusCode.new(511, 'Network Authentication Required', :server_error, 'The client must authenticate to gain network access, as with a captive portal.')
  ].freeze

  # Filter status codes by a free-text query and an optional category.
  #
  # query     - matched case-insensitively against the numeric code (as a
  #             decimal string), the reason phrase, and the description. An
  #             empty/whitespace query returns every code in the pool.
  # codes     - the pool to filter (defaults to STATUS_CODES).
  # category  - restricts the pool first: nil or blank means "no restriction";
  #             an unknown name yields [] — matching the TypeScript semantics.
  #
  # Returns an Array of matching codes in the original order. String#downcase
  # on ASCII-only text coincides with JavaScript's toLowerCase.
  def self.filter_codes(query, codes: STATUS_CODES, category: nil)
    # Step 1 — build the candidate pool by category. An unknown category
    # matches nothing, so short-circuit to [].
    cat_name = category.to_s.strip
    pool =
      if cat_name.empty?
        codes
      else
        resolved = category_from_name(cat_name)
        return [] if resolved.nil?

        codes.select { |code| code.category == resolved }
      end

    # Step 2 — case-insensitive substring match across code/reason/description.
    needle = query.strip.downcase
    return pool if needle.empty?

    pool.select do |code|
      # The code is matched against its decimal form, so "40" hits 404, 405, ...
      code.code.to_s.include?(needle) ||
        code.reason.downcase.include?(needle) ||
        code.description.downcase.include?(needle)
    end
  end
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 →