Changelog v3.18.2
Version 3.18.2 (2026-06-26)
Patch release with fixes for proxy endpoints that forward auto-filled parameters (v3.18.1) and the generated TypeScript client, plus a new opt-in option to omit server-filled parameters from generated request shapes. All surfaced by combining a @proxy with an HTTP Custom Type parameter.
What changed
1. Large auto-filled values no longer break the proxy query string
New option ProxyOptions.MaxForwardedQueryParamLength (default 2048). When a server-filled parameter is appended to the proxy upstream query string, a value longer than this limit is now skipped with a warning instead of being percent-encoded into the URL.
Previously, an HTTP Custom Type whose body field held a large payload (e.g. a scraped HTML page) was percent-encoded into the upstream query string, producing an oversized request line that the upstream rejected (HTTP 414 / 431) or that reset the connection. To forward such a value, use a body-carrying proxy method (POST/PUT/PATCH) so it travels in the request body instead. Set the option to 0 to disable the guard.
2. @body_parameter_name reliably matches HTTP Custom Type fields
@body_parameter_name now matches case-insensitively and accepts any of the parameter's names. For an HTTP Custom Type field expanded out of a composite parameter, all of these now resolve to the same field:
- the converted (API) name — e.g.
responseBody - the expanded signature name — e.g.
_response_body(the name shown in the generated signature /.httpfile) - the base composite name — e.g.
_response(shared by all expanded fields; resolves to the first one)
Previously the annotation value was force-lowercased and compared case-sensitively, so the camelCase converted name never matched, and the expanded signature name (_response_body) matched nothing at all — it is stored as neither the actual nor the converted name. This made it impossible to redirect a single expanded HTTP-type field (such as the response body) into the proxy request body.
Body-parameter resolution is now a single shared rule on the core endpoint (RoutineEndpoint.IsBodyParameter) used by request handling and every code generator, so they no longer drift. This also fixes the HTTP file and OpenAPI generators, which previously left a @body_parameter_name field (e.g. responseBody) in the query string / query parameters instead of moving it to the request body.
3. TypeScript client generation for @body_parameter_name
The generated TypeScript client was broken for an endpoint with @body_parameter_name:
- the body expression was emitted as
request.responseBody?— a syntax error (the TS optional?suffix leaked into the runtime property name); - the query-string exclusion key was
["responseBody?"], so the body parameter was not stripped from the query string; - a
bodywas emitted even for aGETrequest, whichfetchforbids.
The generator now uses the parameter's bare name for the body expression and the exclusion key, only emits a fetch body for methods that can carry one (not GET), and — like the server — matches @body_parameter_name against the converted, actual, or expanded signature name of an HTTP Custom Type field (e.g. responseBody, _response, or _response_body).
4. Opt-in: omit automatic (server-filled) parameters from generated request shapes
New option OmitAutomaticParameters on all three generators — TsClientOptions, HttpFileOptions, and OpenApiOptions (default false, so generated output is unchanged unless you opt in).
When enabled, a parameter is omitted from the generated request (TypeScript request interface, .http query/body, OpenAPI query parameters / request body) when it is automatic (filled server-side, so a client value would be ignored) and optional. Automatic covers: HTTP Custom Type fields, resolved-parameter expressions, upload-metadata parameters, and — on endpoints that use user parameters — IP-address and user-claim parameters. The shared rule lives on the core endpoint (RoutineEndpoint.OmitParameterFromGeneratedRequest), so the three generators stay consistent. When every parameter is omitted, the generated request collapses cleanly (no-argument TS function, bare .http URL, no OpenAPI parameters/requestBody).
This is the proper fix for the misleading case where, e.g., an HTTP Custom Type's responseBody field appeared as a settable request parameter even though the server always overrides it.
Why these go together
The pattern "fetch with an HTTP Custom Type, then @proxy to an upstream" now works cleanly end to end — server and generated client: redirect the (large) body field into the upstream request body with @body_parameter_name, while the remaining small fields travel on the query string under the new length guard.
Notes
ProxyOptions.MaxForwardedQueryParamLengthis wired through the client config (appsettings.json, JSON schema, and the--configtemplate).- No parameter
ActualNamesemantics changed: expanded HTTP-type fields still share the composite base name so they reassemble into the single SQL argument; the per-field name is matched via an internal alias only.
Tests
NpgsqlRestTests/ProxyTests/ProxyHttpTypeProbeTest.cs adds three cases (WireMock proxy target echoing the received URL / body): body redirect by converted name (responseBody), body redirect by expanded signature name (_response_body), and an oversized HTTP-type body field skipped from the proxy query string. NpgsqlRestTests/TsClientTests/BodyParamGetTests.cs covers the generated client for @body_parameter_name endpoints: a GET case (no ?-suffixed name, parameter excluded from the query, no fetch body on GET) and a POST HTTP-Custom-Type case targeted by the expanded name _response_body (body emitted as request.responseBody, excluded from the query). The HTTP file and OpenAPI generators are covered for the same expanded-name body redirect (BodyParamToBodyTests). OmitAutomaticParameters is covered for each generator (TsClient: all-omitted no-arg function + mixed-params; HttpFiles and OpenAPI: query/body omission of HTTP Custom Type fields). Full suite green (2301).