Skip to content

Support repeated and ordered query and form parameters #119

Description

@ZilvinasKucinskas

Priority: P1

Describe the issue

The query: and URL-encoded form: options currently accept only a map whose values are scalar booleans, platform-sized integers, floats, or strings. They reject both common Ruby representations of repeated fields:

  • a hash with an array value; and
  • an enumerable of key-value pairs.

Repeated keys are ordinary HTTP API input (tag=a&tag=b, facets, filters, and multi-select fields). An ordered pair list is also needed when duplicate keys or exact field order must be preserved.

Reproduction

Tested with wreq 1.2.4:

require "wreq"

client = Wreq::Client.new

client.get("https://example.com", query: {tag: %w[ruby http]})
# RuntimeError: data did not match any variant of untagged enum ParamValue

client.get(
  "https://example.com",
  query: [["tag", "ruby"], ["tag", "http"]]
)
# TypeError: expected a map, got sequence

client.get("https://example.com", query: {id: 2**63})
# RangeError: bignum too big to convert into `long long'

The equivalent shapes fail for form: as well.

Proposed Ruby API

Keep query: and form: for compatibility, but accept the same two shapes as Ruby's URL-encoding APIs:

client.get(
  "https://example.com/search",
  query: {tag: %w[ruby http], page: 2}
)
# GET /search?tag=ruby&tag=http&page=2

client.post(
  "https://example.com/search",
  form: [
    [:tag, "ruby"],
    [:tag, "http"],
    [:page, 2]
  ]
)
# body: tag=ruby&tag=http&page=2

Encoding semantics

  • Hash array values expand to one field per element.
  • Enumerable pairs preserve input order and duplicate keys.
  • String and Symbol keys are accepted and encoded by their string value.
  • Scalar String, Symbol, Integer, Float, boolean, and nil values follow documented URI.encode_www_form-compatible conversion. Ruby Integers are stringified without narrowing to the native platform integer range.
  • Invalid pair shapes raise ArgumentError before network I/O.
  • This issue covers application/x-www-form-urlencoded data only. Multipart file uploads remain tracked by #86.

Acceptance criteria

  • Both options accept a Hash and an enumerable of pairs.
  • Duplicate keys reach the wire without being collapsed.
  • Pair order is stable.
  • Hash array values produce repeated fields.
  • Existing scalar hashes remain backward compatible.
  • Tests cover spaces, Unicode, reserved characters, blank strings, nil, booleans, arbitrary-precision Integers, duplicate keys, array values, and invalid entries for both query and form encoding.

Ruby ecosystem precedent

  • Ruby's URI.encode_www_form accepts any enumerable, accepts hashes, expands array values into repeated keys, and preserves enumerable order.
  • HTTPX::Request accepts hashes or arrays of key-value pairs for query and form parameters.
  • Net::HTTPHeader#set_form accepts hash and pair-list form data.
  • wreq-python accepts mappings or ordered sequences of pairs for query and form input over the same Rust client. Ruby array-value expansion remains a Ruby-specific URI.encode_www_form convention.

Relevant wreq-ruby source

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions