Skip to content

fix(apiquery): preserve narrow numeric parameters - #76

Open
sylvesterkaczmarek wants to merge 2 commits into
openai:mainfrom
sylvesterkaczmarek:fix/apiquery-numeric-widths
Open

fix(apiquery): preserve narrow numeric parameters#76
sylvesterkaczmarek wants to merge 2 commits into
openai:mainfrom
sylvesterkaczmarek:fix/apiquery-numeric-widths

Conversation

@sylvesterkaczmarek

Copy link
Copy Markdown

Summary

Preserve narrow Go numeric values when encoding URL query parameters.

Fixes #75.

Problem

internal/apiquery currently has two width-related serialization gaps:

  • int8 and uint8 are not included in the primitive integer cases, so they silently produce no query pair;
  • float32 shares the float64 formatting path and is passed to strconv.FormatFloat with bitSize=64, exposing precision introduced only when reflection widens the value to a Go float64.

A caller can therefore omit a legitimate numeric query parameter entirely, or send a decimal representation different from the source float32 value.

Reproduction

On upstream main at d082a010f7c6cacf407d8a1581446a7857f9f1bb:

values, _ := apiquery.Marshal(map[string]any{"value": int8(-8)})
// values.Encode() == ""

values, _ = apiquery.Marshal(map[string]any{"value": uint8(8)})
// values.Encode() == ""

values, _ = apiquery.Marshal(map[string]any{"value": float32(0.1)})
// values.Get("value") == "0.10000000149011612"

Root cause

The primitive switch omitted the 8-bit integer kinds and grouped both floating-point kinds behind:

strconv.FormatFloat(value.Float(), 'f', -1, 64)

reflect.Value.Float() returns a float64, but FormatFloat's bitSize argument is specifically what tells it whether the original value should be represented with 32-bit or 64-bit precision.

The sibling multipart/form encoder already follows that distinction for primitive values.

Fix

  • include reflect.Int8 with the signed integer kinds;
  • include reflect.Uint8 with the unsigned integer kinds;
  • format reflect.Float32 with bitSize=32;
  • retain bitSize=64 for reflect.Float64.

No query key formatting, array formatting, nesting rules, null handling, or existing wider numeric behavior changes.

Regression coverage

Extended the existing table-driven TestEncode cases with:

  • int8(-8) -> query=-8;
  • uint8(8) -> query=8;
  • float32(0.1) -> query=0.1.

These cases fail on current main for the reasons described above and exercise the real MarshalWithSettings path rather than an isolated helper.

Validation

The branch is based directly on current upstream main and is not behind it. The diff is limited to:

  • 6 additions / 3 deletions in internal/apiquery/encoder.go;
  • 12 lines of focused regression coverage in internal/apiquery/query_test.go.

Full repository validation is left to the repository's GitHub Actions checks.

Risk

Low. The change only fills missing primitive cases and uses the source floating-point width when choosing the standard-library formatting precision. Existing int, wider integer, and float64 output is unchanged.

@sylvesterkaczmarek
sylvesterkaczmarek requested a review from a team as a code owner August 18, 2026 10:48
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.

Query encoder drops int8/uint8 values and widens float32 precision

1 participant