Skip to content

feat: Add _strict=true to url_search_params_serializer - #617

Merged
razor-x merged 1 commit into
mainfrom
strict-serialize
Aug 14, 2026
Merged

feat: Add _strict=true to url_search_params_serializer#617
razor-x merged 1 commit into
mainfrom
strict-serialize

Conversation

@razor-x

@razor-x razor-x commented Aug 14, 2026

Copy link
Copy Markdown
Member

No description provided.

@razor-x
razor-x requested a review from a team as a code owner August 14, 2026 03:28
@razor-x
razor-x merged commit ac53350 into main Aug 14, 2026
23 checks passed
@razor-x
razor-x deleted the strict-serialize branch August 14, 2026 04:18
razor-x pushed a commit to seamapi/php that referenced this pull request Aug 14, 2026
Mirror seamapi/python#617: serialize() and update() take a strict flag
that appends _strict=true to any non-empty query, telling the Seam API
to use strict, schema-aware parsing. The flag is appended after the
sort so it always sits last, a caller-supplied _strict param is
replaced rather than repeated, and a query with no serializable params
stays empty. The SDK client always serializes in strict mode.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HMKbYgbsoFdKiiaxXB6jh2
razor-x pushed a commit to seamapi/ruby that referenced this pull request Aug 14, 2026
Match seamapi/python#617: the SDK serializes query params with strict
mode enabled, appending _strict=true after the sorted pairs of any
non-empty query so the Seam API uses strict, schema-aware parsing. The
strict entry points live in strict_url_search_params_serializer so the
base serializer stays a faithful port of the standard, and a query
built entirely by the caller still passes through without it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017p9TwdqYv9ccnv7nGvpfsp
razor-x pushed a commit to seamapi/php that referenced this pull request Aug 14, 2026
Mirror seamapi/python#617: the new StrictUrlSearchParamsSerializer
wraps the base serializer and appends _strict=true to any non-empty
query, telling the Seam API to use strict, schema-aware parsing. The
flag is appended after the sort so it always sits last, a
caller-supplied _strict param is replaced rather than repeated, and a
query with no serializable params stays empty.

The flag is Seam API behavior, not part of the serialization standard,
so it is isolated in the wrapper and the base UrlSearchParamsSerializer
stays a pure implementation of the standard. The SDK client serializes
every request with the strict wrapper.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HMKbYgbsoFdKiiaxXB6jh2
razor-x added a commit to seamapi/ruby that referenced this pull request Aug 14, 2026
* feat: Add URL search params serializer

Port @seamapi/url-search-params-serializer to Ruby: a UrlSearchParams
pair collection with WHATWG form encoding and UTF-16 code unit sort, a
serializer with ECMAScript number formatting and JavaScript toISOString
date formatting, and the Seam::NULL sentinel distinguishing an explicit
JSON null from an omitted parameter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017p9TwdqYv9ccnv7nGvpfsp

* feat: Serialize request params with the URL search params serializer

Query params are built by a Faraday params encoder that applies the
serializer, so requests carry the exact encoding, ordering, and number
formatting the Seam API parses; Faraday's default encoder dropped the
'=' from empty-array params, silently turning an empty filter into no
filter. Request bodies replace the Seam::NULL sentinel with nil before
JSON encoding, and generated methods now document nullable parameters
with Seam::Null in their types, consuming the blueprint isNullable flag.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017p9TwdqYv9ccnv7nGvpfsp

* test: Add URL search params conformance harness

Verify the Ruby serializer byte for byte against the TypeScript
reference implementation over hand-built, structural-fuzz, and
float-fuzz fixtures, and round-trip the output through
@seamapi/url-search-params-parser in strict mode. The harness needs
Node and the reference implementation, so it lives in dev/conformance
outside the shipped gem.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017p9TwdqYv9ccnv7nGvpfsp

* chore: Remove the URL search params conformance harness

The serializer standard is stable, so the Node-based comparison against
the TypeScript reference and its devDependencies are not worth carrying.
The RSpec suite covers the spec directly, including the exact ECMAScript
exponent formatting and multi-byte encoding cases the harness verified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017p9TwdqYv9ccnv7nGvpfsp

* feat: Add _strict=true to url_search_params_serializer

Match seamapi/python#617: the SDK serializes query params with strict
mode enabled, appending _strict=true after the sorted pairs of any
non-empty query so the Seam API uses strict, schema-aware parsing. The
strict entry points live in strict_url_search_params_serializer so the
base serializer stays a faithful port of the standard, and a query
built entirely by the caller still passes through without it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017p9TwdqYv9ccnv7nGvpfsp

* chore: Trim comments to constraints the code cannot show

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017p9TwdqYv9ccnv7nGvpfsp

* chore: Delete comments that restate tested behavior

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017p9TwdqYv9ccnv7nGvpfsp

* docs: Match the URL search params section to the other SDKs

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017p9TwdqYv9ccnv7nGvpfsp

* Move UrlSearchParamsEncoder down

---------

Co-authored-by: Claude <noreply@anthropic.com>
razor-x added a commit to seamapi/php that referenced this pull request Aug 14, 2026
* feat: implement the URL search params serialization standard

Port @seamapi/url-search-params-serializer to PHP as
Seam\UrlSearchParamsSerializer over a Seam\UrlSearchParams pair
collection, byte-for-byte identical to the TypeScript reference
implementation. The unit test suite mirrors the reference and Python
SDK suites, covering every branch of the standard.

PHP's own primitives each diverge from the standard, so the port
implements them directly: urlencode() is RFC 3986 flavored (escapes *,
keeps ~) where the WHATWG form encoding does the opposite; float
casts render 1.0, switch to exponents at the wrong thresholds, and
spell them E+21, so floats follow the ECMAScript Number::toString
algorithm; sorting compares UTF-16 code units, not UTF-8 bytes; and
dates always carry exactly three fractional digits and a literal Z.

PHP has a single absence value, so the Seam\NullValue enum adds the
explicit null sentinel: null means the safe option of omitting a
param, and sending null is always spelled NullValue::NULL.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HMKbYgbsoFdKiiaxXB6jh2

* feat: apply the URL search params standard and type nullable params

Wrap the Guzzle client in Seam\Http\SerializingClient so every request
follows the serialization standard. Query params given as a map are
serialized with UrlSearchParamsSerializer and handed to Guzzle as a raw
query string, since Guzzle's own encoder escapes *, keeps ~, and drops
an empty array entirely instead of sending name= (which the API reads
as the empty array rather than an unfiltered request). NullValue::NULL
sentinels in JSON bodies become JSON null, so the sentinel works on
both transports. A query already given as a string passes through
untouched, and nothing serialized means no query at all rather than a
bare trailing ?.

Consume the blueprint's isNullable flag in the codegen: a nullable
param is typed string|NullValue|null and accepts the sentinel, while a
merely optional one keeps ?string and rejects it, so the type system
catches sending an accidental null where it would unset a value.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HMKbYgbsoFdKiiaxXB6jh2

* feat: add _strict=true to the URL search params serializer

Mirror seamapi/python#617: the new StrictUrlSearchParamsSerializer
wraps the base serializer and appends _strict=true to any non-empty
query, telling the Seam API to use strict, schema-aware parsing. The
flag is appended after the sort so it always sits last, a
caller-supplied _strict param is replaced rather than repeated, and a
query with no serializable params stays empty.

The flag is Seam API behavior, not part of the serialization standard,
so it is isolated in the wrapper and the base UrlSearchParamsSerializer
stays a pure implementation of the standard. The SDK client serializes
every request with the strict wrapper.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HMKbYgbsoFdKiiaxXB6jh2

* refactor: drop comments that narrate instead of constrain

Keep a comment only when it says something the code cannot: a
non-obvious why, an external constraint, or an invariant a future edit
would break. Comments that narrate a test, restate an assertion, or
argue the code is correct are deleted; the tests are the explanation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HMKbYgbsoFdKiiaxXB6jh2

* docs: align the README sections with the other SDKs

Setting a param to null becomes a top-level usage section and
Serializing URL search params follows the structure of the Python and
Ruby READMEs, including the note explaining why PHP spells the
sentinel NullValue::NULL where the other SDKs spell it NULL with type
Null: both names are reserved in PHP, so the type and the value live
on one enum.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HMKbYgbsoFdKiiaxXB6jh2

* refactor: sort search params by stable byte order

Drop the UTF-16 sort key: a stable sort is what the standard needs to
keep array element order, and byte order matches URLSearchParams.sort()
for every ASCII name, which all Seam param names are. Only a name
beyond the Basic Multilingual Plane could order differently than the
reference implementation, and then only against a name in U+E000 to
U+FFFF.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HMKbYgbsoFdKiiaxXB6jh2

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant