Skip to content

feat: implement the URL search params serialization standard - #597

Open
razor-x wants to merge 3 commits into
mainfrom
claude/python-sdk-ts-url-serializer-xukp7s
Open

feat: implement the URL search params serialization standard#597
razor-x wants to merge 3 commits into
mainfrom
claude/python-sdk-ts-url-serializer-xukp7s

Conversation

@razor-x

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

Copy link
Copy Markdown
Member

Port @seamapi/url-search-params-serializer to Python so the SDK can
serialize objects to URL search params for HTTP GET requests.

Output is byte-for-byte identical to the reference implementation:

  • Values are encoded with the application/x-www-form-urlencoded
    serializer, which differs from urllib in its treatment of "*" and "~".
  • Params are sorted by name, compared by UTF-16 code unit.
  • Floats are formatted using the ECMAScript Number::toString algorithm,
    which differs from repr for integral floats and around the exponent
    notation thresholds.

Python has no undefined, so UNDEFINED is provided as the sentinel for a
removed param, while None serializes to an empty value as null does.
Temporal.Instant and Date both map to datetime, where a naive datetime is
interpreted as UTC and microseconds are truncated to millisecond
precision.

Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01PpqwDhZmyikGbjmCPqFW2A

claude added 2 commits August 5, 2026 16:22
Port @seamapi/url-search-params-serializer to Python so the SDK can
serialize objects to URL search params for HTTP GET requests.

Output is byte-for-byte identical to the reference implementation:

- Values are encoded with the application/x-www-form-urlencoded
  serializer, which differs from urllib in its treatment of "*" and "~".
- Params are sorted by name, compared by UTF-16 code unit.
- Floats are formatted using the ECMAScript Number::toString algorithm,
  which differs from repr for integral floats and around the exponent
  notation thresholds.

Python has no undefined, so UNDEFINED is provided as the sentinel for a
removed param, while None serializes to an empty value as null does.
Temporal.Instant and Date both map to datetime, where a naive datetime is
interpreted as UTC and microseconds are truncated to millisecond
precision.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PpqwDhZmyikGbjmCPqFW2A
The Seam API distinguishes an omitted param from a param explicitly set to
null: in an update request, an omitted param leaves the current value
unchanged while a null param unsets it, and some endpoints accept null as a
meaningful filter value. Python has a single absence value, so route methods
omitted both cases and there was no way to send null. For example,
access_grants.list documents null as a filter for Access Grants without an
access_grant_key, but passing None dropped the filter and returned every
Access Grant.

Add the NULL sentinel for a param explicitly set to null. Since sending null
is rarely intended and unsetting a value cannot be undone, None keeps meaning
the safe option of omitting the param, so this adds the capability without
changing the behavior of any existing call.

The existing generated route methods need no change: they already omit params
set to None, and the client now replaces any remaining NULL sentinel with None
so that json serializes it to null. NULL works at any depth, e.g., to clear a
single key of an object param.

Bind the URL search params serializer to the same convention, replacing its
UNDEFINED sentinel: None is JavaScript undefined and is removed, while NULL is
JavaScript null and serializes to an empty value.

NULL is typed as Any so it may be passed to any param without a type error.
Once blueprint exposes isNullable on Parameter, codegen can type nullable
params precisely instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PpqwDhZmyikGbjmCPqFW2A
@razor-x
razor-x requested a review from a team as a code owner August 5, 2026 18:07
Blueprint now reports isNullable for request parameters, so codegen can
distinguish the params the Seam API documents as nullable from the rest.
Type a nullable param as Union[T, Null] so it accepts the NULL sentinel, and
leave every other param as it was.

This makes NULL checkable. Previously NULL had to be typed as Any to be
passed anywhere, which meant a type checker could not report sending null to
a param that does not accept it. NULL is now typed as Null, so passing it to
a non-nullable param such as devices.update(is_managed=...) is an error while
access_grants.list(access_grant_key=NULL) is accepted.

Reading isNullable requires blueprint 1.4.0 or later, which turns an
untyped property from a warning into an error. The pinned types release
leaves submit_args untyped for /seam/connect_webview/v1/submit, so generation
fails against it; bump types to the next release, which defines that type and
adds the between parameter to events.list.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PpqwDhZmyikGbjmCPqFW2A
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.

2 participants