Changelog
0.47.8
(fix): A request body declared application/x-www-form-urlencoded is now form-encoded
instead of being sent as a JSON document under an application/json header. Those
endpoints went through execute_request, whose .json() both serializes to JSON and
stamps the header, so neither the bytes nor the content type matched the declaration.
0.47.7
(fix): A JSON request body declared under a media type other than application/json - a
vendor type, or application/merge-patch+json - is now sent under that type instead
of application/json. execute_request calls reqwest’s .json(), which stamps
application/json over whatever the endpoint declared, so those endpoints now take a
variant that sets the header and serializes the body identically. Emitted only when an
endpoint declares such a type, so an SDK that never does is unchanged.
0.47.6
(fix): An array query parameter declared style: form with explode: false is now sent as
one comma-joined value instead of a repeated key. The IR has always carried explode
and the Rust generator read it nowhere, so every array went out exploded regardless of
what the endpoint declared. An empty array still produces no parameter.
0.47.5
(fix): Basic auth credentials are now sent. An API whose only security scheme is basic auth
generated a client that applied NO credential at all: the client-wide auth path
applied an API key and a bearer token but had no basic branch, username and
password sat unread on the config, and the one Authorization header in the
generated client was gated on config.token, which such an API never sets. Only
per-endpoint auth routing handled basic auth.
0.47.4
(fix): A string field sent alongside a file in a multipart body is now written verbatim
instead of being JSON-serialized first. serde_json::to_string wrapped it in quotes
and those quotes reached the server as part of the value, so a 13-character caption
arrived as 15. Structured parts (objects, arrays, maps) still go as JSON; numbers and
booleans were never affected.
0.47.3
(fix): A raw-bytes request body is now sent under the content type the endpoint declares
instead of always application/octet-stream. The IR has always carried it on the
bytes body, and the C#, Python and TypeScript generators already stamped it; Rust
hard-coded the header in execute_bytes_request. An endpoint that declares no
content type still sends application/octet-stream.
0.47.2
(fix): An offset-paginated endpoint’s auto-paging method now stops on a SHORT page rather than
only on an empty one. A page holding fewer items than the caller’s page size is the last
page, so treating “not empty” as “there is more” cost one wasted request against a
well-behaved server and never terminated at all against one that keeps answering.
0.47.1
(fix): An offset-paginated endpoint now sends its page-size parameter on every page request
instead of only the first. The step parameter of x-fern-pagination was being
stripped from the query along with the offset, but only the offset changes between
pages - the page size is the same on all of them and has to be sent each time.
(fix): Advance an offset by the number of items the page returned rather than by a step read
out of the response body, which was never present and so left every offset advancing
by one. Add offsetSemantics, matching the TypeScript and Python generators: the
default "item-index" advances by the page’s item count, and "page-index" advances
by one.
0.47.0
(feat): Paginated endpoints once again generate an auto-paging method. It is now emitted
ALONGSIDE the single-page method as <endpoint>_paginated rather than replacing it,
so the endpoint keeps its typed response and callers who want one page do not have
to go through a paginator.
(fix): Fix the borrow that made the paginated method fail to compile. The page loader
outlives the method call, so path and body parameters are now captured as owned
values, and the rewrite that points the loader at those captures no longer fails to
match every name.
0.46.7
(chore): Solve Default support for every type in one pass over the IR instead of walking
the type graph again for each reference. Derives are unchanged, and the answer no
longer depends on which type is analyzed first.
(fix): Index type declarations once instead of scanning every IR type on each lookup.
Generating models for APIs with thousands of types is now dramatically faster.
0.46.6
(fix): List- and set-typed path parameters are now joined instead of being interpolated
directly, so a spec with an array path parameter produces an SDK that compiles.
Previously the parameter name was passed straight to format!, which does not
compile because Vec<T> has no Display:
0.46.5
(fix): Aliases of unknown (e.g. AnyType wrapping serde_json::Value) now derive
Default, so structs and aliases that contain them and derive Default
compile without manual patching. The struct generator’s private copy of the
default analysis has been folded into the shared hasDefaultImpl, which is
now the single source of truth and no longer recurses forever on types that
reference each other. #[serde(default)] emission is unchanged: a required
unknown field still fails to deserialize when the key is missing.
0.46.4
(fix): Fix generated code failing to compile when a property is named self, Self, crate or super.
Rust rejects these as raw identifiers, so they are now suffixed with an underscore (self_)
and given an explicit #[serde(rename = "self")] to preserve the wire name.
0.46.3
(fix): Custom headers are applied when the SDK runs through an injected RequestExecutor (the path
used by generated CLI custom commands). ClientConfig::custom_headers — including an
X-Source-style override and the X-Fern-* platform headers — and
RequestOptions::additional_headers were previously dropped before delegating to the executor,
so they reached the wire on generated-path requests but not on custom-command ones. Auth and
retries remain the executor’s responsibility.
0.46.2
(fix): Endpoints that declare retries: { disabled: true } (x-fern-retries in OpenAPI) no longer
retry. The generated method pins max_retries to zero on the request options, overriding both
the client-level default and any caller-supplied value.
0.46.1
(fix): Fixed generated WireMock stubs for OAuth client credentials APIs whose token endpoint is
itself marked as authenticated: the token (and refresh) endpoint stub no longer requires
an Authorization header, since the token request is made to obtain the token and cannot
carry one yet.
0.46.0
(feat): Add respectOptionalRequestBody. When enabled, an endpoint whose request body the API does not
require takes the body as an Option, so a caller who passes None sends no body and no
Content-Type. Examples that omit the body render as None in snippets, reference docs, and
wire tests. The flag defaults to false, so existing SDKs keep their current method signatures.
0.45.0
(feat): Generated clients accept a custom reqwest::Client. ClientConfig gained a
reqwest_client: Option<reqwest::Client> field, set through the new
ApiClientBuilder::reqwest_client(...), and HttpClient uses it as-is when present
instead of building its own. This is the transport escape hatch other Fern SDKs already
expose (httpx_client in Python, OkHttpClient in Java, urlSession in Swift), and it
lets callers configure root certificates, client certificates, proxies and connection
pooling themselves. Authentication, custom headers and retries are still applied by the
SDK on top of the supplied client; when the field is None the client is built exactly
as before from timeout and user_agent.
0.44.5
(fix): Write the LICENSE file into the generated crate when a custom license is configured
(github.license.custom or metadata.license.custom), matching the other SDK generators.
When that file is written and neither packageLicense nor packageLicenseFile is set,
Cargo.toml now points license-file at it instead of defaulting to MIT.
0.44.4
(fix): Non-2xx responses with a body are now returned as errors instead of successes.
parse_response and parse_response_raw only consulted the status code inside
their empty-body branch, so any error response that carried a payload was
deserialized into the success type and returned Ok. When the success type can
absorb an arbitrary object — all-optional fields, a bare Value, a defaulted
collection — the call looked like an empty-but-successful result: a 401 surfaced
as “no results found” and the process exited 0, which a calling script reads as
“nothing to do”. The status is now checked before deserialization in both
methods, and the response body is carried through as the ApiError::Http
message so the server’s own error detail reaches the caller.