fix(rust): interpolate unknown path parameters without their JSON quotes - #17661
fix(rust): interpolate unknown path parameters without their JSON quotes#17661wiebren wants to merge 1 commit into
Conversation
An `unknown`-typed path parameter is generated as `&serde_json::Value` and was interpolated into the path with `Display`, which prints JSON. A string value keeps its quotes, so every call went to `/resources/%22abc%22` instead of `/resources/abc`. OpenAPI documents commonly hit this: a path parameter whose schema carries constraints (`pattern`, `minLength`) but no `type` imports as `unknown`, and every path-parameterized call in the generated SDK 404s. Use the string content when the value is a string and fall back to the JSON encoding otherwise (numbers and booleans print bare, which is what a path expects). Adds the rust-unknown-path-parameter seed fixture (language-prefixed) covering an endpoint with an unknown path parameter. Verified against a live socket: the request line was `GET /resources/%22abc%22` before and is `GET /resources/abc` after. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CxDNCjqJycKTfzVWg2SeTJ
There was a problem hiding this comment.
AI Review Summary
Single-line generator fix that unwraps serde_json::Value strings before interpolating them into paths, plus a new seed fixture. The approach is sound; the main gap is that path parameters are still not URL-encoded (a value containing / or ? still escapes the path segment), but that's pre-existing behavior beyond this diff. No blocking issues found.
- 🔵 1 suggestion(s)
To request another review, comment /ai-review on this pull request.
| unknown: () => | ||
| `${paramName}.as_str().map(ToString::to_string).unwrap_or_else(|| ${paramName}.to_string())`, |
There was a problem hiding this comment.
🔵 suggestion
as_str().map(ToString::to_string) allocates twice for the string case (&str -> String). Minor, but map(str::to_owned) is the same length and one allocation. Also worth noting: like every other path param here, the result is still not percent-encoded, so a value containing / or ? will break out of the segment — pre-existing, but this change makes string values reachable where they previously produced quoted-and-encoded garbage.
There was a problem hiding this comment.
Devin Review found 1 potential issue.
1 flag not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)
| unknown: () => | ||
| `${paramName}.as_str().map(ToString::to_string).unwrap_or_else(|| ${paramName}.to_string())`, |
There was a problem hiding this comment.
🔴 Unknown aliases break generated SDK builds
When a path parameter aliases unknown, getPathParameterExpression bypasses the new conversion and passes the alias to format!. Generated aliases lack Display, so the entire SDK fails to compile.
Prompt for agents
Extend path-parameter serialization in generators/rust/sdk/src/generators/SubClientGenerator.ts so named aliases resolve recursively before choosing the expression. An alias whose eventual target is unknown must serialize its .0 serde_json::Value like a direct unknown value. Preserve primitive-alias handling and account for alias chains. Add a fixture endpoint using an alias of unknown as a path parameter and verify the generated Rust crate compiles and removes JSON quotes from string values.
Was this helpful? React with 👍 or 👎 to provide feedback.
Description
Linear ticket: n/a — found while running one OpenAPI document through fern's SDK generators
and comparing what each one produces.
An
unknown-typed path parameter is generated as&serde_json::Valueand interpolated intothe path with
Display— which prints JSON. A string value keeps its quotes, so the quotestravel into the URL and every call to the endpoint fails:
OpenAPI documents commonly hit this: a path parameter whose schema carries constraints but no
type—— imports as
unknown. Other generators shrug this off because theirunknownis thelanguage's plain value (
unknownin typescript,Anyin python) and interpolating theruntime string produces the string; rust's
serde_json::Valueis the one representationwhose
Displayre-encodes to JSON.Root cause
getPathParameterExpressioningenerators/rust/sdk/src/generators/SubClientGenerator.tsreturns the parameter name unchanged for the
unknowntype reference, soformat!("{}", value)uses
serde_json::Value's JSONDisplay.Changes Made
unknownpath parameter, interpolatevalue.as_str().map(ToString::to_string).unwrap_or_else(|| value.to_string()): the stringcontent when the value is a string, the JSON encoding otherwise (numbers and booleans print
bare, which is what a path expects).
rust-unknown-path-parametertest definition (language-prefixed, so only the rustgenerators run it): an endpoint with an
unknownpath parameter.Testing
client.get(&serde_json::json!("abc"), None)and capturing the request line:GET /resources/%22abc%22 HTTP/1.1GET /resources/abc HTTP/1.1cargo build+cargo testpass on the new fixture (86 tests).pnpm seed test --generator rust-sdkon path-parameterized fixtures (path-parameters,imdb) — no output changes; no committed fixture has anunknownpath parameter, so onlythe new fixture's output is added.
pnpm turbo run test --filter @fern-api/rust-sdk— all unit tests pass.Generated with Claude Code