# Fern > Documentation for Fern --- # Fern Documentation Source: https://buildwithfern.com/llms-full.txt --- --- # Build with Fern > Build better developer experiences. Generate SDKs in TypeScript, Python, Go, Java, C#, PHP, Ruby, Swift & Rust. Create interactive API docs with AI search.
{/* Main Content */}
{/* Dashed Pattern */} {/* Hero Section */}

Build with Fern

Start with SDKs, Docs, or both.

{/* Feature Grid */}
{/* SDKs Card */}
SDKs Arrow right light Arrow right light

Generate client libraries in multiple languages.

{/* Rive Animation */}
{/* Language Icons */}
Get started with: {/* TypeScript */} TypeScript {/* Python */} Python {/* Go */} Go {/* Java */} Java {/* C# */} C# {/* PHP */} PHP {/* Ruby */} Ruby Swift
{/* Action Buttons */}
Introduction Arrow right light Arrow right light Quickstart Arrow right light Arrow right light Customers Arrow right light Arrow right light
{/* Docs Card */}
Docs Arrow right light Arrow right light

A beautiful, interactive documentation website.

{/* Rive Animation */}
Introduction Arrow right Arrow right Quickstart Arrow right light Arrow right light AI features Arrow right light Arrow right light Fern Editor Arrow right light Arrow right light Bring your own API spec Arrow right light Arrow right light Control role-based access Arrow right light Arrow right light Self host your docs Arrow right light Arrow right light Customers Arrow right light Arrow right light
{/* AI Search Card */}
Ask Fern Arrow right light Arrow right light

AI Search to find answers in your documentation instantly.

{/* Rive Animation */}
Introduction Arrow right light Arrow right light Configure Arrow right light Arrow right light Customers Arrow right light Arrow right light
{/* Supported Specs Section */}

Supported Specs

Select one or more specs to generate SDKs and Docs.

Github Preview Github Preview

OpenAPI

Github Preview Github Preview

AsyncAPI

Github Preview Github Preview

OpenRPC

Github Preview Github Preview

gRPC

Github Preview Github Preview

Fern Definition

{/* Community Section */}

Community

Changelog Preview Changelog Preview

Changelog

See our most recent product updates.

Docs TypeScript {/* Python */} Python {/* Go */} Go {/* Java */} Java {/* C# */} C# {/* PHP */} PHP {/* Ruby */} Ruby {/* Swift */} Swift
Github Preview Github Preview

Github

Follow progress and contribute to the codebase.

View
Slack Preview Slack Preview

Slack

Connect with the Fern community.

View
Twitter Preview Twitter Preview

Twitter X

Get updates on the Fern platform.

View
{/* Help Section */}

Help

We're lightning-fast with support! If you're a customer, reach out via your dedicated Slack channel.

Github Github File a Github issue Email Email Email us Email Email Book a demo
--- # SDKs overview > Build multi-language SDKs with Fern's generator platform. Support TypeScript, Python, Go, Java, .NET, PHP, Ruby, Swift, and Rust clients.
{/* Dashed Pattern - Left Side */}
{/*
*/}
{/* Dashed Pattern - Right Side */}
{/*
*/}
C++
C++ Arrow right light Arrow right light
Kotlin
Kotlin Arrow right light Arrow right light
--- # How SDKs work > Understand Fern's SDK generation process. Cloud-based workflow transforms API specifications into production-ready client libraries automatically. Fern combines your API specifications with generator configurations and custom code to produce SDKs in multiple languages. By default, SDK generation runs on Fern's managed cloud infrastructure. Alternatively, [you can run SDK generation on your own infrastructure](/sdks/deep-dives/self-hosted) to meet specific security or compliance requirements. ## Cloud generation workflow Before generating SDKs, you'll configure your `fern/` folder with SDK generators specified in `generators.yml` and connect your API specification. You can also add custom code, tests, and other configuration as needed. Running `fern generate` kicks off the cloud generation process and involves a few key steps: Fern allocates compute resources and pulls the appropriate Docker image for your specified generator version. The Docker container executes the generation logic and produces your SDK's core files (models, client code, API methods). Fern verifies your organization registration to ensure the complete SDK can be generated. Without organization verification, only partial SDK files (core code without package metadata) are produced. Fern completes the SDK by adding package distribution files such as `pyproject.toml`, `package.json`, README, and any dependencies. Fern publishes or saves the complete SDK to your configured location (local filesystem, GitHub repository, package registry). After publication, developers can use your SDKs to integrate with your APIs. ```mermaid sequenceDiagram autonumber participant Dev as Developer participant Fern as Fern participant Docker as Docker container participant Dest as Output destination Dev->>Fern: fern generate Fern->>Fern: Allocate cloud compute Fern->>Docker: Pull & run generator image Docker->>Docker: Generate core SDK files Docker->>Fern: Return partial SDK Fern->>Fern: Verify organization Fern->>Fern: Add package metadata Fern->>Dest: Output complete SDK ``` ![SDK generation architecture diagram](https://files.buildwithfern.com/fern.docs.buildwithfern.com/learn/7c1a93924212d280041c36db9a92009795bdd80874510285471fa6b3d80c5032/products/sdks/images/sdk-gen.png) --- # Quickstart > Learn how to generate SDKs with Fern. Install the CLI, initialize your project with OpenAPI or Fern Definition, and start building client libraries. Configuring Fern starts with the `fern` folder, the root directory that contains your API definitions, SDK generators, and CLI version. ```bash npm install -g fern-api ``` Initialize the fern folder with your existing OpenAPI specification, or start from scratch with a Fern Definition template. Specify your organization name using the `--organization` flag. ```bash # OpenAPI (local) fern init --openapi path/to/openapi.yml \ --organization # OpenAPI (URL) fern init --openapi https://api.example.com/openapi.yml \ --organization # Fern Definition fern init --organization ``` OpenAPI accepts both JSON and YAML formats. You can always convert a [Fern Definition to OpenAPI](/api-definitions/ferndef/export-openapi) or OpenAPI to a Fern Definition later on. This creates a `fern` folder in your current directory. `imdb.yml` contains an example movies API. If you’re just generating an SDK for test purposes, you can leave this file as it is. To generate an SDK for your own API instead of the example movies API, replace `imdb.yml` with your own endpoints, types, and errors. Generate a [TypeScript SDK](/learn/sdks/generators/typescript/quickstart) locally (or explore [other supported languages](/learn/sdks/overview/introduction)). ```bash fern generate ``` This creates a `sdks/typescript` folder containing your generated SDK: Now that you have a local SDK, you can publish it, try other languages, or extend its functionality: Set up your SDK and API definitions in GitHub. Explore all supported languages. Extend your generated SDKs with custom functionality. --- # Project structure > Learn how to structure your SDK project with Fern. Set up multi-repo architecture, configure generators.yml, and organize API definitions. Before generating SDKs with Fern, set up the proper GitHub repository structure to house your API definitions and SDK code so it's intuitive for you and your users to access, maintain, and update code. ## Repository architecture Fern recommends a multi-repository structure containing: * **Source repository** with your API definitions and SDK generation configuration * **SDK repositories** for each SDK (TypeScript, Python, Go, etc.) This separation allows you to manage API definitions centrally while keeping each SDK in its own repository for independent versioning and distribution. See Cohere's [fern folder](https://github.com/cohere-ai/cohere-developer-experience/tree/23d6c541a01eb6b54dd9bb3588c805bb0e307713/fern) and [TypeScript](https://github.com/cohere-ai/cohere-typescript) and [Python](https://github.com/cohere-ai/cohere-python) SDK repositories. ## Core configuration files The source repository contains a `fern/` folder that is initialized with your API definitions and a top-level `generators.yml` file. ### `fern.config.json` The `fern.config.json` file stores your organization name and the Fern CLI version. Pinning the version provides deterministic builds. ```json title="fern.config.json" { "organization": "plant-catalog", "version": "3.57.0" } ``` When working with a locally installed CLI, set `version` to `"*"`. See [Install Fern CLI locally](/cli-api-reference/cli-reference/overview#install-fern-cli-locally) for details. ### `generators.yml` The `generators.yml` file configures SDK generation in the `groups` section. For OpenAPI/AsyncAPI, you must also declare your API spec location in the `api.specs` section. ```yaml title="generators.yml" # API declaration (required for OpenAPI/AsyncAPI) api: specs: - openapi: ./openapi/openapi.yml # SDK generation groups: ts-sdk: generators: - name: fernapi/fern-typescript-sdk version: 3.46.3 github: repository: your-organization/typescript-sdk-repo python-sdk: generators: - name: fernapi/fern-python-sdk version: 4.50.1 github: repository: your-organization/python-sdk-repo ``` For Fern Definition, the `api` section isn't needed. Fern auto-detects your API from the `definition/` directory. ```yaml title="generators.yml" groups: ts-sdk: generators: - name: fernapi/fern-typescript-sdk version: 3.46.3 github: repository: your-organization/typescript-sdk-repo python-sdk: generators: - name: fernapi/fern-python-sdk version: 4.50.1 github: repository: your-organization/python-sdk-repo ``` See Cohere's [`generators.yml` file](https://github.com/cohere-ai/cohere-developer-experience/blob/23d6c541a01eb6b54dd9bb3588c805bb0e307713/fern/apis/sdks/generators.yml) and Vapi's [`generators.yml` file](https://github.com/VapiAI/docs/blob/9c674c2b16ba03e864e26673c5290c88048c9a7a/fern/apis/api/generators.yml). See the [`generators.yml` reference page](/sdks/reference/generators-yml) for complete configuration options. ### API definition file See [Project structure (API Definitions)](/api-definitions/overview/project-structure) for details on organizing your API definition files and working with multiple APIs. ## Setup instructions 1. **Create repositories**: Set up your source repository, plus one repository for each SDK 2. **Install Fern GitHub App**: Install the [Fern GitHub App](https://github.com/apps/fern-api) on all repositories 3. **Configure `generators.yml`**: In your `generators.yml`, add a reference to each SDK repository. --- # Adding custom code > Extend Fern-generated SDKs with custom methods, logic, and dependencies. Use .fernignore to protect your code from being overwritten during regeneration. Fern-generated SDKs are designed to be extended with custom logic, methods, and dependencies. If you want your SDK to do more than just make basic API calls (like combining multiple calls, processing data, adding utilities), you can add custom code that lives in harmony with the generated code. You can also add custom methods by inheriting the Fern generated client and extending it, plus add any dependencies that your custom methods depend on in your `generators.yml` file. ## Using `.fernignore` to preserve your customizations Once you add files containing custom code, use `.fernignore` to protect your custom code from being overwritten when Fern regenerates your SDK. Simply add your custom files to the SDK repository and list them in `.fernignore`. Fern won't override any files listed there. A `.fernignore` file is automatically created in your SDK repository when you use GitHub publishing. Your `.fernignore` file might look something like this: ```gitignore title=".fernignore" --- # Custom workflows .github/workflows/test.yml .github/workflows/ci.yml --- # Custom code src/CustomClient.ts ``` For another example, see Cohere's [`.fernignore` file for their TypeScript SDK](https://github.com/cohere-ai/cohere-typescript/blob/ad583e3003bd51e80a82317f9e16beec85881b86/.fernignore) . You'll have a separate `.fernignore` file for each of your SDKs: ## Augmenting your SDK with custom code Get started adding custom code to a specific SDK: } href="/sdks/generators/typescript/custom-code" /> } href="/sdks/generators/python/custom-code" /> } href="/sdks/generators/go/custom-code" /> } href="/sdks/generators/java/custom-code" /> } href="/sdks/generators/csharp/custom-code" /> } href="/sdks/generators/php/custom-code" /> } href="/sdks/generators/ruby/custom-code" /> --- # Capabilities > Fern SDK capabilities include type safety, auto-pagination, OAuth token refresh, retries with backoff, webhook verification, and more. Move fast and break nothing with type safety Rich autocomplete and inline documentation in your editor

Learn more Arrow right light Arrow right light

Fine-tune SDK resources and method names

Learn more Arrow right light Arrow right light

Fail fast if payloads diverge from your schema

Learn more Arrow right light Arrow right light

Fern SDKs include support for discriminated unions

Learn more Arrow right light Arrow right light

SDKs that handle multipart form data

Learn more Arrow right light Arrow right light

SDKs that are fault-tolerant as your API evolves Fern Autorelease automatically detects API changes, regenerates SDKs, and publishes to registries.

Learn more Arrow right light Arrow right light

Paginate through API responses easily with offset, cursor, and link-based pagination.

Learn more Arrow right light Arrow right light

Fern supports OAuth as a first class citizen

Learn more Arrow right light Arrow right light

Automatically retry failed requests with exponential backoff

Learn more Arrow right light Arrow right light

Verify the signature of incoming webhook requests

Learn more Arrow right light Arrow right light

Built-in protection against duplicate submissions

Learn more Arrow right light Arrow right light

Stream JSON data from your server to your client (i.e. chat completions)

Learn more Arrow right light Arrow right light

Auto-generated and handwritten tests to ensure your SDK works in production

Learn more Arrow right light Arrow right light

No longer depend on manually written code snippets

Learn more Arrow right light Arrow right light

Extend the generated SDK to provide additional functionality

Learn more Arrow right light Arrow right light

Multiple API definitions. One SDK.

Learn more Arrow right light Arrow right light

Send and receive messages over WebSockets

Learn more Arrow right light Arrow right light

--- # Fern Autorelease > Automate SDK releases with Fern Autorelease. Detects API spec changes, regenerates SDKs, determines version bumps, and publishes to package registries. Fern Autorelease automates SDK releases end-to-end. When your API specification changes, Autorelease regenerates SDKs, determines the version bump, and publishes to package registries. ## How it works Autorelease detects changes to your spec using either **git-based detection** (monitors your spec repository for commits) or **pull-based detection** (periodically fetches your hosted spec from a URL). Once changes are detected, Autorelease: 1. Regenerates SDKs for all configured languages 2. Analyzes the API diff and determines the next version (semantic, calendar-based, integer, or custom) 3. Commits to repositories, tags releases, and publishes packages 4. Updates changelogs automatically Autorelease pauses and requests confirmation if it's uncertain about the version bump. Publishing uses tokens stored in your GitHub Actions secrets—Fern never has access to these credentials. If a release fails, Autorelease pauses and sends alerts via Slack (if configured) or the Fern Dashboard where you can review and retry. ## Setup To enable Autorelease, add `autorelease: true` to your `generators.yml` and ensure the [Fern GitHub App](https://github.com/apps/fern-api) is installed on your SDK repositories. Releases trigger automatically on commits to your spec repository and appear as commit status checks. No changes to your CI/CD setup are required. ```yaml generators.yml autorelease: true ``` ```yaml generators.yml {6} groups: python-sdk: generators: - name: fernapi/fern-python-sdk version: 4.50.1 autorelease: true ``` Autorelease commit status check ### Customize Autorelease You can customize Autorelease if you need to fetch from a hosted spec URL or review releases before publishing. Add a cron schedule to your `generators.yml`: ```yaml generators.yml autorelease: cron: schedule: "0 0 * * 0" # Weekly on Sunday at midnight ``` Or configure per-generator: ```yaml generators.yml groups: python-sdk: generators: - name: fernapi/fern-python-sdk version: 4.50.1 autorelease: cron: schedule: "0 */6 * * *" # Every 6 hours ``` [Set `mode: pull-request`](/learn/sdks/reference/generators-yml#pull-request) to review releases before publishing. Autorelease will open a pull request for you to review instead of publishing directly. ```yaml generators.yml {8} groups: ts-sdk: generators: - name: fernapi/fern-typescript-sdk ... github: repository: your-org/your-repo-name mode: pull-request ``` --- # TypeScript quickstart > Create TypeScript client libraries with Fern SDK generator. Quick guide to configuring generators.yml and generating SDKs from OpenAPI or Fern definitions. Generate a TypeScript SDK by following the instructions on this page. This page assumes that you have: * An initialized `fern` folder. See [Set up the `fern` folder](/sdks/overview/quickstart). * A GitHub repository for your SDK. See [Project Structure](/sdks/overview/project-structure). ### Pass `fern check` Run `fern check` to ensure that your API definition is valid. If there are any errors, fix them before proceeding. If you're using an OpenAPI Specification, check out all of our [supported extensions](/learn/api-definition/openapi/extensions). ## Add the SDK generator Run the following command to add the TypeScript SDK generator to `generators.yml`: ```bash fern add fern-typescript-sdk --group ts-sdk ``` `ts-sdk` is the name of the `generators.yml` group that configures your TypeScript SDK's output location and other metadata. You can customize this group name to differentiate between multiple SDKs across different languages (e.g., `ruby-sdk`, etc) in your organization. This command adds the following `group` to `generators.yml`: ```yaml title="generators.yml" ts-sdk: # group name generators: - name: fernapi/fern-typescript-sdk version: 3.46.3 output: location: local-file-system path: ../sdks/typescript ``` ## Generate the SDK Run the following command to generate your SDK: ```bash fern generate --group ts-sdk ``` If you have multiple APIs, use the [`--api` flag](/cli-api-reference/cli-reference/commands#api) to specify the API you want to generate: ```bash fern generate --group ts-sdk --api your-api-name ``` This creates a `sdks` folder in your current directory. The resulting folder structure looks like this: --- # TypeScript configuration > Configure TypeScript SDK generation with Fern. Customize namespaces, enable serde layer, manage dependencies, and control file output. You can customize the behavior of the TypeScript SDK generator in `generators.yml`: ```yml {6-9} title="generators.yml" groups: ts-sdk: generators: - name: fernapi/fern-typescript-sdk version: 3.46.3 config: namespaceExport: AcmePayments noSerdeLayer: false generateSubpackageExports: true ``` Allow fields that are not defined in object schemas. This only applies to serde. See [TypeScript serde layer](/sdks/generators/typescript/serde-layer) for more information. The default timeout for network requests. In the generated client, this can be overridden at the request level. When enabled, the inline schemas will be generated as nested types in TypeScript. This results in cleaner type names and a more intuitive developer experience. `enableInlineTypes: false`: ```typescript // MyRootType.ts import * as MySdk from "..."; export interface MyRootType { foo: MySdk.MyRootTypeFoo; } // MyRootTypeFoo.ts import * as MySdk from "..."; export interface MyRootTypeFoo { bar: MySdk.MyRootTypeFooBar; } // MyRootTypeFooBar.ts import * as MySdk from "..."; export interface MyRootTypeFooBar {} ``` `enableInlineTypes: true`: ```typescript // MyRootType.ts import * as MySdk from "..."; export interface MyRootType { foo: MyRootType.Foo; } export namespace MyRootType { export interface Foo { bar: Foo.Bar; } export namespace Foo { export interface Bar {} } } ``` Now users can get the deep nested `Bar` type as follows: ```typescript import { MyRootType } from MySdk; const bar: MyRootType.Foo.Bar = {}; ``` This feature is available only for the [Pro and Enterprise plans](https://buildwithfern.com/pricing). To get started, reach out to [support@buildwithfern.com](mailto:support@buildwithfern.com). Specify extra dependencies in the generated `package.json`. This is useful when you add custom code to your SDK that requires additional dependencies. ```yaml # generators.yml config: extraDependencies: lodash: "3.0.2" ``` This feature is available only for the [Pro and Enterprise plans](https://buildwithfern.com/pricing). To get started, reach out to [support@buildwithfern.com](mailto:support@buildwithfern.com). Specify extra dev dependencies in the generated `package.json`. ```yaml # generators.yml config: extraDevDependencies: jest: "29.0.7" ``` Only applies when publishing to Github. Specify extra peer dependencies in the generated `package.json`: ```yaml # generators.yml config: extraPeerDependencies: react: ">=16.8.0 <19.0.0" "react-dom": ">=16.8.0 <19.0.0" ``` Specify extra peer dependencies meta fields in the generated `package.json`: ```yaml # generators.yml config: extraPeerDependencies: react: ">=16.8.0 <19.0.0" "react-dom": ">=16.8.0 <19.0.0" ``` Choose whether you want to include `node-fetch` to support Node.js versions before Node.js 18, or choose `native` to use the native `fetch` API available in Node.js 18 and later. Change the type of response returned to the user for a binary HTTP response: * `stream`: Returns a stream. See `streamType`, which controls the type of stream returned. * `binary-response`: Returns the `BinaryResponse` type, which allows the user to choose how to consume the binary HTTP response. Here's how your users can interact with the `BinaryResponse`: ```typescript const response = await client.getFile(...); const stream = response.stream(); // const arrayBuffer = await response.arrayBuffer(); // const blob = await response.blob(); // const bytes = await response.bytes(); const bodyUsed = response.bodyUsed; ``` Choose whether you want to support Node.js 16 and above (`Node16`), or Node.js 18 and above (`Node18`). * `Node16` uses multiple dependencies to support multipart forms, including `form-data`, `formdata-node`, and `form-data-encoder`. * `Node18` uses the native FormData API, and accepts a wider range of types for file uploads, such as `Buffer`, `File`, `Blob`, `Readable`, `ReadableStream`, `ArrayBuffer`, and `Uint8Array` Generates [mock server (wire) tests](/sdks/deep-dives/testing#mock-server-tests) to verify that the SDK sends and receives HTTP requests as expected. Generates subpackage exports that allow users to import individual clients directly, rather than importing the entire SDK. This enables JavaScript bundlers to tree-shake unused code, significantly reducing bundle sizes. ```typescript import { BarClient } from '@acme/sdk/foo/bar'; // Imports only the Bar subpackage const client = new BarClient({...}); ``` Subpackage exports are also documented in the generated `README.md` when this option is enabled. Includes the content type and content length from binary responses. The user will receive an object of the following type: ```typescript { data: ; contentLengthInBytes?: number; contentType?: string; } ``` `` is `core.BinaryResponse` or a stream, depending on `fileResponseType` setting. When enabled, [`withCredentials`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials) is set to `true` when making network requests. Generate file upload properties as inline request properties (instead of positional parameters). `inlineFileProperties: false`: ```typescript /** * @param {File | fs.ReadStream} file * @param {File[] | fs.ReadStream[]} fileList * @param {File | fs.ReadStream | undefined} maybeFile * @param {File[] | fs.ReadStream[] | undefined} maybeFileList * @param {Acme.MyRequest} request * @param {Service.RequestOptions} requestOptions - Request-specific configuration. * * @example * await client.service.post(fs.createReadStream("/path/to/your/file"), [fs.createReadStream("/path/to/your/file")], fs.createReadStream("/path/to/your/file"), [fs.createReadStream("/path/to/your/file")], {}) */ public async post( file: File | fs.ReadStream, fileList: File[] | fs.ReadStream[], maybeFile: File | fs.ReadStream | undefined, maybeFileList: File[] | fs.ReadStream[] | undefined, request: Acme.MyRequest, requestOptions?: Acme.RequestOptions ): Promise { ... } ``` `inlineFileProperties: true`: ```typescript /** * @param {Acme.MyRequest} request * @param {Service.RequestOptions} requestOptions - Request-specific configuration. * * @example * await client.service.post({ * file: fs.createReadStream("/path/to/your/file"), * fileList: [fs.createReadStream("/path/to/your/file")] * }) */ public async post( request: Acme.MyRequest, requestOptions?: Service.RequestOptions ): Promise { ... } ``` Inline path parameters into request types. `inlinePathParameters: false`: ```typescript await service.getFoo("pathParamValue", { id: "SOME_ID" }); ``` `inlinePathParameters: true`: ```typescript await service.getFoo({ pathParamName: "pathParamValue", id: "SOME_ID" }); ``` Customizes the exported namespace and client class names in the generated SDK. Must be in PascalCase. By default, names are derived from the organization and API names defined in your API definition: ```typescript import { AcmeApi, AcmeApiClient } from "@acme/node"; ``` Setting namespaceExport overrides these default names: ```yaml title="generators.yml" config: namespaceExport: AcmePayments ``` ```typescript import { AcmePayments, AcmePaymentsClient } from "@acme/node"; ``` When enabled, the client doesn't throw errors when a non-200 response is received from the server. Instead, the response is wrapped in an [`ApiResponse`](https://github.com/fern-api/fern/blob/main/seed/ts-sdk/alias/src/core/fetcher/APIResponse.ts). ```typescript const response = await client.callEndpoint(...); if (response.ok) { console.log(response.body) } else { console.error(respons.error) } ``` By default, Fern's `optional<>` properties will translate to optional TypeScript properties: ```yaml {4} Person: properties: name: string age: optional ``` ```typescript {3} interface Person { name: string; age?: number; } ``` When `noOptionalProperties` is enabled, the generated properties are never optional. Instead, the type is generated with `| undefined`. As a result, users must explicitly set the property to a value or `undefined`. ```typescript {3} interface Person { name: string; age: number | undefined; } ``` Prevent the generator from running any scripts such as `yarn format` or `yarn install`. If any of the scripts cause errors, toggling this option will allow you to receive the generated code. Controls whether the serde layer is enabled for serialization/deserialization. When `noSerdeLayer: false`, the generated client includes custom serialization code that transforms property names to camelCase, validates requests/responses at runtime, and supports complex types. See [TypeScript serde layer](/sdks/generators/typescript/serde-layer) for detailed guidance on when to enable this option. Controls the output format of generated files: * **When `true` (default)**: Outputs raw TypeScript `.ts` files * **When `false`**: Runs TypeScript compiler and outputs compiled `.js` files with `.d.ts` declaration files This option only applies when using local file system output. This setting is ignored when publishing to GitHub or npm, where files are always compiled. When you specify an object in `packageJson`, it will be merged into the `package.json` file. This is the recommended way to customize your SDK's package.json. ```yaml # generators.yml config: packageJson: description: The SDK for Acme Corp's API. author: name: Acme Corp url: https://developer.acmecorp.com email: developers@acmecorp.com bugs: url: https://developer.acmecorp.com email: developers@acmecorp.com ``` Use the `packageJson` config option instead of `.fernignore` to prevent package.json from being overwritten. Specifies the TypeScript package name that users will import your generated client from. For example, setting `package-name: "my_custom_package"` enables users to use `my_custom_package import Client` to import your client. Specify the path where the source files for the generated SDK should be placed. Publish your SDK to [JSR](https://jsr.io/). When enabled, the generator will generate a `jsr.json` as well as a GitHub workflow to publish to JSR. When enabled, property names in the generated code retain their original casing from the API definition instead of being converted to camelCase. ```yaml # generators.yml config: retainOriginalCasing: true ``` **Example with OpenAPI input:** ```yaml {7, 9} # OpenAPI schema components: schemas: User: type: object properties: user_id: type: string display_name: type: string ``` Generated TypeScript with `retainOriginalCasing: true`: ```typescript {2-3} export interface User { user_id: string; display_name: string; } ``` Generated TypeScript with default settings (`retainOriginalCasing: false`): ```typescript {2-3} export interface User { userId: string; displayName: string; } ``` Generate WebSocket clients from your AsyncAPI specs. By default, the client will throw an error if the response from the server doesn't match the expected type (based on how the response is modeled in the Fern Definition). If `skipResponseValidation` is set to `true`, the client will never throw if the response is misshapen. Instead, the client will log the issue using `console.warn` and return the data (casted to the expected response type). Response validation only occurs when the Serde layer is enabled ( `noSerdeLayer: false` ). The Serde layer is disabled by default ( `noSerdeLayer: true` ). Change the type of stream that is used in the generated SDK. * `wrapper`: The streams use a wrapper with multiple underlying implementations to support versions of Node.js before Node.js 18. * `web`: The streams use the web standard `ReadableStream`. The default is `web`. When `treatUnknownAsAny` is enabled, [unknown types from Fern are generated into TypeScript using `any` instead of the `unknown` type](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html#new-unknown-top-type). When `useBigInt` is set to `true`, a customized JSON serializer & deserializer is used that will preserve the precision of `bigint`'s, as opposed to the native `JSON.stringify` and `JSON.parse` function which converts `bigint`'s to number's losing precision. When combining `useBigInt` with our serialization layer (`noSerdeLayer: false`), both the request and response properties that are marked as `long` and `bigint` in OpenAPI/Fern spec, will consistently be `bigint`'s. However, when disabling the serialization layer (`noSerdeLayer: true`), they will be typed as `number | bigint`. See [TypeScript serde layer](/sdks/generators/typescript/serde-layer) for more information. Here's an overview of what to expect from the generated types when combining `useBigInt` and `noSerdeLayer` with the following Fern definition: *Fern definition*: ```yaml types: ObjectWithOptionalField: properties: longProp: long bigIntProp: bigint ``` *TypeScript output*: ```typescript // useBigInt: true // noSerdeLayer: false interface ObjectWithLongAndBigInt { longProp: bigint; bigIntProp: bigint; } // useBigInt: true // noSerdeLayer: true interface ObjectWithLongAndBigInt { longProp: bigint | number; bigIntProp: bigint | number; } // useBigInt: false // noSerdeLayer: false interface ObjectWithLongAndBigInt { longProp: number; bigIntProp: string; } // useBigInt: false // noSerdeLayer: true interface ObjectWithLongAndBigInt { longProp: number; bigIntProp: string; } ``` When `useBrandedStringAliases` is disabled (the default), string aliases are generated as normal TypeScript aliases: ```typescript // generated code export type MyString = string; export type OtherString = string; ``` When `useBrandedStringAliases` is enabled, string aliases are generated as branded strings. This makes each alias feel like its own type and improves compile-time safety. ```yaml # fern definition types: MyString: string OtherString: string ``` ```typescript // generated code export type MyString = string & { __MyString: void }; export const MyString = (value: string): MyString => value as MyString; export type OtherString = string & { __OtherString: void }; export const OtherString = (value: string): OtherString => value as OtherString; ``` ```typescript // consuming the generated type function printMyString(s: MyString): void { console.log("MyString: " + s); } // doesn't compile, "foo" is not assignable to MyString printMyString("foo"); const otherString = OtherString("other-string"); // doesn't compile, otherString is not assignable to MyString printMyString(otherString); // compiles const myString = MyString("my-string"); printMyString(myString); ``` --- # Publishing to npm > Learn how to publish your Fern TypeScript SDK to npm using OIDC or token-based authentication. Complete guide with GitHub Actions setup. Publish your public-facing Fern TypeScript SDK to the [npmjs registry](https://www.npmjs.com/). After following the steps on this page, you'll have a versioned package published on npm. If you're using token-based authentication, npm has deprecated long-lived classic tokens. See [Migrating from token-based to OpenID Connect (OIDC) publishing](#migrating-from-token-based-to-oidc-publishing) to upgrade to the more secure OIDC authentication. Versioned package published on npmjs.com This page assumes that you have: * An initialized `fern` folder. See [Set up the `fern` folder](/sdks/overview/quickstart). * A GitHub repository for your TypeScript SDK. See [Project structure](/sdks/overview/project-structure). * A TypeScript generator group in `generators.yml`. See [TypeScript Quickstart](quickstart#add-the-sdk-generator). ## Configure SDK package settings You'll need to update your `generators.yml` file to configure the package name, output location, and client naming for npm publishing. Your `generators.yml` [should live in your source repository](/sdks/overview/project-structure) (or on your local machine), not the repository that contains your TypeScript SDK code. In the `group` for your TypeScript SDK, change the output location from `local-file-system` (the default) to `npm` to indicate that Fern should publish your package directly to the npmjs registry: ```yaml {6-7} title="generators.yml" groups: ts-sdk: # Group name for your TypeScript SDK generators: - name: fernapi/fern-typescript-sdk version: 3.46.3 output: location: npm ``` Your package name must be unique in the npmjs registry, otherwise publishing your SDK will fail. ```yaml {8} title="generators.yml" groups: ts-sdk: generators: - name: fernapi/fern-typescript-sdk version: 3.46.3 output: location: npm package-name: your-package-name ``` The `namespaceExport` option controls the name of the generated client. This is the name customers use to import your SDK (`import { your-client-name } from 'your-package-name';`). ```yaml {9-10} title="generators.yml" groups: ts-sdk: generators: - name: fernapi/fern-typescript-sdk version: 3.46.3 output: location: npm package-name: your-package-name config: namespaceExport: YourClientName # must be PascalCase ``` ## Configure GitHub publishing Fern can automatically publish your SDK to npmjs via GitHub Actions. Configure your GitHub repository and publishing mode: Optionally set the mode to control how Fern handles SDK publishing: * `mode: release` (default): Fern generates code, commits to main, and tags a release automatically * `mode: pull-request`: Fern generates code and creates a PR for you to review before release * `mode: push`: Fern generates code and pushes to a branch you specify for you to review before release You can also configure other settings, like the reviewers or license. Refer to the [full `github` (`generators.yml`) reference](/sdks/reference/generators-yml#github) for more information. ```yaml title="generators.yml" {11-14} groups: ts-sdk: generators: - name: fernapi/fern-typescript-sdk version: 3.46.3 output: location: npm package-name: your-package-name config: namespaceExport: YourClientName github: repository: your-org/your-repository mode: push # or "pull-request" branch: your-branch-name # Required for mode: push ``` ## Configure authentication Choose how you want to authenticate with npmjs when publishing. npm has deprecated long-lived classic tokens for publishing from CI/CD workflows. **OpenID Connect (OIDC) authentication is strongly recommended** for security. OIDC-based publishing (also known as "trusted publishing") is the most secure way to publish. With OIDC, you don't need to manage authentication tokens - npmjs trusts your GitHub repository to publish directly. * Fern TypeScript SDK generator version `3.12.3` or later * Fern CLI version `0.94.0` or later (only required for local generation with `--local`) Add `token: OIDC` to the `output` section: ```yaml title="generators.yml" {9} groups: ts-sdk: generators: - name: fernapi/fern-typescript-sdk version: 3.46.3 # Must be 3.12.3 or later output: location: npm package-name: your-package-name token: OIDC config: namespaceExport: YourClientName github: repository: your-org/your-repository mode: push branch: your-branch-name ``` Generate your SDK to create the GitHub Actions workflow with OIDC configuration: ```bash fern generate --group ts-sdk ``` This creates a `.github/workflows/ci.yml` file that's configured to use OIDC for npmjs publishing. Alternatively, you can push your `generators.yml` changes and let the Fern GitHub Action generate the workflow for you. This creates a `.github/workflows/ci.yml` file that's configured to use OIDC for npm publishing. Configure trusted publishing on npmjs.com to allow your GitHub repository to publish: 1. Navigate to your package settings on npmjs.com 2. Find the **Trusted Publisher** section and click **Add trusted publisher** 3. Select **GitHub Actions** as your provider 4. Fill in: * **Organization or user**: Your GitHub username or organization * **Repository**: Your TypeScript SDK repository name (e.g., `your-org/your-repository`) * **Workflow filename**: `ci.yml` * **Environment name**: Leave blank For more details, see npm's [trusted publishing documentation](https://docs.npmjs.com/trusted-publishers). **"Unable to authenticate" error** Common causes: * Workflow filename doesn't match exactly (must be `ci.yml`) * Trusted publisher configuration on npmjs.com doesn't match your repository settings * Using self-hosted runners (not supported by npmjs.org) **Solution:** Double-check your trusted publisher configuration on npmjs.com matches your repository name and workflow filename exactly. **Private repository limitations** Provenance attestations aren't generated for packages published from private repositories, even when using trusted publishing. This is a [known limitation](https://github.blog/changelog/2023-07-25-publishing-with-npm-provenance-from-private-source-repositories-is-no-longer-supported/). **npm has deprecated long-lived classic tokens.** Long-lived authentication tokens can be exposed in logs, compromised, and are difficult to manage and rotate. [OIDC-based authentication is strongly recommended instead](#migrating-from-token-based-to-oidc-publishing). 1. Log into [npmjs.com](https://www.npmjs.com/) 2. Click on your profile picture and select **Edit Profile** 3. Select **Access Tokens** 4. Click **Generate New Token** and choose either **Classic Token** (select "Automation" type) or **Granular Access Token** 5. Save your token securely - it won't be displayed again For more information on access tokens, see npm's [About access tokens](https://docs.npmjs.com/about-access-tokens) documentation. Add `token: ${NPM_TOKEN}` to the `output` section: ```yaml title="generators.yml" {9} groups: ts-sdk: generators: - name: fernapi/fern-typescript-sdk version: 3.46.3 output: location: npm package-name: your-package-name token: ${NPM_TOKEN} config: namespaceExport: YourClientName github: repository: your-org/your-repository mode: push branch: your-branch-name ``` 1. Open your repository on GitHub and go to **Settings** 2. Navigate to **Secrets and variables** > **Actions** 3. Click **New repository secret** 4. Name it `NPM_TOKEN` and paste your npm token 5. Click **Add secret** ## Publish your SDK Your SDK will automatically be published to npmjs when you create a GitHub release with a version tag: 1. Create a GitHub release with a version tag (for example, `v1.0.0`) 2. The CI workflow will run automatically and publish to npm 3. View your package on npmjs.com to confirm the version If you prefer to trigger publishes manually, create a `.github/workflows/publish.yml` file: ```yaml title=".github/workflows/publish.yml" name: Publish TypeScript SDK on: workflow_dispatch: inputs: version: description: "Version to publish (e.g., 1.0.0)" required: true type: string jobs: publish: runs-on: ubuntu-latest steps: - name: Checkout repo uses: actions/checkout@v4 - name: Install Fern run: npm install -g fern-api - name: Generate and publish SDK env: FERN_TOKEN: ${{ secrets.FERN_TOKEN }} run: fern generate --group ts-sdk --version ${{ inputs.version }} --log-level debug ``` Add your `FERN_TOKEN` as a repository secret (run `fern token` to generate one), then trigger the workflow from the **Actions** tab. *** ## Migrating from token-based to OIDC publishing If you're using token-based authentication and need to migrate to OIDC, follow these steps: ### Why migrate to OIDC npmjs is implementing trusted publishing to remove security risks associated with long-lived tokens, which can be: * Exposed in logs or configuration files * Compromised and used persistently until manually revoked * Difficult to manage and rotate OIDC-based publishing uses short-lived, cryptographically signed tokens that are specific to your workflow and can't be extracted or reused. ### Prerequisites Before migrating, ensure you have: * A package published to [npmjs.org](https://npmjs.org) * A GitHub repository with GitHub Actions configured * Access to your package settings on [npmjs.com](https://npmjs.com) * Fern CLI version `0.94.0` or later (for local generation) ### Choose your migration path Select the approach that fits your situation: This is the easiest path if you can upgrade to version 3.12.3 or later of the TypeScript SDK generator. **When to use this path:** * You're able to upgrade to Fern TypeScript SDK generator version 3.12.3 or later * You haven't `.fernignore`'d your CI workflow file Follow npm's ["Add a trusted publisher on npmjs.com"](https://docs.npmjs.com/trusted-publishers#step-1-add-a-trusted-publisher-on-npmjscom) instructions: 1. Navigate to your package settings on [npmjs.com](https://npmjs.com) 2. Find the **Trusted Publisher** section and click **Add trusted publisher** 3. Select **GitHub Actions** as your provider 4. Configure: * **Organization or user**: Your GitHub username or organization * **Repository**: Your TypeScript SDK repository name * **Workflow filename**: `ci.yml` (the default Fern workflow file) * **Environment name**: Leave blank (unless you use GitHub environments) Change the `output.token` field from `${NPM_TOKEN}` to `OIDC` and ensure you're using version `3.12.3` or later: ```yaml title="generators.yml" groups: ts-sdk: generators: - name: fernapi/fern-typescript-sdk version: 3.46.3 # Must be 3.12.3 or later output: location: npm package-name: your-package-name token: OIDC # Changed from ${NPM_TOKEN} config: namespaceExport: YourClientName github: repository: your-org/your-repository ``` Regenerate your SDK with the updated CI configuration. You can do this either: **Locally:** ```bash fern generate --group ts-sdk ``` **Or via GitHub Actions:** If you use the Fern GitHub Action to generate your SDK, simply push your updated `generators.yml` file and let the workflow regenerate the SDK for you. This will update your `.github/workflows/ci.yml` file with the required OIDC permissions. After verifying the migration works, remove the `NPM_TOKEN` secret from your GitHub repository settings to prevent accidental use. Use this path if you can't upgrade the generator or have customized your CI workflow. **When to use this path:** * You can't upgrade due to breaking changes or bugs * You've customized your CI workflow and added it to `.fernignore` * Path 1 didn't update your workflow file Follow the same instructions as Path 1 to add your repository as a trusted publisher on npmjs.com. Open your `.github/workflows/ci.yml` file and make these changes to the `publish` job: ```yaml title=".github/workflows/ci.yml" publish: needs: [ compile, test ] if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') runs-on: ubuntu-latest permissions: contents: read # ADD THIS: Required for actions/checkout@v4 id-token: write # ADD THIS: Required for OIDC steps: - name: Checkout repo uses: actions/checkout@v4 - name: Set up node uses: actions/setup-node@v4 # ADD THIS: Ensure npm 11.5.1 or later is installed for OIDC support - name: Update npm run: npm install -g npm@latest - name: Install pnpm uses: pnpm/action-setup@v4 - name: Install dependencies run: pnpm install - name: Build run: pnpm build # MODIFY THIS: Remove npm config set and env block - name: Publish to npm run: | if [[ ${GITHUB_REF} == *alpha* ]]; then npm publish --access public --tag alpha elif [[ ${GITHUB_REF} == *beta* ]]; then npm publish --access public --tag beta else npm publish --access public fi # Previously had: # run: | # npm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN} # if [[ ${GITHUB_REF} == *alpha* ]]; then # npm publish --access public --tag alpha # elif [[ ${GITHUB_REF} == *beta* ]]; then # npm publish --access public --tag beta # else # npm publish --access public # fi # env: # NPM_TOKEN: ${{ secrets.NPM_TOKEN }} ``` **Key changes:** * Add `permissions` block with `id-token: write` and `contents: read` to the publish job * Add step to update npm to version 11.5.1 or later * Remove the `npm config set` line from the publish step * Remove the `env` block with `NPM_TOKEN` from the publish step If you haven't already, add your CI workflow to `.fernignore` to prevent future generator updates from overwriting your manual changes: ```text title=".fernignore" .github/workflows/ci.yml ``` After verifying the migration works, remove the `NPM_TOKEN` secret from your GitHub repository settings. ### Verify your migration After completing either migration path: 1. **Trigger a workflow run** by creating a GitHub release with an alpha tag (for example, `v1.0.0-alpha`) 2. **Check the workflow logs** to verify the publish step succeeds 3. **Verify provenance** by visiting your package on [npmjs.com](https://npmjs.com) - you should see a provenance badge ### Migration troubleshooting **Common causes:** * Workflow filename doesn't match exactly (must be `ci.yml` with the `.yml` extension) * Missing `id-token: write` or `contents: read` permissions in workflow * npm CLI version is older than 11.5.1 * Using self-hosted runners (not supported) **Solution:** Double-check your trusted publisher configuration on npmjs.com matches your actual workflow file name and verify all requirements are met. If your workflow continues using token-based authentication: * Verify you've removed the `npm config set` line and the `env: NPM_TOKEN` block from the publish step * Check that npm CLI version 11.5.1+ is installed (add the update npm step) * Ensure you're using generator version 3.12.3 or later (if using Path 1) * When using `--local` generation, you need to use Fern CLI version 0.94.0 or later --- # Adding custom code > Learn how to add custom logic, methods, and dependencies to your TypeScript SDK with Fern. Extend generated clients easily. This page covers how to add custom logic, methods, and dependencies to your TypeScript SDK. Before getting started, [read about how Fern SDKs use custom code and learn about the `.fernignore` file](/sdks/overview/custom-code) . ## Adding custom logic To get started adding custom code: ### Create a new file and add your custom logic ```typescript title="src/helper.ts" export function myHelper(): void { return console.log("Hello world!"); } ``` ### Add your file to `.fernignore` ```yaml {3} title=".fernignore" # Specify files that shouldn't be modified by Fern src/helper.ts ``` ### Consume the helper Now your users can consume the helper function by importing it from the SDK. ```typescript import { myHelper } from "sdk/helper"; myHelper(); ``` ## Custom SDK methods Fern also allows you to add custom methods to the SDK itself (e.g. `client.my_method()` ) by inheriting the Fern generated client and then extending it. See an example from Flatfile using this process in their [TypeScript SDK](https://github.com/FlatFilers/flatfile-node) ### Import and extend the generated client First, import the Fern generated client from `../client` and alias it to `FernClient`. Next, extend `FernClient` and add whatever methods you want. ```typescript title="src/wrapper/MyClient.ts" import { MyClient as FernClient } from "../client"; // alias the Fern generated client export class MyClient extends FernClient { // extend the Fern generated client public myHelper(): void { console.log("Hello world!"); } } ``` See an example from Flatfile doing this in their [FlatfileClient](https://github.com/FlatFilers/flatfile-node/blob/main/src/wrapper/FlatfileClient.ts) ### Export the extended client Update your `index.ts` file to export the **extended client** instead of the generated client. ```typescript title="src/index.ts" export { MyClient } from "src/wrapper/MyClient"; // instead of "src/client" ``` See an example [index.ts](https://github.com/FlatFilers/flatfile-node/blob/main/src/index.ts) from Flatfile ### Update `.fernignore` Add both the `wrapper` directory and `index.ts` to `.fernignore`. ```diff title=".fernignore" + src/wrapper + src/index.ts ``` See an example [.fernignore](https://github.com/FlatFilers/flatfile-node/blob/main/.fernignore) from Flatfile ### Consume the method Now your users can consume the helper function by importing it from the SDK. ```typescript client.myHelper() ``` ## Custom dependencies This feature is available only for the [Pro and Enterprise plans](https://buildwithfern.com/pricing). To get started, reach out to [support@buildwithfern.com](mailto:support@buildwithfern.com). To add packages that your custom code requires, update your `generators.yml`. ```yaml {4-7} title="generators.yml" - name: fernapi/fern-typescript-sdk version: 3.46.3 config: extraDependencies: lodash-es: '1.0.0' extraDevDependencies: "@types/lodash-es": '1.0.0' ``` --- # Dynamic authentication > Implement dynamic authentication patterns like short-lived JWT signing in TypeScript SDKs using custom fetcher middleware. Your API may require dynamic authentication where credentials need to be generated or refreshed for each request, such as signing short-lived JWTs or rotating tokens. TypeScript SDKs support this pattern through custom fetcher middleware. ## Custom fetcher middleware The recommended way to implement dynamic authentication in TypeScript SDKs is to use a custom fetcher. This acts as middleware for all requests, allowing you to inject authentication logic in a single place without overriding individual methods. ### How it works When you enable `allowCustomFetcher` in your generator configuration, the generated SDK accepts a `fetcher` parameter in the client options. This fetcher wraps all HTTP requests, giving you a single injection point for authentication logic. ### Example: Short-lived JWT signing Here's how to implement JWT signing with token memoization: ### Enable custom fetcher in generator configuration Add `allowCustomFetcher: true` to your `generators.yml`: ```yaml title="generators.yml" # inside your TypeScript SDK generator - name: fernapi/fern-typescript-sdk config: allowCustomFetcher: true ``` ### Add runtime dependency via packageJson Add the `jsonwebtoken` dependency using the `packageJson` config option so it gets merged into the generated package.json: ```yaml title="generators.yml" # inside your TypeScript SDK generator - name: fernapi/fern-typescript-sdk config: packageJson: dependencies: jsonwebtoken: "^9.0.0" devDependencies: "@types/jsonwebtoken": "^9.0.0" ``` See the [TypeScript configuration page](/sdks/generators/typescript/configuration#packagejson) for all available packageJson options. ### Create a custom fetcher with JWT signing Create a fetcher function that wraps the default fetcher and injects JWT authentication: ```typescript title="src/wrapper/jwtFetcher.ts" import * as jwt from "jsonwebtoken"; import { fetcher as defaultFetcher, type FetchFunction } from "../core/fetcher"; export function createJwtFetcher(privateKey: string): FetchFunction { // Cache token to avoid regenerating on every request let cachedToken: { value: string; expiresAt: number } | undefined; return async (args) => { const now = Math.floor(Date.now() / 1000); // Regenerate token if expired or about to expire (within 2 seconds) if (!cachedToken || cachedToken.expiresAt - 2 <= now) { const payload = { iat: now, exp: now + 15, // Token valid for 15 seconds }; const token = jwt.sign(payload, privateKey, { algorithm: "RS256" }); cachedToken = { value: token, expiresAt: payload.exp }; } // Inject JWT into request headers const headers = { ...(args.headers ?? {}), Authorization: `Bearer ${cachedToken.value}`, }; // Call the default fetcher with modified headers return defaultFetcher({ ...args, headers }); }; } ``` ### Create a wrapper client Extend the generated client to use the custom fetcher: ```typescript title="src/wrapper/PlantStoreClient.ts" import { PlantStoreClient as FernClient } from "../Client"; import { createJwtFetcher } from "./jwtFetcher"; // Infer the exact options type from the generated client's constructor type FernClientOptions = ConstructorParameters[0]; // Accept all options except 'fetcher', and add our 'privateKey' type Options = Omit & { privateKey: string }; export class PlantStoreClient extends FernClient { constructor(options: Options) { // Extract privateKey and pass all other options to the parent const { privateKey, ...clientOptions } = options; super({ ...clientOptions, fetcher: createJwtFetcher(privateKey), }); } } ``` This pattern uses `ConstructorParameters` to infer the exact options type from the generated client, ensuring compatibility with all client options (headers, timeoutInSeconds, maxRetries, etc.) without hardcoding them. This keeps the wrapper future-proof as the generator adds new options. ### Export the wrapper client Update your `index.ts` to export the wrapper instead of the generated client: ```typescript title="src/index.ts" export { PlantStoreClient } from "./wrapper/PlantStoreClient"; export * from "./api"; // Export types ``` ### Add to `.fernignore` Protect your custom code from being overwritten: ```diff title=".fernignore" + src/wrapper + src/index.ts ``` Use `.fernignore` to preserve your custom wrapper files, not to manage package.json. Add dependencies via the `packageJson` config option in generators.yml instead. ### Use the client Users can use the client with automatic JWT signing on all requests: ```typescript import { PlantStoreClient } from "plant-store-sdk"; const client = new PlantStoreClient({ privateKey: process.env.PRIVATE_KEY, environment: "https://api.plantstore.com", }); // JWT is automatically signed and injected for each request const plant = await client.plants.get("monstera-123"); const newPlant = await client.plants.create({ name: "Fiddle Leaf Fig", species: "Ficus lyrata" }); ``` ## Other authentication patterns This same pattern works for other dynamic authentication scenarios: * **OAuth token refresh**: Automatically refresh expired access tokens before each request * **HMAC (Hash-based Message Authentication Code) signing**: Sign requests with HMAC signatures based on request content * **Rotating API keys**: Switch between multiple API keys based on rate limits * **Time-based tokens**: Generate tokens that include timestamps or nonces ## Important considerations ### Custom fetcher requirements * **Generator configuration**: The `allowCustomFetcher` option must be enabled in your `generators.yml` for the `fetcher` parameter to be available in `BaseClientOptions` * **Import path**: Import the default fetcher from `../core/fetcher` (or the appropriate path in your generated SDK) to wrap it with your custom logic * **Preserve all arguments**: When wrapping the default fetcher, ensure you pass through all arguments to maintain compatibility with the SDK's internal behavior ### Security considerations * **Server-side only**: Never expose private keys in browser environments. JWT signing with private keys should only be done in server-side code (Node.js, Deno, Bun) * **Secure key storage**: Never hardcode private keys; use environment variables or secure key management systems * **Avoid double authentication**: If your API already uses bearer token authentication in the Fern definition, be careful not to override the existing `Authorization` header. Consider using a different header name or conditionally setting the header ### Performance and concurrency * **Token memoization**: Cache tokens to avoid regenerating them on every request. The example above caches tokens and refreshes them 2 seconds before expiration * **Thread safety**: The memoization pattern shown is safe for concurrent requests in JavaScript's single-threaded event loop, but be mindful of race conditions in other environments * **Grace period**: Refresh tokens slightly before they expire (e.g., 2 seconds early) to avoid edge cases where a token expires during request processing ### Header merging * **Preserve existing headers**: When injecting authentication headers, always spread existing headers to avoid overwriting headers set by the SDK or user * **Header precedence**: Headers are merged in order: SDK defaults → client options → request options → custom fetcher. Your custom fetcher runs last and can override previous headers ### Time synchronization * **Clock drift**: Be aware of potential clock drift between your client and server. Consider adding tolerance to your token expiration checks * **Timestamp precision**: Use Unix timestamps (seconds since epoch) for `iat` and `exp` claims to match JWT standards ## Best practices * **Cache tokens appropriately**: Balance between security (shorter token lifetime) and performance (less frequent regeneration) * **Handle errors gracefully**: Implement retry logic for authentication failures and token refresh errors * **Test thoroughly**: Ensure your wrapper handles all edge cases, including concurrent requests, token expiration, and network failures * **Monitor token usage**: Log token generation and refresh events to help debug authentication issues in production ## See also * [Adding custom code](/sdks/generators/typescript/custom-code) - TypeScript-specific customization guide * [TypeScript configuration](/sdks/generators/typescript/configuration) - Full list of configuration options --- # TypeScript serde layer > Learn how to enable the TypeScript serde layer in Fern SDK generator to transform API field names to camelCase and validate requests at runtime. Fern's TypeScript SDK generator includes an optional serde layer that determines whether the generated SDK matches your original API naming conventions (snake\_case vs. camelCase, case-sensitive fields) or follows TypeScript conventions. This serde layer is controlled by the `noSerdeLayer` option. By default, the serde layer is **disabled** (`noSerdeLayer: true`), meaning field names are preserved exactly as they appear in your API specification. ## When to enable the serde layer ```yaml title="generators.yml" {7} groups: ts-sdk: generators: - name: fernapi/fern-typescript-sdk version: 3.46.3 config: noSerdeLayer: false # Enable serde layer ``` When you turn on the serde layer, (`noSerdeLayer: false`), the TypeScript SDK generator includes custom serialization code that: * Transforms all property names from your API to camelCase * Validates requests and responses at runtime * Supports complex types like `Date` and `Set`. Enable the serde layer when you want idiomatic TypeScript conventions and don't have case-sensitive field conflicts. Keep it disabled when your API has fields that differ only by casing or when you need exact field name preservation. ## Additional configuration options Several configuration options work alongside an enabled serde layer: * `skipResponseValidation` disables the serde layer's runtime validation while keeping its transformation features * `allowExtraFields` permits properties not defined in your schema. * `useBigInt` enables custom JSON handling to preserve large number precision. These options only take effect when the serde layer is enabled (`noSerdeLayer: false`), as they require the custom serialization infrastructure. ```yaml title="generators.yml" {7-10} groups: ts-sdk: generators: - name: fernapi/fern-typescript-sdk version: 3.46.3 config: noSerdeLayer: false # Enable serde layer skipResponseValidation: true # Disable runtime validation errors allowExtraFields: true # Allow undefined fields in responses useBigInt: true # Preserve precision for large numbers ``` For the complete list of all TypeScript configuration options, go to [TypeScript configuration](/sdks/generators/typescript/configuration). --- # January 30, 2026 ## 3.46.3 **`(chore):`** Update oxfmt to 0.27.0, oxlint to 1.42.0, and oxlint-tsgolint to 0.11.4. ## 3.46.2 **`(fix):`** Fix TypeScript circular reference error (TS7022/TS2456) when generating enums with visitor utilities enabled. The enum type alias now references an intermediate `Values` const instead of using `Omit`, which avoids the circular reference in the type's own initializer. --- # January 29, 2026 ## 3.46.1 **`(fix):`** Fix `outputSrcOnly` not working with `local-file-system` output mode when the organization has `selfHostedSdKs` enabled. The `outputSrcOnly` check now takes priority over `shouldGenerateFullProject`, ensuring that when a user explicitly sets `outputSrcOnly: true`, only the src contents are output without the full project structure. ## 3.46.0 **`(feat):`** Add `outputSrcOnly` configuration option that outputs only the contents of the `src/` directory directly to the destination path, without the `src/` wrapper directory. This is useful when you want to integrate the generated source files directly into another project without the extra directory nesting. The option takes priority over `outputSourceFiles` when both are enabled. --- # January 26, 2026 ## 3.45.1 **`(fix):`** Remove check if body is `null` or `undefined`. If `null`, it is valid JSON `null`, and if `undefined`, it handles correctly to not have a body. ## 3.45.0 **`(feat):`** Add support for additional query parameters in WebSocket connections. The `ConnectArgs` interface now includes an optional `queryParams` property that allows users to pass additional query parameters that get merged into the WebSocket URL alongside any channel-defined query parameters. ## 3.44.2 **`(fix):`** Fix README pagination section being included even when the SDK has no autopaginated endpoints. The pagination section is now only included in the README when there is at least one endpoint with pagination defined. --- # January 22, 2026 ## 3.44.1 **`(fix):`** Fix optional query parameters with date/datetime types throwing serialization errors when undefined. Previously, optional query parameters that were named types aliasing Date (like `before?: Before` where `Before = Date`) would call `jsonOrThrow` unconditionally, causing "Expected Date object. Received undefined" errors when the parameter was omitted. Now the generator adds a null check for optional date/datetime query parameters, matching the behavior already used for object-type query parameters. --- # January 21, 2026 ## 3.44.0 **`(feat):`** Enable forward compatible enums when the serde layer is enabled. Previously, the `enableForwardCompatibleEnums` option only worked when `noSerdeLayer` was true. Now enum types include `| string` regardless of the serde layer setting when `enableForwardCompatibleEnums` is enabled, allowing TypeScript SDKs to accept unrecognized enum values from APIs. --- # January 14, 2026 ## 3.43.13 **`(fix):`** Fix nullable enum query parameters to be dropped when undefined is passed instead of being sent as null. Previously, nullable query parameters like `role: nullable` would generate code that converted undefined to null, causing the parameter to be included in the request as an empty value. Now undefined values remain undefined and are properly dropped from the query string. ## 3.43.12 **`(fix):`** Fix passthrough() function to only include truly unknown/extra properties in the result. Previously, when a type had `additionalProperties: true` and used property name mapping (e.g., snake\_case to camelCase), the passthrough would spread both the original raw object and the transformed value, resulting in duplicate properties with both naming conventions. Now the passthrough correctly filters out known properties before spreading, ensuring only extra properties that aren't part of the schema definition are included. --- # January 13, 2026 ## 3.43.11 **`(chore):`** Update linters and formatters to latest versions. ## 3.43.10 **`(chore):`** Update Dockerfile to only pre-cache for the default configuration options to reduce image size from 1.45GB to 823MB. The following dependencies are no longer pre-cached: * jest * @types/jest * node-fetch * @types/node-fetch * qs * @types/qs * readable-stream * @types/readable-stream * form-data * formdata-node * jest-environment-jsdom * prettier * oxfmt * oxlint * oxlint-tsgolint * ts-jest * form-data-encoder * fetch-mock-jest Additionally, the Dockerfile only pre-caches using pnpm, removing duplicate yarn cache. ## 3.43.9 **`(chore):`** Update Dockerfile to use the latest generator-cli with improve reference.md generation. --- # January 9, 2026 ## 3.43.8 **`(fix):`** Fix wire test mock server to ignore cursor mismatches in pagination tests. When pagination tests call `getNextPage()`, the SDK correctly sends the cursor from the response, but the mock server was rejecting the request because the cursor didn't match the original request. The mock server now accepts an `ignoredFields` option to specify which fields to ignore during request body matching. The test generator extracts pagination cursor field names from the IR and passes them to the mock server at code generation time. ## 3.43.7 **`(fix):`** Support `bytes` argument type and custom method names for websocket messages. --- # January 8, 2026 ## 3.43.6 **`(fix):`** Fix fetcher tests to use `.trim()` for platform-agnostic line ending comparisons. This resolves test failures on Windows where files have CRLF line endings instead of LF. --- # January 7, 2026 ## 3.43.5 **`(fix):`** Fix GitHub repository URL format in package.json to use `git+https://` format, ensuring local generation output matches remote generation. --- # January 6, 2026 ## 3.43.4 **`(fix):`** Fix export of inline enum const values from request types. Previously, request types with inline enums (defined directly in OpenAPI schemas) were exported using `export type { ... }` which only exports the type, not the runtime const values. SDK consumers couldn't access enum values like `ConvertRequest.Resource.Auto` at runtime. Now request types are exported using `export { ... }` which exports both the type and the const. --- # January 5, 2026 ## 3.43.3 **`(fix):`** Fix repository URL format in package.json for self-hosted GitHub configurations to use full https URL format matching Fiddle's output. --- # December 22, 2025 ## 3.43.2 **`(chore):`** Simplify optional query parameter handling by removing unnecessary null/undefined checks. Query parameters can now be assigned directly without wrapping in if-statements, as it's safe to pass null or undefined values to query string parameters. **`(chore):`** Use optional chaining (?.) for optional query parameters that require method calls like toISOString() for dates, instead of ternary expressions. **`(chore):`** Skip unnecessary .map() calls for list query parameters when the item type doesn't need transformation (e.g., string arrays). Also skip the Array.isArray check entirely when both scalar and array branches would produce identical code. **`(chore):`** Refactor query parameter generation to use object initializers instead of sequential property assignments. This produces cleaner, more idiomatic TypeScript code where all query parameters are defined in a single object literal. ## 3.43.1 **`(fix):`** Fix bug where ts-morph would generate incorrect code when `Accept: */*` header would be defined as a parameter in OpenAPI. The old generated code would generate broken JSDoc comments with invalid syntax. **`(chore):`** Optimize generated SDK code by eliminating unnecessary `.toString()` calls on primitive types in headers and query parameters. The generator now only stringifies types that require it (dates/datetimes) while using primitives like strings, numbers, booleans, and UUIDs directly. **`(fix):`** Add `createNumericLiteralSafe` utility to properly handle negative numbers in generated code examples, ensuring compatibility with newer TypeScript/ts-morph versions that require prefix unary expressions. **`(fix):`** Add support for nullable types in query parameter type resolution, properly unwrapping both optional and nullable containers when determining primitive and object types. **`(chore):`** Simplify header and query parameter types from verbose union types to `Record` for more flexible and less complex type signatures in generated SDKs. --- # December 19, 2025 ## 3.43.0 **`(feat):`** Add support for endpoint-level security configuration via new `endpoint-security` auth requirement type. This allows APIs to specify different authentication schemes per endpoint, enabling fine-grained control over which endpoints accept which auth methods (e.g., some endpoints use Bearer, others use API Key). **`(feat):`** Add `RoutingAuthProvider` that dynamically routes authentication requests based on endpoint metadata. When `auth: endpoint-security` is configured, the SDK uses endpoint metadata to determine which auth provider to use for each request. `AnyAuthProvider` remains the default for `auth: any` configurations. **`(chore):`** Refactor all auth providers to use factory pattern with static `createInstance` methods. This enables type-safe provider instantiation, conditional provider creation based on available credentials, and better error messages with scheme-specific context. **`(feat):`** Add conditional wrapper properties for auth options to prevent naming conflicts when multiple auth schemes are configured (e.g., `options.bearer.token` vs `options.oauth.token`). **`(chore):`** Make `endpointMetadata` parameter optional in `EndpointSupplier.get()` to allow auth providers to handle endpoints without metadata gracefully while maintaining backward compatibility. --- # December 18, 2025 ## 3.42.8 **`(fix):`** Fix wire test generation for paginated endpoints. The test generator now correctly uses wire format (snake\_case) when checking JSON examples for pagination results, and properly handles examples with null or missing cursor fields by skipping `hasNextPage()` assertions. ## 3.42.7 **`(chore):`** Add sdkVersion as a top-level field in the generated metadata.json file. --- # December 17, 2025 ## 3.42.6 **`(fix):`** Fix wire test generation for OAuth endpoints with reference request bodies. ## 3.42.5 **`(fix):`** Add fallback OAuth credentials for wire tests when examples don't include explicit auth values. --- # December 16, 2025 ## 3.42.4 **`(fix):`** Fix bug where request wrapper was set as body when the body property inside the request wrapper should've been used. This only affects a specific combination of feature flags: * `inline-path-parameters: true` on the API spec settings * `inlinePathParameters: false` on the generator config ## 3.42.3 **`(fix):`** Fix wire test generation: filter out headers with null/undefined values to prevent invalid assertions, and allow empty form body in mock server when expected body is empty. ## 3.42.2 **`(fix):`** Fix property access for file upload request parameters with hyphenated or special character names by using bracket notation instead of dot notation. ## 3.42.1 **`(fix):`** Fix OAuth token handling for optional expires\_in field with default fallback. ## 3.42.0 **`(feat):`** Add normalized client options and request options as a parameter to custom pagination. This allows SDK authors to access the client options (including auth provider) when implementing custom pagination logic. --- # December 15, 2025 ## 3.41.0 **`(feat):`** Improve the custom pagination code. --- # December 12, 2025 ## 3.40.0 **`(feat):`** Run `npm pkg fix` after saving package.json to disk to normalize the package.json file. This is enabled by default and can be disabled by setting `skipNpmPkgFix: true` in the generator config. ## 3.39.3 **`(fix):`** Fix missing information in generated package.json. --- # December 10, 2025 ## 3.39.2 **`(fix):`** Fix reference.md generation for APIs with multiple root-level endpoints. Previously, only the last root endpoint appeared in the reference documentation because `addRootSection()` was called inside the endpoint loop, replacing the root section each time. The fix moves section creation before the endpoint loop, ensuring all root endpoints are included and removing the empty `##` section header that was being generated. ## 3.39.1 **`(fix):`** Fix wire tests for paginated endpoints to expect an empty array `[]` instead of `undefined` when `response.data` is not present. This aligns with the paginator's behavior which uses `?? []` to return an empty array when the data property is undefined. --- # December 9, 2025 ## 3.39.0 **`(feat):`** Add support for custom pagination with a dedicated `CustomPager` class, similar to the C# SDK generator. The `CustomPager` class provides: * A `CustomPagerParser` callback type that SDK authors implement to define pagination logic * Support for both forward (`getNextPage`) and backward (`getPreviousPage`) pagination * `AsyncIterable` implementation for ergonomic consumption with `for await...of` * Access to raw response data via `response` and `rawResponse` properties The generated endpoint returns a `CustomPager` with a default parser that extracts items from the configured results property and sets `hasNextPage`/`hasPreviousPage` to `false`. SDK authors who need custom pagination logic can create their own wrapper/factory that calls `CustomPager.create()` with their own `CustomPagerParser` implementation. ## 3.38.3 **`(chore):`** Sort imports and exports in generated TypeScript SDK files for consistent, deterministic output. This eliminates the need to rely on formatters like prettier, biome, or oxfmt to order imports and exports. ## 3.38.2 **`(chore):`** Pre format and lint as is files and core utilities. ## 3.38.1 **`(fix):`** `hasNextPage` employs the default for the `step` attribute on offset-based pagination endpoints if it's set. ## 3.38.0 **`(feat):`** The `oauthTokenOverride` feature flag has been removed and is now always enabled. OAuth token override allows users to skip the OAuth flow by providing a pre-generated bearer token directly. This feature is now the default behavior and no longer requires configuration. --- # December 8, 2025 ## 3.37.4 **`(chore):`** The README now demonstrates how to pass custom headers to both the client constructor and individual endpoint invocations. ## 3.37.3 **`(chore):`** Update generator-cli to 0.5.0. ## 3.37.2 **`(chore):`** Update oxfmt to 0.17.0, oxlint to 1.32.0, and oxlint-tsgolint to 0.8.4. ## 3.37.1 **`(fix):`** Fixed a possible type issue in Fetcher.test.ts. --- # December 5, 2025 ## 3.36.0 **`(feat):`** Refactor auth options to be defined in individual AuthProvider classes instead of directly in BaseClientOptions. BaseClientOptions is now a type alias that intersects with the auth provider's AuthOptions interface. This improves code organization and makes auth options more discoverable. --- # December 4, 2025 ## 3.37.0 **`(feat):`** Add support for OAuth token override, allowing users to skip the OAuth flow by providing a pre-generated bearer token directly. This is useful when users already have a valid token and don't need to go through the OAuth client credentials flow. To enable this feature, add the `oauthTokenOverride` configuration to your *generators.yml* file: ```yaml --- # In generators.yml groups: generators: - name: fernapi/fern-typescript-sdk config: oauthTokenOverride: true ``` Users can then instantiate the client with either OAuth credentials or a pre-generated token: ```ts // Option 1: OAuth flow (existing behavior) const client = new Client({ clientId: "YOUR_CLIENT_ID", clientSecret: "YOUR_CLIENT_SECRET", ... }); // Option 2: Direct bearer token override (new capability) const client = new Client({ token: "my-pre-generated-bearer-token", ... }); ``` ## 3.35.9 **`(fix):`** Fix generated error classes to correctly set the prototype chain, capture stack traces, and set the error name so `instanceof` checks behave as expected. Error classes now use `new.target.prototype` instead of the static class name for `Object.setPrototypeOf`, conditionally call `Error.captureStackTrace` for V8 environments, and set `this.name` dynamically. --- # December 2, 2025 ## 3.35.8 **`(chore):`** Added `writeUnitTests` config option to control unit test generation. Both `writeUnitTests` and `generateWireTests` now default to `true` and operate independently. ## 3.35.7 **`(fix):`** Wire tests are now controlled entirely by the `generateWireTests` custom config option, no longer falling back to the CLI's `writeUnitTests` flag. ## 3.35.6 **`(chore):`** Remove noisy IR services log from inferred auth provider generation. --- # December 1, 2025 ## 3.35.5 **`(fix):`** Fix WebSocket client to only generate auth code when the channel has `auth: true`. Previously, auth code was generated whenever the API had auth schemes defined, even if the WebSocket channel didn't require auth. This caused a mismatch where the client used `NormalizedClientOptions` but the connect method tried to access `authProvider`. ## 3.35.4 **`(fix):`** Centralize non-status code error handling to a single reusable function in the generated SDK. This will reduce the amount of duplicated code and make it easier to maintain consistent error handling across all endpoints. ## 3.35.3 **`(fix):`** Fix WebSocket client `ConnectArgs` interface to correctly handle `allow-multiple: true` query parameters. Previously, query parameters with `allow-multiple: true` were typed as `T | undefined` instead of `T | T[] | undefined`. ## 3.35.2 **`(chore):`** \* Add --frozen-lockfile flag to pnpm and yarn install commands in generated ci.yml workflow. * Update actions/checkout to v6 and actions/setup-node to v6 in generated ci.yml workflow. ## 3.35.1 **`(fix):`** Fix WebSocket query parameter destructuring for property names that are not valid JavaScript identifiers (e.g., `language-code`). The generated code now correctly uses renaming syntax in destructuring (e.g., `const { "language-code": languageCode } = args;`). --- # November 30, 2025 ## 3.34.3 **`(fix):`** Improve React Native compatibility in the SDK runtime and fetcher: * Move React Native detection before Node.js detection since React Native may have a process polyfill * Use `ReturnType` instead of `NodeJS.Timeout` for better cross-platform compatibility * Remove `ResponseWithBody` type guard that incorrectly failed in React Native environments where `response.body` may be null * Update `BinaryResponse` type to use Response types directly for better compatibility * Add structured error responses with `body-is-null` reason for SSE and streaming endpoints when `response.body` is unavailable * Simplify JSON parsing error handling to return consistent error structure with `non-json` reason --- # November 26, 2025 ## 3.34.2 **`(fix):`** Avoid infinite recursion when an auth client is incorrectly configured to use itself for authentication. To circumvent the infinite recursion, auth providers receive a no-op auth provider when constructing themselves. ## 3.34.1 **`(fix):`** Remove error on null config in README generation. --- # November 23, 2025 ## 3.34.0 **`(feat):`** Implement auth provider architecture for all auth schemes, replacing inline auth logic. This reduces code duplication and improves maintainability. Each auth scheme now uses a dedicated `AuthProvider` class that implements the `AuthProvider` interface. The `AnyAuthProvider` class is used when multiple auth schemes are defined. --- # November 21, 2025 ## 3.33.1 **`(fix):`** Remove using generator-cli to push to GitHub for self-hosted SDKs; this is now handled in the local workspace runner. --- # November 20, 2025 ## 3.35.0 **`(fix):`** Fix validateAndTransformExtendedObject to add null/undefined guard. ## 3.33.0 **`(feat):`** Implement auth provider architecture for basic auth, matching the pattern established by inferred auth. Basic auth now uses a dedicated `BasicAuthProvider` class that implements the `AuthProvider` interface, replacing inline auth logic. ## 3.32.1 **`(fix):`** Add contents:read permission to generated publish workflow for OIDC authentication to fix actions/checkout\@v4 requirements. --- # November 19, 2025 ## 3.32.0 **`(feat):`** Add support for OAuth and inferred auth in generated wire tests. **`(feat):`** Respect the `auth: false` at the endpoint level when generating the endpoint function. ## 3.31.5 **`(chore):`** Include subpackage exports in generated README.md if `generateSubpackageExports` is enabled. --- # November 18, 2025 ## 3.31.4 **`(fix):`** Default to mock an endpoint once when using `msw` for wire tests. ## 3.31.3 **`(fix):`** Generate wire tests with `maxRetries` set to 0. ## 3.31.2 **`(chore):`** Bump generator CLI version to publish new Docker image. --- # November 17, 2025 ## 3.31.1 **`(fix):`** Fix generator to not generate CONTRIBUTING.md file if config.whitelabel is true. ## 3.31.0 **`(feat):`** Add `generateSubpackageExports` configuration option to enable direct imports of subpackage clients. This allows JavaScript bundlers to tree-shake and include only the imported subpackage code, resulting in much smaller bundle sizes. Example: ```ts import { BarClient } from '@acme/sdk/foo/bar'; const client = new BarClient({...}); ``` To enable this feature, add the following configuration to your *generators.yml* file: ```yaml --- # In generators.yml groups: generators: - name: fernapi/fern-typescript-sdk config: generateSubpackageExports: true ``` --- # November 14, 2025 ## 3.30.0 **`(feat):`** Add `offsetSemantics` flag, which changes how the `step` attribute in `x-fern-pagination` is interpreted. When `offsetSemantics` is `item-index` (the default), offset is understood as an item index that increases by the number of entities fetched. When `offsetSemantics` is `page-index`, offset is understood as a page index that increases by 1 each time. --- # November 13, 2025 ## 3.29.2 **`(fix):`** Improve SDK generation performance. ## 3.29.1 **`(fix):`** When generating `hasNextPage`, use `Math.Floor` to ensure an integer comparison against the number of entities. --- # November 11, 2025 ## 3.29.0 **`(feat):`** Add `parameterNaming` configuration option to control how parameter names are generated in the SDK. The available options are: * `originalName`: Use the original name from the OpenAPI spec. * `wireValue`: Use the wire value from the OpenAPI spec, falling back to the original name if not present. * `camelCase`: Convert the name to camelCase. * `snakeCase`: Convert the name to snake\_case. * `default`: Use the default naming strategy. ## 3.28.11 **`(fix):`** Do not generate a *snippet-templates.json* file in the generated TypeScript SDK. ## 3.28.12 **`(fix):`** Include more files and folders in .npmignore: * .mock * .fern * dist * scripts * jest.config.\* * vitest.config.\* **`(fix):`** Only generate *.npmignore* when `useLegacyExports: true`. When `useLegacyExports: false`, we generate a *package.json* with `"files"` field which makes *.npmignore* redundant. --- # November 10, 2025 ## 3.28.10 **`(fix):`** Set `Accept` header for JSON (`application/json`), text (`text/plain`), and other (`*/*`) response types. This ensures that the `Accept` header is set consistently across runtimes. Unlike all other runtimes, Cloudflare Workers and Vercel Edge Runtime do not set a default `Accept` header in their `fetch` implementations. ## 3.28.9 **`(fix):`** Fix `Error._visit` to pass the correct type (`core.Fetcher.Error`) to the `_other` callback. ## 3.28.8 **`(fix):`** Clean up imports for requestWithRetries.test.ts. --- # November 8, 2025 ## 3.28.7 **`(fix):`** Fix circular type alias errors (TS2456) in undiscriminated unions containing self-recursive Record types where the value is a union of itself with null and/or undefined. --- # November 7, 2025 ## 3.28.6 **`(fix):`** Fix circular type alias errors (TS2456) in undiscriminated unions containing self-recursive Record types. --- # November 6, 2025 ## 3.28.5 **`(fix):`** Fix issue where logs were logged even when the respective log level was disabled. **`(chore):`** Add tests for logging and the fetcher's redaction functionality. **`(chore):`** Improve unit test performance and refactor code to reduce duplication. ## 3.28.4 **`(fix):`** Fix a compilation error when a websocket channel has no send or receive messages. ## 3.28.3 **`(fix):`** Fix local GitHub generation to match remote generation. ## 3.28.2 **`(fix):`** Fix inconsistent path parameter casing in the WebSocket connect options. The casing now follows the same rules as other HTTP path parameters: * `retainOriginalCasing: true`: use the original casing from the OpenAPI spec, regardless of the `noSerdeLayer` setting. * `noSerdeLayer: true`: use the original casing from the OpenAPI spec. * `noSerdeLayer: false`: use camelCase for path parameters. --- # November 5, 2025 ## 3.28.1 **`(fix):`** Always use vitest.config.mts for consistency across all generated SDKs. This ensures Vitest v3 can load the config as ESM in both CommonJS and ESM packages. ## 3.27.0 **`(feat):`** Add support for variables in wire tests. ## 3.26.0 **`(feat):`** Include `"dependencies": {}` in package.json when generating a TypeScript SDK without dependencies. --- # November 4, 2025 ## 3.28.0 **`(feat):`** Added Generation Metadata file to output. ## 3.25.0 **`(feat):`** Add support for logging to the generated SDK. Users can configure the logger by passing in a `logging` object to the client options. ```ts import { FooClient, logging } from "foo"; const client = new FooClient({ logging: { level: logging.LogLevel.Info, // LogLevel.Info is the default logger: new logging.ConsoleLogger(), // ConsoleLogger is the default silent: false, // true is the default, set to false to enable logging } }); ``` The `logging` object can have the following properties: * `level`: The log level to use. Defaults to `logging.LogLevel.Info`. * `logger`: The logger to use. Defaults to `logging.ConsoleLogger`. * `silent`: Whether to silence the logger. Defaults to `true`. The `level` property can be one of the following values: * `logging.LogLevel.Debug` * `logging.LogLevel.Info` * `logging.LogLevel.Warn` * `logging.LogLevel.Error` To provide a custom logger, users can pass in a custom logger implementation that implements the `logging.ILogger` interface. --- # November 3, 2025 ## 3.24.0 **`(feat):`** Add support for forward-compatible enums. To enable forward-compatible enums, add the following configuration to your *generators.yml* file: ```yaml --- # In generators.yml groups: generators: - name: fernapi/fern-typescript-sdk config: enableForwardCompatibleEnums: true ``` ## 3.23.0 **`(feat):`** Add support for bytes download responses. ## 3.22.0 **`(feat):`** Add support for oxfmt as the formatter. This is a beta feature and not officially supported yet. ## 3.21.0 **`(feat):`** Add support for oxlint as the linter. This is a beta feature and not officially supported yet. ## 3.20.0 **`(feat):`** Implement base and extend properties in discriminated union examples. ## 3.19.1 **`(fix):`** `mergeHeaders()` and `mergeOnlyDefinedHeaders()` are now case-insensitive. ## 3.19.0 **`(feat):`** Add support for application/x-www-form-urlencoded request bodies. ## 3.18.0 **`(feat):`** Users can now pass in a custom `fetch` function to the client options. --- # October 31, 2025 ## 3.17.1 **`(fix):`** `hasNextPage()` now factors in `offset.step` if provided for offset-based pagination such that `hasNextPage` now returns `false` if the returned page was not as large as requested. --- # October 29, 2025 ## 3.17.0 **`(feat):`** Add `Page` to the top-level `exports.ts` files, which allows for `import { Page } from '...';` to work. Remove `Pageable`, and use only `core.Page` for pagination everywhere. ## 3.16.0 **`(feat):`** Generate a CONTRIBUTING.md file. ## 3.15.0 **`(feat):`** Export types for `ReconnectingWebSocket`, `ReconnectingWebSocket.Event`, `ReconnectingWebSocket.CloseEvent`, and `ReconnectingWebSocket.ErrorEvent`. ## 3.14.0 **`(feat):`** Expose the underlying response on the `Page` type. --- # October 28, 2025 ## 3.13.0 **`(feat):`** Improve pnpm and yarn caching in generator Docker images. ## 3.12.3 **`(fix):`** Fix `.github/workflows/ci.yml` file when using OIDC for npm publishing. ## 3.12.2 **`(fix):`** Add streaming tests; fix custom message terminators in streams; fix multi-byte character handling across chunk breaks in streams. ## 3.12.1 **`(chore):`** Update Biome to 2.3.1 --- # October 21, 2025 ## 3.12.0 **`(feat):`** Add support for [publishing to npmjs.org using OIDC from GitHub Actions](https://docs.npmjs.com/trusted-publishers). To use OIDC for publishing to npmjs.org, you need to follow two steps: 1. Follow the instructions in ["Step 1: Add a trusted publisher on npmjs.com"](https://docs.npmjs.com/trusted-publishers#step-1-add-a-trusted-publisher-on-npmjscom). 2. Set the `output.token` field to `OIDC` in *generators.yml* to enable this feature: ```yml # In generators.yml groups: ts-sdk: generators: - name: fernapi/fern-typescript-sdk output: location: npm package-name: your-package-name token: OIDC # previously this would be set to something like ${NPM_TOKEN} ... ``` This will take care of ["Step 2: Configure your CI/CD workflow"](https://docs.npmjs.com/trusted-publishers#step-2-configure-your-cicd-workflow). For local generation, you'll need Fern CLI version 0.94.0 or later. **`(feat):`** Update GitHub Actions `setup-node` action to v4 in the generated CI workflow. ## 3.11.1 **`(fix):`** Generate streaming response section in README.md for streaming response endpoints. ## 3.11.0 **`(feat):`** Add `linter` and `formatter` configuration options to configure code linters and formatters for the generated SDK. * `linter`: * `biome`: Use Biome as the code linter. This is the default. * `none`: Do not include a code linter. * `formatter`: * `biome`: Use Biome as the code formatter. This is the default. * `prettier`: Use Prettier as the code formatter. For consistency, the *package.json* scripts will always include the following scripts: * `lint`: Run the configured linter. * `lint:fix`: Run the configured linter with auto-fix. * `format`: Run the configured formatter. * `format:check`: Run the configured formatter in check mode. * `check`: Run both the linter and formatter in check mode. * `check:fix`: Run both the linter and formatter with auto-fix. When the `linter` is set to `none`, `lint` and `lint:fix` scripts will echo a message indicating that no linter is configured. --- # October 20, 2025 ## 3.10.0 **`(feat):`** Generate file upload section in README.md for multipart-form file uploads. --- # October 17, 2025 ## 3.9.3 **`(fix):`** Fix a compilation error when a path parameter is nullable or optional. ## 3.9.2 **`(fix):`** Match the logic in wire test generation where the static example generation omits the request parameter for empty objects when optional. This fixes some wire tests that were failing due to mismatched request bodies. **`(fix):`** Return `undefined` when passing in `undefined` to `toJson` when `useBigInt` is enabled. --- # October 16, 2025 ## 3.9.1 **`(fix):`** Improve the performance of JSON serialization and parsing when `useBigInt` is enabled. --- # October 14, 2025 ## 3.9.0 **`(feat):`** Add support for the `Uploadable.FromPath` and `Uploadable.WithMetadata` types to upload files with metadata to multipart-form endpoints. Users can configure metadata when uploading a file to a multipart-form upload endpoint using the `Uploadable.WithMetadata` type: ```typescript import { createReadStream } from "fs"; await client.upload({ file: { data: createReadStream("path/to/file"), filename: "my-file", contentType: "audio/mpeg", }, otherField: "other value", }); ``` The `filename`, `contentType`, and `contentLength` properties are optional. Alternatively, users can use the `Uploadable.FromPath` type to upload directly from a file path: ```typescript await client.upload({ file: { path: "path/to/file", filename: "my-file", contentType: "audio/mpeg", }, otherField: "other value", }); ``` The metadata is used to set the `Content-Type` and `Content-Disposition` headers. If not provided, the client will attempt to determine them automatically. ``` ``` --- # October 13, 2025 ## 3.7.3 **`(fix):`** Fix default request parameter value unwrapping for `nullable<>`. --- # October 10, 2025 ## 3.7.2 **`(fix):`** Include `extra-properties` (aka. `additionalProperties`) when generating examples for objects and inlined request bodies. **`(fix):`** Allow arbitrary properties in inlined request bodies when `extra-properties` (aka. `additionalProperties`) is set to true. --- # October 9, 2025 ## 3.7.1 **`(fix):`** Filter out `undefined` from lists, maps, sets, and object properties when generating examples. **`(fix):`** Restore missing test scripts in package.json when using `useLegacyExports: true`. --- # October 8, 2025 ## 3.8.0 **`(feat):`** Use Biome for formatting instead of Prettier, and also use Biome to check (fix) the generated code. ## 3.7.0 **`(feat):`** Generate a `BaseClientOptions`, `BaseRequestOptions`, and `BaseIdempotentRequestOptions` interface and extend from these in the generated client `Options`, `RequestOptions`, and `IdempotentRequestOptions` interfaces. This reduces a large amount of duplicate code in the generated SDK. ## 3.6.1 **`(fix):`** Add missing test scripts when `bundle: true`. ## 3.6.0 **`(feat):`** Allow for configuring `timeoutMs` and `maxRetries` request options at the client-level as well as the request level. --- # October 7, 2025 ## 3.5.0 **`(feat):`** Enable `verbatimModuleSyntax` in *tsconfig.esm.json* to increase TypeScript performance for the ESM build (not CJS). You may need to update your custom TypeScript code to comply with this setting. ## 3.4.0 **`(feat):`** Add `wireTestsFallbackToAutoGeneratedErrorExamples` configuration option to control whether to use autogenerated error examples if user does not provide error examples for generating wire tests. --- # October 3, 2025 ## 3.3.9 **`(fix):`** Use `// ... file header ...` file header instead of `/** ... file header ... */`. The latter is considered a JSDoc comment and may cause issues with some tools. The TypeScript compiler will remove `//` but not `/** */` comments. ## 3.3.7 **`(fix):`** Dynamically build type for enums based on the const to reduce generated code. Before: ```ts export type Operand = | ">" | "=" | "<"; export const Operand = { GreaterThan: ">", EqualTo: "=", LessThan: "<", } as const; ``` After: ```ts export const Operand = { GreaterThan: ">", EqualTo: "=", LessThan: "<", } as const; export type Operand = (typeof Operand)[keyof typeof Operand]; ``` ## 3.3.6 **`(fix):`** Fix basic auth password parsing to support colons in passwords. --- # October 1, 2025 ## 3.3.5 **`(feat):`** Log error when `testFramework: vitest` is used alongside `useBigInt: true`, `streamType: wrapper`, or `packagePath: path/to/package`. --- # September 30, 2025 ## 3.3.4 **`(fix):`** Upgrade generator-cli dependency to fix local generation handling of .fernignore files. --- # September 29, 2025 ## 3.3.3 **`(fix):`** If `useLegacyExports` is `true`, reference `../tsconfig.json` instead of `../tsconfig.base.json` in `tests/tsconfig.json`. ## 3.3.2 **`(fix):`** Fix non-GitHub output modes. **`(fix):`** Format GitHub Actions workflow files using prettier. **`(fix):`** Add .prettierignore to ensure dist and temporary files are not formatted. ## 3.3.2-rc1 **`(fix):`** Fix npm publish output mode --- # September 26, 2025 ## 3.3.2-rc0 **`(fix):`** Format GitHub Actions workflow files using prettier. **`(fix):`** Add .prettierignore to ensure dist and temporary files are not formatted. **`(fix):`** Fix non-GitHub output modes. --- # September 25, 2025 ## 3.3.1 **`(fix):`** Fix `bundle: true` mode ## 3.3.0 **`(feat):`** Add support for PR mode for self-hosted/local sdk generation ## 3.2.1 **`(fix):`** Set `compilerOptions.isolatedModules` and `compilerOptions.isolatedDeclarations` to `true` in *tsconfig.json*, and update the TypeScript code to comply with this setting. Users that enable `isolatedModules` can now use the SDK without any TypeScript compilation errors. While `isolatedModules` is not turned on by default in TypeScript, more frameworks and tools enable it by default. **Warning**: If you have custom code, this may cause compilation errors. Please refer to the TypeScript documentation to learn more about these settings: * [Isolated Declarations](https://www.typescriptlang.org/tsconfig#isolatedDeclarations) * [Isolated Modules](https://www.typescriptlang.org/tsconfig#isolatedModules) --- # September 24, 2025 ## 3.2.0 **`(feat):`** Add `generateEndpointMetadata` configuration to generate endpoint metadata for each endpoints. When you use a callback function to generate headers or auth tokens, the endpoint metadata will be passed to the callback. ```ts const client = new Foo({ ..., token: ({ endpointMetadata }) => { // generate token based on endpoint metadata } }); ``` To enable this, set `generateEndpointMetadata` to `true` in the `config` of your generator configuration. ```yml --- # In generators.yml groups: ts-sdk: generators: - name: fernapi/fern-typescript-sdk config: generateEndpointMetadata: true ``` ## 3.1.2 **`(fix):`** Pin `msw` dependency to `2.11.2` because newer version introduces jest/vitest compatibility issues. --- # September 23, 2025 ## 3.1.1 **`(fix):`** Rely on the version of pnpm in *package.json* instead of hardcoding the version in GitHub workflows. --- # September 19, 2025 ## 3.1.0 **`(feat):`** `consolidateTypeFiles` consolidates all folders of type files into a single file. ## 3.0.2 **`(fix):`** Update `exportAllRequestsAtRoot` to create an aggregate request file instead of adding imports. --- # September 18, 2025 ## 3.0.1 **`(fix):`** Fix incorrect pnpm commands inside of ci.yml **`(fix):`** Delete browser specific tests. **`(fix):`** Make tests more robust across Jest and Vitest. ## 3.0.0 **`(feat):`** Change defaults configuration in *generators.yml* to use pnpm package manager and vitest test framework. To avoid breaking changes, explicitly set the options above with the `Before` values in the `config` of your generator in *generators.yml*. | Option | Before | Now | | ---------------- | ------ | -------- | | `packageManager` | `yarn` | `pnpm` | | `testFramework` | `jest` | `vitest` | `testFramework: vitest` is not supported alongside `useBigInt: true`, `streamType: wrapper`, or `packagePath`. --- # September 17, 2025 ## 2.13.0 **`(feat):`** Use Vitest instead of Jest for running tests. Enable Vitest by setting `testFramework` to `vitest` in the `config` of your generator configuration. ## 2.12.3 **`(chore):`** Updated retry strategy; in particular, don't jitter for `retry-after` header. --- # September 16, 2025 ## 2.12.2 **`(fix):`** Generate correct types for pagination with inline types. ## 2.12.1 **`(fix):`** Generate property accessors for auth and pagination with `?.` if the property is optional or nullable, and `.` if the property is required and non-nullable. ## 2.12.0 **`(feat):`** Add support for custom sections in the README.md via `customSections` config option. ## 2.11.2 **`(fix):`** Websocket client generation compiles when there are no query parameters and when the auth scheme has custom authentication headers. --- # September 15, 2025 ## 2.11.1 **`(fix):`** The `_getAuthorizationHeader` method now returns `Promise` when oauth is enabled. This prevents compilation errors in the TypeScript SDK. ## 2.11.0 **`(feat):`** Generate `Request` and `Response` types variations for types that have readonly and/or writeonly properties. For example, a type `User` will have a `User.Request` type that omits readonly properties and a `User.Response` type that omits writeonly properties. Set `experimentalGenerateReadWriteOnlyTypes` to `true` in the `config` of your generator configuration to enable this feature. ```ts import { User, FooClient } from "foo"; const client = new FooClient(...); const createUser: User.Request = { name: "Jon", // id: "123", // Error: id is read-only and thus omitted }; const createdUser: User.Response = await client.createUser(createUser); // createdUser.id is available here ``` --- # September 12, 2025 ## 2.10.4 **`(feat):`** Use cached `prettier` to format project instead of yarn/pnpm installing all dependencies during generation. **`(feat):`** Generate lockfile without installing dependencies and using `--prefer-offline` to avoid network requests. --- # September 9, 2025 ## 2.10.3 **`(feat):`** Retries now check `Retry-After` and `X-RateLimit-Reset` before defaulting to exponential backoff. --- # September 5, 2025 ## 2.10.2 **`(fix):`** Allow `null` values in headers in addition to `undefined` to explicitly unset a header. --- # September 3, 2025 ## 2.10.1 **`(fix):`** Use autogenerated error examples if user does not provide error examples for generating wire tests. ## 2.10.0 **`(fix):`** Do not set a default `Content-Type` header when creating a HTTP response for wire test mocking. **`(feat):`** Generate wire tests for HTTP endpoint error examples. --- # September 2, 2025 ## 2.9.5 **`(feat):`** Introduce a custom configuration called `exportAllRequestsAtRoot` which exposes all request types through the root-level namespace. --- # August 28, 2025 ## 2.9.4 **`(fix):`** Grab overrideable root header value from Client as default. ## 2.9.2 **`(fix):`** Do not throw an error if example properties are mismatched with the schema definition. --- # August 27, 2025 ## 2.9.3 **`(feat):`** Add support for autogenerating simple tests for pagination endpoints. --- # August 26, 2025 ## 2.9.0 **`(feat):`** Generator passes readme configs apiName, disabledSections, and whiteLabel --- # August 22, 2025 ## 2.9.1 **`(fix):`** Introduce a custom configuration called `flattenRequestParameters` which collapses referenced bodies into the request instead of nesting under a body key. **Before**: ```ts client.users.create({ userId: "...", body: { "name": "Joe Scott" } }); ``` **After** ```ts client.users.create({ userId: "...", "name": "Joe Scott" }); ``` --- # August 21, 2025 ## 2.8.4 **`(feat):`** Add `flattenRequestParameters` to the SDK generator config. `flattenRequestParameters` is a boolean that controls whether to flatten request parameters. When `false` (default), the legacy flattening logic is used. When `true`, the new flattening logic is used. ```yml --- # In generators.yml groups: ts-sdk: generators: - name: fernapi/fern-typescript-sdk config: flattenRequestParameters: true ``` ## 2.8.3 **`(fix):`** Set `Authorization` header for WebSocket connects when auth is available on the generated SDK client. This will happen regardless of whether the AsyncAPI server or channel is marked for auth. **`(fix):`** Add support for inferred bearer authentication in WebSocket connects. --- # August 15, 2025 ## 2.8.2 **`(feat):`** Log warning when `noSerdeLayer` is `false` and `enableInlineTypes` is `true`. ## 2.8.1 **`(fix):`** Properly assert responses in wire tests when the `neverThrowErrors` flag is enabled. --- # August 13, 2025 ## 2.8.0 **`(feat):`** Choose to use `pnpm` or `yarn` as the package manager for the generated SDK. Configure this in *generators.yml* like so: ```yml --- # In generators.yml groups: ts-sdk: generators: - name: fernapi/fern-typescript-sdk config: packageManager: pnpm ``` The default is `yarn`. --- # August 12, 2025 ## 2.7.0 **`(feat):`** Implement inferred bearer authentication. --- # August 6, 2025 ## 2.6.8 **`(fix):`** Export BinaryResponse using `export type { BinaryResponse } ...` syntax to fix an issue with the SWC compiler. --- # August 4, 2025 ## 2.6.6 **`(fix):`** Requests and responses with no body should not be asserted as JSON in wire tests. --- # August 1, 2025 ## 2.6.7 **`(feat):`** Improve logging inside of wire tests for when a JSON body fails to parse to JSON. ## 2.6.5 **`(fix):`** If an enum wire value is not found, use the first enum value as a fallback. --- # July 30, 2025 ## 2.6.4 **`(fix):`** Fix inline types inside of multipart-form requests --- # July 25, 2025 ## 2.6.3 **`(fix):`** Include root variables in code snippet generation for client instantiation. --- # July 24, 2025 ## 2.6.2 **`(chore):`** Update form-data version to 4.0.4 to avoid vulnerability. --- # July 23, 2025 ## 2.6.1 **`(chore):`** Add additional query string parameters section to the generated README.md file. ## 2.6.0 **`(feat):`** Users can now pass in `queryParams` as part of the request options. ```ts await client.foo.bar(..., { queryParams: { foo: "bar" } }); ``` --- # July 22, 2025 ## 2.5.1 **`(chore):`** Update README.md generation to be more accurate --- # July 18, 2025 ## 2.4.11 **`(chore):`** Bump the docker image for the generator to node:22.12-alpine3.20 --- # July 17, 2025 ## 2.5.0 **`(feat):`** Support uploading file-like types for binary upload endpoints (not multipart-form): * Buffered types: `Buffer`, `Blob`, `File`, `ArrayBuffer`, `ArrayBufferView`, and `Uint8Array` * Stream types: `fs.ReadStream`, `stream.Readable`, and `ReadableStream` **`(feat):`** Users can configure metadata when uploading a file to a binary upload endpoint using the `Uploadable.WithMetadata` type: ```typescript import { createReadStream } from "fs"; await client.upload({ data: createReadStream("path/to/file"), filename: "my-file", contentType: "audio/mpeg", contentLength: 1949, }); ``` The `filename`, `contentType`, and `contentLength` properties are optional. Alternatively, users can use the `Uploadable.FromPath` type to upload directly from a file path: ```typescript await client.upload({ path: "path/to/file", filename: "my-file", contentType: "audio/mpeg", contentLength: 1949, }); ``` The metadata is used to set the `Content-Length`, `Content-Type`, and `Content-Disposition` headers. If not provided, the client will attempt to determine them automatically. For example, `fs.ReadStream` has a `path` property which the SDK uses to retrieve the file size from the filesystem without loading it into memory: ```typescript import { createReadStream } from "fs"; await client.upload(createReadStream("path/to/file")); ``` --- # July 15, 2025 ## 2.4.10 **`(fix):`** Escape strings containing `*/` inside of JSDoc comments to avoid premature JSDoc block ending. ## 2.4.9 **`(fix):`** Preserve trailing slash of URL and path if present --- # July 10, 2025 ## 2.4.8 **`(fix):`** Fix ts readme snippet where const was reassigned. Changed to let. ## 2.4.7 **`(fix):`** Make sure `extraDependencies`, `extraPeerDependencies`, `extraPeerDependenciesMeta`, and `extraDevDependencies` are always merged into *package.json*. This was previously fixed for `bundle: true`, but not for `bundle: false` (default). All dependencies should now come through. --- # July 9, 2025 ## 2.4.6 **`(fix):`** Parse HTTP error bodies as JSON if the response content-type header is JSON, otherwise fallback to text. **`(fix):`** Fix `bytes` fetcher test. **`(fix):`** Fix Jest configuration when a `packagePath` is specified in *generators.yml* config. ## 2.4.5 **`(fix):`** Make sure `extraDependencies`, `extraPeerDependencies`, `extraPeerDependenciesMeta`, and `extraDevDependencies` are always merged into *package.json*. ## 2.4.4 **`(fix):`** Make the `BinaryResponse.bytes` function optional because some versions of runtimes do not support the function on fetch `Response`. --- # July 8, 2025 ## 2.4.3 **`(fix):`** Fix an issue where a property set to `undefined` would not match with a property that is missing in the `withJson` MSW predicate. --- # July 4, 2025 ## 2.4.2 **`(fix):`** Fixes a compile issue when WebSocket connect methods require query parameters with special characters. Fixes response deserialization in websockets to respect skipping validation. ## 2.4.1 **`(fix):`** When serde layer is enabled, WebSocket channels now pass through unrecognized properties instead of stripping them to preserve forwards compatibility. --- # July 3, 2025 ## 2.4.0 **`(fix):`** Fixes bug with query parameter and path parameter serialization in URL for WebSocket channels. ## 2.3.3 **`(internal):`** Bump version to test Docker image rename to `fernapi/fern-typescript-sdk` ## 2.3.2 **`(fix):`** Remove ".js" extension from ESM imports in the source generator code. If `useLegacyExports` is `true`, you will not see ".js" extensions in ESM imports. If `useLegacyExports` is `false` (default), a post process step will add the `.js` extension, so you won't see a difference. We're doing this because Jest has a bug where it doesn't properly load TypeScript modules even though the TypeScript and imports are valid. ## 2.3.1 **`(fix):`** Fixes an issue where OAuth clients would not compile when variables were configured in the SDK. Now, the oauth client is instantiated with any global path parameters or headers. ## 2.3.0 **`(feat):`** Change the `outputSourceFiles` default from `false` to `true`. This will affect the output when you generate the SDK to the local file system. ## 2.2.1 **`(fix):`** Ensure *tests/wire* is generated even when there are no wire tests generated. Otherwise, Jest throws an error because the wire test project `roots` doesn't exist. ## 2.2.0 **`(feat):`** Improve generated package.json files: * Add `engines` field to specify minimum Node.js version supported as Node.js 18. * Add `sideEffects: false` * Add `README.md` and `LICENSE` to `files` array * Use GitHub shorthand for `repository` field. You can override these fields using the `packageJson` config: ```yml --- # In generators.yml groups: ts-sdk: generators: - name: fernapi/fern-typescript-sdk config: packageJson: engines: node: ">=16.0.0" ``` --- # July 2, 2025 ## 2.1.0 **`(feat):`** Split up Jest configuration into multiple projects. You can now run the following command to run tests: * `yarn test`: runs all tests * `yarn test:unit`: runs unit tests (any non-browser and non-wire tests) * `yarn test:browser`: runs browser only tests inside of `js-dom` * `yarn test:wire`: runs wire tests You can now pass in paths and patterns as an argument to the above commands to filter down to specific tests. For example: `yarn test tests/unit/fetcher` ## 2.0.0 **`(feat):`** The TypeScript generator has received a large amount of improvements, but to maintain backwards compatibility, they require you to opt in using feature flags. The 2.0.0 release now has these feature flags enabled by default. Here's an overview of the `config` defaults that have changed in *generators.yml*. | Option | Before | Now | | ------------------ | -------------- | ------------------- | | `streamType` | `"wrapper"` | `"web"` | | `fileResponseType` | `"stream"` | `"binary-response"` | | `formDataSupport` | `"Node16"` | `"Node18"` | | `fetchSupport` | `"node-fetch"` | `"native"` | To avoid breaking changes, explicitly set the options above with the `Before` values in the `config` of your generator in *generators.yml*. With these defaults, the generated SDKs will have ***ZERO*** dependencies (excluding devDependencies and `ws` in case of WebSocket generation). As a result, the SDKs are smaller, faster, more secure, and easier to use. ## 1.10.6 **`(fix):`** Publish multi-platform builds of the TypeScript SDK docker container. --- # July 1, 2025 ## 1.10.4 **`(fix):`** Add `omitFernHeaders` configuration to omit Fern headers from the generated SDK. ## 1.10.3 **`(fix):`** Remove `qs` dependency. ## 1.10.2 **`(fix):`** Remove `js-base64` dependency in favor of using native implementations. --- # June 30, 2025 ## 1.10.5 **`(feat):`** Add default values to request parameters. For example, if you have a query parameter `foo` with a default value of `bar`, the generated request parameter will have a default value of `bar`. To enable this, set `useDefaultRequestParameterValues` to `true` in the `config` of your generator configuration. ```yml --- # In generators.yml groups: ts-sdk: generators: - name: fernapi/fern-typescript-sdk config: useDefaultRequestParameterValues: true ``` ## 1.10.1 **`(fix):`** Remove `url-join` dependency in favor of a handwritten `joinUrl` function. --- # June 27, 2025 ## 1.10.0 **`(feat):`** Add `fetchSupport` configuration which lets you choose between `node-fetch` and `native`. The default is `node-fetch`. If you choose `native`, the `node-fetch` dependency will be removed. ## 1.9.1 **`(fix):`** Improve auto-pagination logic to consider empty strings in response as null cursors and stop paging. --- # June 22, 2025 ## 1.9.0 **`(feat):`** Add `formDataSupport` configuration which lets you choose between `Node16` and `Node18`. The default is `Node16`. If you choose `Node18`, the `form-data`, `formdata-node`, and `form-data-encoder` dependencies will be removed. `formDataSupport: Node18` supports uploading files from the following types: * `Buffer` * `File` * `Blob` * `Readable` (includes Readstream) * `ReadableStream` * `ArrayBuffer` * `Uint8Array` ## 1.8.2 **`(fix):`** When a multipart form part is explicitly marked as JSON, serialize the data as JSON regardless of type. This also means arrays, maps, etc. will not be split into multiple parts, but serialized to JSON as a single part. ## 1.8.1 **`(fix):`** Fix binary response README.md examples --- # June 19, 2025 ## 1.8.0 **`(feat):`** You can now specify whether to return the `BinaryResponse` type for binary response endpoints. Change the response type by setting `fileResponseType` to `stream` or `binary-response` in the `config` of your generator configuration. The default is `stream` for backwards compatibility, but we recommend using `binary-response`. Here's how you users can interact with the `BinaryResponse`: ```ts const response = await client.getFile(...); const stream = response.stream(); // const arrayBuffer = await response.arrayBuffer(); // const blob = await response.blob(); // const bytes = await response.bytes(); const bodyUsed = response.bodyUsed; ``` The user can choose how to consume the binary data. ## 1.7.2 **`(fix):`** Fix bug where duplicate file generation was silently allowed instead of failing. The `withSourceFile` method now properly handles the `overwrite` option to prevent unintended file overwrites. --- # June 18, 2025 ## 1.7.1 **`(fix):`** **jest.config.mjs** now only maps relative path modules that end on `.js` to their `.ts` equivalent. --- # June 16, 2025 ## 1.7.0 **`(feat):`** Allow users to specify the path they'd like to generate the SDK to. Here's an example of how to implement this in generators.yml: ```yml --- # In generators.yml groups: ts-sdk: generators: - name: fernapi/fern-typescript-sdk config: packagePath: src/package-path ``` --- # June 13, 2025 ## 1.6.0 **`(feat):`** You can now specify whether to return streams using the stream wrapper, or return the web standard stream. Change the type of stream returned by setting `streamType` to `wrapper` or `web` in the `config` of your generator configuration. The default is `wrapper`. **`(internal):`** `tests/unit/zurg` are moved to `tests/unit/schemas` to match the name in `src/core/schemas` which is what the tests are verifying. --- # June 11, 2025 ## 1.5.0 **`(feat):`** Add support for websocket connect methods with path parameters in the TypeScript generator --- # June 5, 2025 ## 1.4.0 **`(feat):`** You can now pass in headers to the root client. These headers will be merged with service and endpoint specific headers. **`(internal):`** Reduce duplicate code generation by passing headers from the root client down to the subpackage clients. ## 1.3.2 **`(fix):`** Fix dynamic imports in the built dist/esm code. ## 1.3.1 **`(fix):`** MSW is used for generated wire tests, but inadvertently also captures real HTTP request, for example in integration tests. When the HTTP request does not match any of the configured predicates, it would throw an error, including in the unrelated integration tests. In this version MSW is configured to bypass instead of throw an error when HTTP requests do not match the configured predicates. --- # June 4, 2025 ## 1.3.0 **`(feat):`** Add support for generating the full project when using the filesystem output mode. ## 1.1.1 **`(fix):`** Fix an issue where attempting to access a property with an invalid property name would lead to a broken output SDK. --- # June 3, 2025 ## 1.2.4 **`(feat):`** Generate tests to verify the SDK sends and receives HTTP requests as expected. You can turn of these tests by setting `generateWireTests` to `false` in the `config` of your generator configuration. ## 1.1.0 **`(feat):`** Add support for HEAD HTTP method. --- # May 14, 2025 ## 1.0.1 **`(fix):`** Fix property lookup in inherited schemas during snippet generation for object schemas. ## 1.0.0 **`(feat):`** This release changes the defaults for the following custom configuration in *generators.yml*. | Option | Before | Now | | ------------------------ | ------- | ------- | | `inlineFileProperties` | `false` | `true` | | `inlinePathParameters` | `false` | `true` | | `enableInlineTypes` | `false` | `true` | | `noSerdeLayer` | `false` | `true` | | `omitUndefined` | `false` | `true` | | `skipResponseValidation` | `false` | `true` | | `useLegacyExports` | `true` | `false` | To avoid breaking changes, explicitly set the options above with the `Before` values in the `config` of your generator in *generators.yml*. **`(fix):`** When generating properties for interfaces and classes, we only surround the property name with quotes if necessary. In some cases where the property name wasn't a valid identifier before, we now surround it with quotes too. ## 0.51.7 **`(fix):`** If an object extends an alias, the generator now visits the alias that is being extended (instead of throwing an error). --- # May 13, 2025 ## 0.51.6 **`(fix):`** Add support for the custom introduction setting in the generated README.md. --- # May 3, 2025 ## 0.51.5 **`(fix):`** Fixed an issue with ts-morph where creating an ifStatement with empty conditions array caused errors in multipart form data handling. --- # April 22, 2025 ## 0.51.4 **`(fix):`** Fix issue where the *runtime.ts* file was missing when other files were trying to import it. --- # April 21, 2025 ## 0.51.3 **`(fix):`** Fix minor type issue for polyfilling Headers in Node 16 and below. ## 0.51.2 **`(fix):`** When uploading files, extract the filename from the `path` property if present on the given object. This will extract the filename for `fs.createReadStream()` for example. ## 0.51.1 **`(fix):`** Fallback to a custom `Headers` class implementation if the native `Headers` class is not available. Versions of Node 16 and below do not support the native `Headers` class, so this fallback is necessary to ensure compatibility. --- # April 14, 2025 ## 0.51.0 **`(feat):`** Add `rawResponse` property to JavaScript errors. ```ts try { const fooBar = await client.foo.bar("id", options); } catch (e) { if (error instanceof FooError) { console.log(error.rawResponse); } else { // ... } } ``` --- # April 8, 2025 ## 0.50.1 **`(feat):`** Add `"packageManager": "yarn@1.22.22"` to *package.json*. --- # April 7, 2025 ## 0.50.0 **`(feat):`** All endpoint functions now return an `HttpResponsePromise` instead of a `Promise`. Using `await`, `.then()`, `.catch()`, and `.finally()` on these promises behave the same as before, but you can call `.withRawResponse()` to get a promise that includes the parsed response and the raw response. The raw response let's you retrieve the response headers, status code, etc. ```ts const fooBar = await client.foo.bar("id", options); const { data: alsoFooBar, rawResponse } = await client.foo.bar("id", options).withRawResponse(); const { headers, status, url, ... } = rawResponse; ``` --- # March 27, 2025 ## 0.49.7 **`(fix):`** Significantly improve performance of SDK generation when the `useLegacyExports` config is `false`. For a large spec like Square, the generation went from 10+ minutes to almost 1 minute. ## 0.49.6 **`(feat):`** Support arbitrary websocket headers during connect handshake. ## 0.49.5 **`(feat):`** Improvements to Websocket code generation quality. --- # March 19, 2025 ## 0.49.4 **`(fix):`** Increase the timeout used in the generated `webpack.test.ts` file. ## 0.49.3 **`(fix):`** Increase the timeout used in the generated `webpack.test.ts` file. --- # March 18, 2025 ## 0.49.2 **`(fix):`** Fix issue where IdempotentRequestOptions is not generated in the client namespace. --- # March 10, 2025 ## 0.49.1 **`(fix):`** This PR includes several fixes to the generated `Socket.ts` file when websocket client code generation is enabled. --- # March 6, 2025 ## 0.49.0 **`(feat):`** This PR enables the Typescript generator to produce Websocket SDK endpoints. This can be enabled by adding the option `shouldGenerateWebsocketClients: true` to the Typescript generator config. --- # January 28, 2025 ## 0.48.7 **`(fix):`** Form data encoding now correctly handles array and object values by encoding each property value as a separate key-value pair, rather than trying to encode the entire object as a single value. This ensures proper handling of complex data structures in multipart form requests. ## 0.48.6 **`(fix):`** Support form-encoded form data parameters by using `qs` to properly encode array and object values with the `repeat` array format. ## 0.48.5 **`(fix):`** Don't double wrap a blob if a user uploads a blob to a multi-part form. Otherwise file's content-type is lost in Deno. --- # January 21, 2025 ## 0.48.4 **`(fix):`** When custom config `useBigInt` is `true`, generate examples and snippets with `BigInt("123")`. --- # January 16, 2025 ## 0.48.3 **`(fix):`** The SDK now supports reading the basic auth username and password values from environment variables. ## 0.48.2 **`(fix):`** This updates the retrier logic to stop retrying on HTTP conflict (409). This was an oversight that we've meant to remove for a while (similar to other Fern SDKs). ## 0.48.1 **`(fix):`** Record types with `null` values are now correctly serialized. ## 0.48.0 **`(feat):`** When `useBigInt` SDK configuration is set to `true`, a customized JSON serializer & deserializer is used that will preserve the precision of `bigint`'s, as opposed to the native `JSON.stringify` and `JSON.parse` function which converts `bigint`'s to `number`'s losing precision. When combining `useBigInt` with our serialization layer (`no-serde: false` (default)), both the request and response properties that are marked as `long` and `bigint` in OpenAPI/Fern spec, will consistently be `bigint`'s. However, when disabling the serialization layer (`no-serde: true`), they will be typed as `number | bigint`. Here's an overview of what to expect from the generated types when combining `useBigInt` and `noSerde` with the following Fern definition: **Fern definition** ```yml types: ObjectWithOptionalField: properties: longProp: long bigIntProp: bigint ``` **TypeScript output** ```typescript // useBigInt: true // noSerde: false interface ObjectWithLongAndBigInt { longProp: bigint; bigIntProp: bigint; } // useBigInt: true // noSerde: true interface ObjectWithLongAndBigInt { longProp: bigint | number; bigIntProp: bigint | number; } // useBigInt: false // noSerde: false interface ObjectWithLongAndBigInt { longProp: number; bigIntProp: string; } // useBigInt: false // noSerde: true interface ObjectWithLongAndBigInt { longProp: number; bigIntProp: string; } ``` --- # January 15, 2025 ## 0.47.1 **`(fix):`** Resolves an issue where nullable query parameters were not null-safe in their method invocations. The generated code now appropriately guard against `null` values like so: ```typescript const _queryParams: Record< ... >; if (value !== undefined) { _queryParams["value"] = value?.toString() ?? null; } ``` --- # January 14, 2025 ## 0.47.0 **`(feat):`** Add support for `nullable` properties. Users can now specify explicit `null` values for types that specify `nullable` properties like so: ```typescript await client.users.update({ username: "john.doe", metadata: null }); ``` ## 0.46.11 **`(fix):`** Don't double check whether an optional string literal alias (see example below) is a string when using serializer to build query string parameters. ```yml types: LiteralAliasExample: literal<"MyLiteralValue"> service: endpoints: foo: path: /bar method: POST request: name: FooBarRequest query-parameters: optional_alias_literal: optional ``` ```ts // before if (optionalAliasLiteral != null) { _queryParams["optional_alias_literal"] = typeof serializers.LiteralAliasExample.jsonOrThrow(optionalAliasLiteral, { unrecognizedObjectKeys: "strip", }) === "string" ? serializers.LiteralAliasExample.jsonOrThrow(optionalAliasLiteral, { unrecognizedObjectKeys: "strip", }) : JSON.stringify(serializers.LiteralAliasExample.jsonOrThrow(optionalAliasLiteral, { unrecognizedObjectKeys: "strip", })); } // after if (optionalAliasLiteral != null) { _queryParams["optional_alias_literal"] = serializers.LiteralAliasExample.jsonOrThrow(optionalAliasLiteral, { unrecognizedObjectKeys: "strip", }); } ``` ## 0.46.10 **`(fix):`** Use serialization layer to convert types to JSON strings when enabled. --- # January 13, 2025 ## 0.46.9 **`(fix):`** Expose `baseUrl` as a default Client constructor option and construct URL correctly. ## 0.46.8 **`(fix):`** Generate the `version.ts` file correctly --- # January 9, 2025 ## 0.46.7 **`(fix):`** Simplify runtime detection to reduce the chance of using an unsupported API like `process.` Detect Edge Runtime by Vercel. ## 0.46.6 **`(fix):`** Update `@types/node` to `18+`, required for the generated `Node18UniversalStreamWrapper` test. ## 0.46.5 **`(fix):`** Fix the webpack test to work with .js/.jsx extensions in TypeScript **`(fix):`** Only map .js modules in Jest, not .json files. ## 0.46.4 **`(fix):`** Fix packageJson custom configuration & package.json types field. ## 0.46.3 **`(fix):`** Revert to using legacy exports by default. ## 0.46.2 **`(fix):`** Fix Jest to work with files imported using `.js` extension. **`(fix):`** Make sure Jest loads Jest configuration regardless of package.json type. --- # January 8, 2025 ## 0.46.1 **`(fix):`** ESModule output is fixed to be compatible with Node.js ESM loading. --- # January 6, 2025 ## 0.46.0 **`(feat):`** SDKs are now built and exported in both CommonJS (legacy) and ESModule format. **`(feat):`** Export `serialization` code from root package export. ```ts import { serialization } from `@packageName`; ``` The serialization code is also exported as `@packageName/serialization`. ```ts import * as serialization from `@packageName/serialization`; ``` **`(feat):`** `package.json` itself is exported in `package.json` to allow consumers to easily read metadata about the package they are consuming. --- # December 31, 2024 ## 0.45.2 **`(fix):`** TS generated snippets now respect proper parameter casing when noSerdeLayer is enabled. --- # December 27, 2024 ## 0.45.1 **`(fix):`** Export everything inside of TypeScript namespaces that used to be ambient. For the `enableInlineTypes` feature, some namespaces were no longer declared (ambient), and types and interfaces inside the namespace would no longer be automatically exported without the `export` keyword. This fix exports everything that's inside these namespaces and also declared namespaces for good measure (in case they are not declared in the future). --- # December 26, 2024 ## 0.45.0 **`(feat):`** Update dependencies of the generated TS SDK and Express generator. TypeScript has been updated to 5.7.2 which is a major version upgrade from 4.6.4. --- # December 23, 2024 ## 0.44.5 **`(fix):`** Fix a bug where we attempt to parse an empty terminator when receiving streaming JSON responses. --- # December 20, 2024 ## 0.44.4 **`(feat):`** Use specified defaults for pagination offset parameters during SDK generation. --- # December 18, 2024 ## 0.44.3 **`(fix):`** Fix a bug where client would send request wrapper instead of the body of the request wrapper, when the request has inline path parameters and a body property. --- # December 17, 2024 ## 0.44.2 **`(fix):`** Inline path parameters will use their original name when `retainOriginalName` or `noSerdeLayer` is enabled. --- # December 16, 2024 ## 0.44.1 **`(fix):`** When there is an environment variable set, you do not need to pass in any parameters to the client constructor. --- # December 13, 2024 ## 0.44.0 **`(feat):`** Inline path parameters into request types by setting `inlinePathParameters` to `true` in the generator config. Here's an example of how users would use the same endpoint method without and with `inlinePathParameters` set to `true`. Without `inlinePathParameters`: ```ts await service.getFoo("pathParamValue", { id: "SOME_ID" }); ``` With `inlinePathParameters`: ```ts await service.getFoo({ pathParamName: "pathParamValue", id: "SOME_ID" }); ``` --- # December 11, 2024 ## 0.43.1 **`(fix):`** When `noSerdeLayer` is enabled, streaming endpoints were failing to compile because they assumed that the serialization layer existed. This is now fixed. ## 0.43.0 **`(feat):`** Generate inline types for inline schemas by setting `enableInlineTypes` to `true` in the generator config. When enabled, the inline schemas will be generated as nested types in TypeScript. This results in cleaner type names and a more intuitive developer experience. Before: ```ts // MyRootType.ts import * as MySdk from "..."; export interface MyRootType { foo: MySdk.MyRootTypeFoo; } // MyRootTypeFoo.ts import * as MySdk from "..."; export interface MyRootTypeFoo { bar: MySdk.MyRootTypeFooBar; } // MyRootTypeFooBar.ts import * as MySdk from "..."; export interface MyRootTypeFooBar {} ``` After: ```ts // MyRootType.ts import * as MySdk from "..."; export interface MyRootType { foo: MyRootType.Foo; } export namespace MyRootType { export interface Foo { bar: Foo.Bar; } export namespace Foo { export interface Bar {} } } ``` Now users can get the deep nested `Bar` type as follows: ```ts import { MyRootType } from MySdk; const bar: MyRootType.Foo.Bar = {}; ``` --- # December 3, 2024 ## 0.42.7 **`(feat):`** Support `additionalProperties` in OpenAPI or `extra-properties` in the Fern Defnition. Now an object that has additionalProperties marked as true will generate the following interface: ```ts interface User { propertyOne: string; [key: string]: any; } ``` --- # November 23, 2024 ## 0.42.6 **`(fix):`** Remove the generated `APIPromise` since it is not compatible on certain node versions. ## 0.42.5 **`(fix):`** Remove extraneous import in pagination snippets. --- # November 22, 2024 ## 0.42.3 **`(fix):`** Fixed issue with snippets used for pagination endpoints. --- # November 21, 2024 ## 0.42.4 **`(fix):`** Improve `GeneratedTimeoutSdkError` error to include endpoint name in message. ## 0.42.2 **`(feat):`** Added documentation for pagination in the README. The snippet below will now show up on generated READMEs. ```typescript // Iterate through all items const response = await client.users.list(); for await (const item of response) { console.log(item); } // Or manually paginate let page = await client.users.list(); while (page.hasNextPage()) { page = await page.getNextPage(); } ``` --- # November 20, 2024 ## 0.42.1 **`(feat):`** Added support for passing additional headers in request options. For example: ```ts const response = await client.someEndpoint(..., { headers: { 'X-Custom-Header': 'custom value' } }); ``` --- # November 18, 2024 ## 0.41.2 **`(fix):`** Actually remove `jest-fetch-mock` from package.json. --- # November 15, 2024 ## 0.42.0 **`(feat):`** Added support for `.asRaw()` which allows users to access raw response data including headers. For example: ```ts const response = await client.someEndpoint().asRaw(); console.log(response.headers["X-My-Header"]); console.log(response.body); ``` --- # November 2, 2024 ## 0.41.1 **`(fix):`** Remove dev dependency on `jest-fetch-mock`. --- # October 8, 2024 ## 0.41.0 **`(feat):`** Add a variable jitter to the exponential backoff and retry. ## 0.41.0-rc2 **`(feat):`** Generated READMEs now include improved usage snippets for pagination and streaming endpoints. ## 0.41.0-rc1 **`(fix):`** Fixes a broken unit test introduced in 0.41.0-rc0. ## 0.41.0-rc0 **`(feat):`** The generated SDK now supports bytes (`application/octet-stream`) requests. --- # September 28, 2024 ## 0.40.8 **`(fix):`** File array uploads now call `request.appendFile` instead of `request.append` which was causing form data to be in a corrupted state. ## 0.40.7 **`(fix):`** The generated README will now have a section that links to the generated SDK Reference (in `reference.md`). ```md ## Reference A full reference for this library can be found [here](./reference.md). ``` --- # September 18, 2024 ## 0.40.6 **`(fix):`** The TypeScript SDK now supports specifying a custom contentType if one is specified. ## 0.40.5 **`(fix):`** The snippet templates for file upload are now accurate and also respect the feature flag `inlineFileProperties`. --- # September 12, 2024 ## 0.40.4 **`(fix):`** Upgrades dependency `stream-json` which improves the performance when reading large API specs. This version will improve your `fern generate` performance. ## 0.40.3 **`(fix):`** If the serde layer is enabled, then all the serializers are exported under the namespace `serializers`. ```ts import { serializers } from "@plantstore/sdk"; export function main(): void { // serialize to json const json = serializers.Plant.toJson({ name: "fern" }); const parsed = serializers.Plant.parseOrThrow(`{ "name": "fern" }`); } ``` ## 0.40.2 **`(fix):`** The generated SDK now handles reading IR JSONs that are larger than 500MB. In order to to this, the function `streamObjectFromFile` is used instead of `JSON.parse`. ## 0.40.1 **`(fix):`** The generated snippets now inline referenced request objects given they are not named, they need to be inlined. ## 0.40.0 **`(feat):`** A new configuration flag has now been added that will automatically generate `BigInt` for `long` and `bigint` primitive types. To turn this flag on: ```yml groups: ts-sdk: name: fernapi/fern-typescript-sdk version: 0.40.0 config: useBigInt: true ``` --- # September 11, 2024 ## 0.39.8 **`(fix):`** The generated enum examples now reference the value of the enum directly instead of using the enum itself. ### Before ```ts { "genre": Imdb.Genre.Humor, } ``` ### After ```ts { "genre": "humor" } ``` --- # August 27, 2024 ## 0.39.7 **`(chore):`** The SDK now produces a `version.ts` file where we export a constant called `SDK_VERSION`. This constant can be used by different utilities to dynamically import in the version (for example, if someone wants to customize the user agent). ## 0.39.6 **`(fix):`** Browser clients can now import streams, via `readable-streams` polyfill. Additionally adds a webpack unit test to verify that the core utilities can be compiled. --- # August 20, 2024 ## 0.39.5 **`(fix):`** If `noSerdeLayer` is enabled, then the generated TypeScript SDK snippets and wire tests will not use `Date` objects but instead use strings. Without this fix, the generated wire tests would result in failures. ## 0.39.4 **`(fix):`** Ensure that environment files don't generate, unless there is a valid environment available. --- # August 16, 2024 ## 0.39.3 **`(fix):`** Multipart form data unit tests only get generated if the SDK has multipart form uploads. ## 0.39.2 **`(fix):`** Allows filenames to be passed from underlying File objects in Node 18+ and browsers Users can now supply files like so, using a simple multipart upload API as an example: ```typescript client.file.upload(new File([...blobParts], 'filename.ext'), ...) ``` `filename.ext` will be encoded into the upload. --- # August 7, 2024 ## 0.39.1 **`(feat):`** The SDK now supports looking directly at a `hasNextPage` property for offset pagination if configured. Previously the SDK would look if the number of items were empty, but this failed in certain edge cases. ## 0.38.6 **`(feat):`** The SDK generator now sends a `User-Agent` header on each request that is set to `/`. For example if your package is called `imdb` and is versioned `0.1.0`, then the user agent header will be `imdb/0.1.0`. ## 0.38.5 **`(fix):`** Addressed fetcher unit test flakiness by using a mock fetcher --- # August 4, 2024 ## 0.38.4 **`(fix):`** Literal templates are generated if they are union members **`(fix):`** Snippet templates no longer try to inline objects within containers --- # August 2, 2024 ## 0.38.3 **`(fix):`** Adds async iterable to StreamWrapper implementation for easier use with downstream dependencies. --- # August 1, 2024 ## 0.38.2 **`(fix):`** Refactors the `noScripts` feature flag to make sure that no `yarn install` commands can be accidentally triggered. ## 0.38.1 **`(feat):`** A feature flag called `noScripts` has been introduced to prevent the generator from running any scripts such as `yarn format` or `yarn install`. If any of the scripts cause errors, toggling this option will allow you to receive the generated code. ``` - name: fernapi/fern-typescript-sdk version: 0.38.1 config: noScripts: true ``` --- # July 31, 2024 ## 0.38.0-rc0 **`(internal):`** Upgrade to IRv53. **`(chore):`** The generator now creates snippet templates for undiscriminated unions. --- # July 29, 2024 ## 0.37.0-rc0 **`(feat):`** The business plan Typescript SDK will now generate wire tests if the feature flag in the configuration is turned on. ``` - name: fernapi/fern-typescript-sdk version: 0.37.0-rc0 config: generateWireTests: true ``` ## 0.36.6 **`(fix):`** Now import paths are correctly added to getResponseBody tests. CI checks also added. ## 0.36.5 **`(fix):`** Now, server sent events are treated differently as streaming responses, to ensure the correct wrapping happens. --- # July 26, 2024 ## 0.36.4 **`(fix):`** Now, import paths are correctly added to stream wrapper tests. ## 0.36.3 **`(fix):`** Support starting the stream on `StreamWrapper.pipe(...)` for shorter syntax when dealing with `node:stream` primitives. ## 0.36.2 **`(fix):`** This release comes with numerous improvements to streaming responses: 1. Introduces new stream wrapper polyfills that implement the ability to stream to more streams, per environment. 2. For `Node 18+`, stream responses can now be piped to `WritableStream`. They can also be streamed to `stream.Writable`, as possible before. 3. For `< Node 18`, stream responses can be piped to `stream.Writeable`, as before. 4. For `Browser` environments, stream responses can be piped to `WritableStream`. 5. For `Cloudflare Workers`, stream responses can be piped to `WritableStream`. **`(fix):`** Now, there are generated unit tests for the `fetcher/stream-wrappers` core directory which makes sure that Fern's stream wrapping from responses work as expected! --- # July 16, 2024 ## 0.36.1 **`(fix):`** Now, there are generated unit tests for the `auth` and `fetcher` core directory which makes sure that Fern's fetcher and authorization helpers work as expected! ## 0.36.0 **`(fix):`** Now, there are generated unit tests for the `schemas` core directory which makes sure that Fern's request + response validation will work as expected! ## 0.35.0 **`(fix):`** Support Multipart Form uploads where `fs.createReadStream` is passed. This requires coercing the stream into a `File`. ## 0.34.0 **`(internal):`** Upgrade to IRv50. **`(feat):`** Add support for generating an API version scheme in `version.ts`. Consider the following `api.yml` configuration: ```yaml version: header: X-API-Version default: "1.0.0" values: - "1.0.0-alpha" - "1.0.0-beta" - "1.0.0" ``` The following `version.ts` file is generated: ```typescript /** * This file was auto-generated by Fern from our API Definition. */ /** The version of the API, sent as the X-API-Version header. */ export type AcmeVersion = "1.0.0" | "2.0.0" | "latest"; ``` If a default value is specified, it is set on every request but can be overridden in either the client-level `Options` or call-specific `RequestOptions`. If a default value is *not* specified, the value of the header is required on the generated `Options`. An example call is shown below: ```typescript import { AcmeClient } from "acme"; const client = new AcmeClient({ apiKey: "YOUR_API_KEY", xApiVersion: "2.0.0" }); await client.users.create({ firstName: "john", lastName: "doe" }); ``` ## 0.33.0 **`(fix):`** This release comes with numerous improvements to multipart uploads: 1. `Fetcher.ts` no longer depends on form-data and formdata-node which reduces the size of the SDK for all consumers that are not leveraging multipart form data uploads. 2. The SDK now accepts `fs.ReadStream`, `Blob` and `File` as inputs and handles parsing them appropriately. 3. By accepting a `Blob` as a file parameter, the SDK now supports sending the filename when making a request. --- # July 15, 2024 ## 0.32.0 **`(feat):`** The `reference.md` is now generated for every SDK. **`(feat):`** The `reference.md` is now generated by the `generator-cli`. **`(fix):`** The `reference.md` includes a single section for the *first* example specified on the endpoint. Previously, a separate section was included for *every* example. --- # July 12, 2024 ## 0.31.0 **`(feat):`** Add `omitUndefined` generator option. This is enabled with the following config: ```yaml groups: generators: - name: fernapi/fern-typscript-node-sdk version: 0.31.0 ... config: omitUndefined: true ``` When enabled, any property set to an explicit `undefined` is *not* included in the serialized result. For example, ```typescript const request: Acme.CreateUserRequest = { firstName: "John", lastName: "Doe", email: undefined }; ``` By default, explicit `undefined` values are serialized as `null` like so: ```json { "firstName": "John", "lastName": "Doe", "email": null } ``` When `omitUndefined` is enabled, the JSON object is instead serialized as: ```json { "firstName": "John", "lastName": "Doe" } ``` --- # July 11, 2024 ## 0.30.0 **`(feat):`** Client-level `Options` now supports overriding global headers like version. --- # July 10, 2024 ## 0.29.2 **`(fix):`** Fix serialization of types with circular references ## 0.29.1 **`(fix):`** Pagination endpoints that define nested offset/cursor properties are now functional. A new `setObjectProperty` helper is used to dynamically set the property, which is inspired by Lodash's `set` function ([https://lodash.com/docs/4.17.15#set](https://lodash.com/docs/4.17.15#set)). The generated code now looks like the following: ```typescript let _offset = request?.pagination?.page != null ? request?.pagination?.page : 1; return new core.Pageable({ response: await list(request), hasNextPage: (response) => (response?.data ?? []).length > 0, getItems: (response) => response?.data ?? [], loadPage: (_response) => { _offset += 1; return list(core.setObjectProperty(request, "pagination.page", _offset)); } }); ``` --- # July 9, 2024 ## 0.29.0 **`(internal):`** Upgrade to IRv48. **`(feat):`** Add support for pagination endpoints that require request body properties. **`(feat):`** Add support for pagination with an offset step. This is useful for endpoints that page based on the element index rather than a page index (i.e. the 100th element vs. the 10th page). This feature shares the same UX as both the `offset` and `cursor` pagination variants. ## 0.29.0-rc0 **`(fix):`** All serializers in the generated SDK are now synchronous. This makes the serializers easier to use and improves the performance as well. ## 0.28.0-rc0 **`(feat):`** Add support for offset pagination, which uses the same pagination API introduced in `0.26.0-rc0`. --- # July 8, 2024 ## 0.27.2 **`(fix):`** The generated readme now moves the sections for `AbortController`, `Runtime Compatibility` and `Custom Fetcher` under the Advanced section in the generated README. ## 0.27.1 **`(feat):`** Support JSR publishing. If you would like your SDK to be published to JSR, there is now a configuration option called `publishToJsr: true`. When enabled, the generator will generate a `jsr.json` as well as a GitHub workflow to publish to JSR. ```yaml - name: fernapi/fern-typescript-sdk version: 0.27.1 config: publishToJsr: true ``` ## 0.27.0 **`(fix):`** Boolean literal headers can now be overridden via `RequestOptions`. **`(feat):`** The generated `.github/workflows/ci.yml` file now supports NPM publishing with alpha/beta dist tags. If the selected version contains the `alpha` or `beta` substring, the associated dist tag will be added in the `npm publish` command like the following: ```sh --- # Version 1.0.0-beta npm publish --tag beta ``` For more on NPM dist tags, see [https://docs.npmjs.com/adding-dist-tags-to-packages](https://docs.npmjs.com/adding-dist-tags-to-packages) --- # June 30, 2024 ## 0.26.0-rc3 **`(fix):`** The typescript generator now returns all `FormData` headers and Fetcher no longer stringifies stream.Readable type. --- # June 27, 2024 ## 0.26.0-rc2 **`(feat):`** `RequestOptions` now supports overriding global headers like authentication and version. ## 0.26.0-rc1 **`(fix):`** The generator was skipping auto pagination for item arrays that were optional. Now, those are safely handled as well. ## 0.26.0-rc0 **`(feat):`** The TypeScript generator now supports cursor-based auto pagination. With auto pagination, a user can simply iterate over the results automatically: ```ts for (const user of client.users.list()) { consoler.log(user); } ``` Users can also paginate over data manually ```ts const page = client.users.list(); for (const user of page.data) { consoler.log(user); } // Helper methods for manually paginating: while (page.hasNextPage()) { page = page.getNextPage(); // ... } ``` --- # June 26, 2024 ## 0.25.3 **`(internal):`** The generator is now upgraded to `v46.2.0` of the IR. --- # June 20, 2024 ## 0.25.2 **`(fix):`** The generator now removes `fs`, `path`, and `os` dependencies from the browser runtime. ## 0.25.1 **`(fix):`** The generator now removes `fs`, `path`, and `os` dependencies from the browser runtime. --- # June 19, 2024 ## 0.25.0 **`(fix):`** The generator now generates snippets for streaming endpoints. There is also a fix where literals are excluded from inlined requests. ## 0.25.0-rc0 **`(feat):`** The generator now merges the user's original `README.md` file (if any). ## 0.24.4 **`(fix):`** APIs that specify a default environment no longer include an unused environment import in their generated snippets. ## 0.24.2 **`(feat):`** Remove the unnecessary client call from the request/response README.md section. **`(fix):`** The generated README.md snippets now correctly referenced nested methods. For example, `client.users.create` (instead of `client.create`) in the following: ```ts import { AcmeClient } from "acme"; const client = new AcmeClient({ apiKey: "YOUR_API_KEY" }); await client.users.create({ firstName: "john", lastName: "doe" }); ``` ## 0.24.1 **`(fix):`** Dynamic snippets now support importing the client directly from the package. ```typescript import { MyClient } from "@org/sdk"; const client = new MyClient({ ... }); ``` --- # June 18, 2024 ## 0.24.3 **`(fix):`** The generator only adds a publish step in github actions if credentials are specified. ## 0.24.0 **`(feat):`** Add dynamic client instantiation snippets ## 0.24.0-rc0 **`(feat):`** Dynamic client instantiation snippets are now generated. Note this only affects enterprise users that are using Fern's Snippets API. --- # June 17, 2024 ## 0.23.3 **`(fix):`** The NPM publish job is *not* generated if the token environment variable is not specified. **`(feat):`** The snippets now use the `client` variable name like so: ```ts import { AcmeClient } from "acme"; const client = new AcmeClient({ apiKey: "YOUR_API_KEY" }); await client.users.create({ firstName: "john", lastName: "doe" }); ``` --- # June 14, 2024 ## 0.23.2 **`(fix):`** Client constructor snippets now include an `environment` property whenever it's required. **`(fix):`** The import paths included in the `README.md` exclusively use double quotes. **`(fix):`** When an NPM package name is not specified, the generated `README.md` will default to using the namespace export. --- # June 13, 2024 ## 0.23.1 **`(fix):`** Undiscriminated unions used as map keys examples no longer return an error. --- # June 12, 2024 ## 0.23.0 **`(fix):`** The latest version of the `generator-cli` (used to generate `README.md` files) is always installed. --- # June 11, 2024 ## 0.23.0-rc1 **`(fix):`** Introduce a custom configuration for arbitrary package json field. Now you can specify arbitrary key, value pairs that you want to be merged in the generated `package.json`. ```yml config: packageJson: dependencies: my-dep: "2.0.0" bin: "./index.js" ``` --- # June 7, 2024 ## 0.23.0-rc0 **`(fix):`** Union snippet templates are fixed in 2 ways: 1. The templates do not have a leading single quote (a typo from before) 2. The templates now inline union properties (in certain cases) ## 0.22.0 **`(feat):`** Add support for higher quality `README.md` generation. --- # June 5, 2024 ## 0.21.1 **`(feat):`** Detect `workerd` (Cloudflare) environments in `Runtime.ts`. The `Stream` class which is used for Server-Sent Events now prefers `TextDecoder` if it is present in the environment, to work in Cloudflare environments. ## 0.21.0 **`(feat):`** The generator now supports `bigint` types. **`(internal):`** Bump to IRv46. --- # June 2, 2024 ## 0.20.9 **`(fix):`** TypeScript generator outputs code snippets that have `example-identifier` embedded. ## 0.20.8 **`(feat):`** TypeScript projects were skipping added peer dependencies in certain cases, now those are fixed. --- # May 31, 2024 ## 0.20.7 **`(fix):`** Simplify the error handling introduced in `0.20.6` so that it more easily handles endpoints that include structured errors. ## 0.20.6 **`(fix):`** This updates the behavior of the failure condition introduced in `0.20.2`; the SDK now throws an error whenever we fail to refresh an access token even if `neverThrowErrors` is set. We treat this failure as a systematic exception, so it's OK to throw in this case. --- # May 30, 2024 ## 0.20.5 **`(feat):`** Support setting `extraPeerDependencies` and `extraPeerDependenciesMeta` as configuration arguments. For example: ```yaml extraPeerDependencies: "openai": "^4.47.1" extraPeerDependenciesMeta: "openai": optional: true ``` --- # May 29, 2024 ## 0.20.4 **`(fix):`** Functionality to generate integration tests against a mock server has been disabled. ## 0.20.2 **`(fix):`** The OAuth token provider supports SDKs that enable the `neverThrowErrors` setting. If the OAuth token provider fails to retrieve and/or refresh an access token, an error will *not* be thrown. Instead, the original access token will be used and the user will be able to act upon an error available on the response. For example, ```ts const response = await client.user.get(...) if (!response.ok) { // Handle the response.error ... } ``` ## 0.20.1 **`(fix):`** Remove node:stream imports for Webpack and Next.js compatibility **`(fix):`** Fix URL encoded body encoding in fetcher ## 0.20.1-rc0 **`(fix):`** URL encoded bodies are now appropriately encoded within the fetcher. --- # May 24, 2024 ## 0.20.0-rc1 **`(fix):`** Pass `abortSignal` to `Stream` for server-sent-events and JSON streams so that the user can opt out and break from a stream. ## 0.20.0-rc0 **`(feat):`** Add `abortSignal` to `RequestOptions`. SDK consumers can now specify an an arbitrary abort signal that can interrupt the API call. ```ts const controller = new AbortController(); client.endpoint.call(..., { abortSignal: controller.signal, }) ``` --- # May 20, 2024 ## 0.19.0 **`(feat):`** Add `inlineFileProperties` configuration to support generating file upload properties as in-lined request properties (instead of positional parameters). Simply configure the following: ```yaml - name: fernapi/fern-typscript-node-sdk version: 0.19.0 ... config: inlineFileProperties: true ``` **Before**: ```ts /** * @param {File | fs.ReadStream} file * @param {File[] | fs.ReadStream[]} fileList * @param {File | fs.ReadStream | undefined} maybeFile * @param {File[] | fs.ReadStream[] | undefined} maybeFileList * @param {Acme.MyRequest} request * @param {Service.RequestOptions} requestOptions - Request-specific configuration. * * @example * await client.service.post(fs.createReadStream("/path/to/your/file"), [fs.createReadStream("/path/to/your/file")], fs.createReadStream("/path/to/your/file"), [fs.createReadStream("/path/to/your/file")], {}) */ public async post( file: File | fs.ReadStream, fileList: File[] | fs.ReadStream[], maybeFile: File | fs.ReadStream | undefined, maybeFileList: File[] | fs.ReadStream[] | undefined, request: Acme.MyRequest, requestOptions?: Acme.RequestOptions ): Promise { ... } ``` **After**: ```ts /** * @param {Acme.MyRequest} request * @param {Service.RequestOptions} requestOptions - Request-specific configuration. * * @example * await client.service.post({ * file: fs.createReadStream("/path/to/your/file"), * fileList: [fs.createReadStream("/path/to/your/file")] * }) */ public async post( request: Acme.MyRequest, requestOptions?: Service.RequestOptions ): Promise { ... } ``` --- # May 17, 2024 ## 0.18.3 **`(internal):`** The generator now uses the latest FDR SDK. --- # May 15, 2024 ## 0.18.2 **`(fix):`** If OAuth is configured, the generated `getAuthorizationHeader` helper now treats the bearer token as optional. This prevents us from sending the `Authorization` header when retrieving the access token. --- # May 14, 2024 ## 0.18.1 **`(fix):`** If OAuth environment variables are specified, the `clientId` and `clientSecret` parameters are optional. ```ts export declare namespace Client { interface Options { ... clientId?: core.Supplier; clientSecret?: core.Supplier; } ... } ``` --- # May 13, 2024 ## 0.18.0 **`(feat):`** Add support for the OAuth client credentials flow. The new `OAuthTokenProvider` automatically resolves the access token and refreshes it as needed. The resolved access token is then used as the bearer token in all client requests. --- # May 6, 2024 ## 0.17.1 **`(fix):`** Multipart form data requests are now compatible across browser and Node.js runtimes. ## 0.17.0 **`(internal):`** Bump to v43 of IR which means that you will need `0.26.1` of the Fern CLI version. To bump your CLI version, please run `fern upgrade`. ## 0.16.0-rc8 **`(feat):`** The SDK generator now supports upload endpoints that specify an array of files like so: ```ts /** * @param {File[] | fs.ReadStream[]} files * @param {Acme.UploadFileRequest} request * @param {Service.RequestOptions} requestOptions - Request-specific configuration. */ public async post( files: File[] | fs.ReadStream[], request: Acme.UploadFileRequest, requestOptions?: Service.RequestOptions ): Promise { const _request = new FormData(); for (const _file of files) { _request.append("files", _file); } ... } ``` --- # April 30, 2024 ## 0.16.0-rc7 **`(feat):`** The SDK generator now supports `@param` JSDoc comments for endpoint parameters. The generator now arranges JSDoc in a few separate groups, one for each of `@param`, `@throws`, and `@examples` like so: ```ts /** * This endpoint checks the health of a resource. * * @param {string} id - A unique identifier. * @param {Service.RequestOptions} requestOptions - Request-specific configuration. * * @throws {@link Acme.UnauthorizedRequest} * @throws {@link Acme.BadRequest} * * @example * await testSdk.health.service.check("id-2sdx82h") */ public async check(id: string, requestOptions?: Service.RequestOptions): Promise { ... } ``` **`(feat):`** The generator will only include user-provided examples if they exist, and otherwise only include a single generated example, like so: ```ts /** * This endpoint checks the health of a resource. * * @example * await testSdk.health.service.check("id-2sdx82h") */ public async check(id: string, requestOptions?: Service.RequestOptions): Promise { ... } ``` **`(fix):`** The SDK generator now escapes path parameters that would previously create invalid URLs (e.g. "\example"). Method implementations will now have references to `encodeURIComponent` like the following: ```ts const _response = await core.fetcher({ url: urlJoin( (await core.Supplier.get(this._options.environment)) ?? environments.AcmeEnvironment.Prod, `/users/${encodeURIComponent(userId)}` ), ... }); ``` ## 0.16.0-rc6 **`(fix):`** snippet templates now move file upload parameters to unnamed args ## 0.16.0-rc5 **`(fix):`** remove duplicate quotation marks in snippet templates --- # April 25, 2024 ## 0.16.0-rc4 **`(fix):`** fixes to styling of the SDK code snippet templates. --- # April 24, 2024 ## 0.16.0-rc0 **`(feat):`** The generator now registers snippet templates which can be used for dynamic SDK code snippet generation. ## 0.15.1-rc1 **`(feat):`** Earlier for inlined request exports, we were doing the following: ```ts export { MyRequest } from "./MyRequest"; ``` In an effort to make the generated code JSR compatible, the TS generator will now append the `type` explicitly for request exports. ```ts export { type MyRequest } from "./MyRequest"; ``` --- # April 22, 2024 ## 0.15.1-rc0 **`(feat):`** plain text responses are now supported in the TypeScript generator. ## 0.15.0-rc1 **`(fix):`** Minor fixes to SSE processing. In particular, stream terminal characters are now respected like `[DONE]` and JSON parsed data is sent to the deserialize function. --- # April 19, 2024 ## 0.15.0-rc0 **`(feat):`** Bump to v38 of IR and support server-sent events where the events are sent with a `data: ` prefix and terminated with a new line. --- # April 17, 2024 ## 0.14.1-rc5 **`(fix):`** Code snippets are generated for file upload endpoints using `fs.readStream`. Previously, generation for these endpoints was being skipped. **`(fix):`** If integration tests are not enabled, simple jest tests with a `yarn test` script will be created. **`(feat):`** In an effort to make the generated code JSR compatible, the generator now directly imports from files instead of using directory imports. **`(feat):`** In an effort to make the generated code JSR compatible, we make sure all methods are strongly typed with return signatures (in this case `_getAuthorizationHeader()`). **`(fix):`** Generate code snippet for FileDownload endpoint **`(fix):`** Import for `node-fetch` in `Fetcher.ts` uses a dynamic import instead of `require` which so that the SDK works in ESM environments (that are using local file output). When the `outputEsm` config flag is turned on, the dynamic import will be turned into an ESM specific import. **`(fix):`** The test job in `ci.yml` works even if you have not configured Fern to generate integration tests. Without integration tests the test job will run `yarn && yarn test`. With the integration tests, the test job will delegate to the fern cli `fern yarn test`. **`(feat):`** Add `allowExtraFields` option to permit extra fields in the serialized request. ```yaml - name: fernapi/fern-typscript-node-sdk version: 0.14.0-rc0 ... config: allowExtraFields: true ``` --- # April 9, 2024 ## 0.13.0 **`(internal):`** Support V37 of the IR. --- # April 2, 2024 ## 0.13.0-rc0 **`(feat):`** Add `retainOriginalCasing` option to preserve the naming convention expressed in the API. For example, the following Fern definition will generate a type like so: ```yaml types: GetUsersRequest properties: group_id: string ``` **Before** ```typescript export interface GetUsersRequest { groupId: string; } export interface GetUsersRequest = core.serialization.object({ groupId: core.serialization.string("group_id") }) export namespace GetUsersRequest { interface Raw { group_id: string } } ``` **After** ```typescript export interface GetUsersRequest { group_id: string; } export interface GetUsersRequest = core.serialization.object({ group_id: core.serialization.string() }) export namespace GetUsersRequest { interface Raw { group_id: string } } ``` --- # March 22, 2024 ## 0.12.9 **`(fix):`** The generator stopped working for remote code generation starting in `0.12.7`. This is now fixed. ## 0.12.8 **`(feat):`** Enhance serde performance by reducing reliance on async behavior and lazy async dynamic imports. **`(internal):`** Shared generator notification and config parsing logic. --- # March 18, 2024 ## 0.12.8-rc0 **`(feat):`** Enhance serde performance by reducing reliance on async behavior and lazy async dynamic imports. --- # March 14, 2024 ## 0.12.7 **`(feat):`** the SDK will now leverage environment variable defaults, where specified, for authentication variables, such as bearer tokens, api keys, custom headers, etc. Previously, the SDK would only leverage these defaults for bearer token auth IF auth was mandatory throughout the SDK. --- # February 27, 2024 ## 0.12.6 **`(fix):`** In Node.js environments the SDK will default to using `node-fetch`. The SDK depends on v2 of node-fetch to stay CJS compatible. Previously the SDK was doing `require("node-fetch")` but it should be `require("node-fetch").default` based on [https://github.com/node-fetch/node-fetch/issues/450#issuecomment-387045223](https://github.com/node-fetch/node-fetch/issues/450#issuecomment-387045223). ## 0.12.5 **`(feat):`** Introduce a custom configuration called `tolerateRepublish` which supports running npm publish with the flag `--tolerateRepublish`. This flag allows you to publish on top of an existing npm package. To turn on this flag, update your generators.yml: ```yaml groups: generators: - name: fernapi/fern-typscript-node-sdk version: 0.12.5 ... config: tolerateRepublish: true ``` ## 0.12.4 **`(fix):`** Previously reference.md was just leveraging the function name for the reference, now it leverages the full package-scoped path, mirroring how the function would be used in reality. ```ts seedExamples.getException(...) // is now seedExamples.file.notification.service.getException(...) ``` **`(fix):`** Previously SDK code snippets would not support generation with undiscriminated unions. Now, it does. ## 0.12.2 **`(fix):`** Previously SDK code snippets would not take into account default parameter values and would always include a `{}`. This was odd and didn't represent how a developer would use the SDK. Now, the snippets check for default parameter values and omit if there are no fields specified. ```ts // Before client.users.list({}); // After client.users.list(); ``` ## 0.12.1 **`(fix):`** Optional objects in deep query parameters were previously being incorrectly serialized. Before this change, optional objects were just being JSON.stringified which would send the incorrect contents over the wire. ```ts // Before if (foo != null) { _queryParams["foo"] = JSON.stringify(foo); } // After if (foo != null) { _queryParams["foo"] = foo; } // After (with serde layer) if (foo != null) { _queryParams["foo"] = serializers.Foo.jsonOrThrow(foo, { skipValidation: false, breadcrumbs: ["request", "foo"] }); } ``` --- # February 26, 2024 ## 0.12.0 **`(feat):`** support deep object query parameter serialization. If, query parameters are objects then Fern will support serializing them. ```yaml MyFoo: properties: bar: optional query-parameters: foo: MyFoo ``` will now be serialized as `?foo[bar]="...` and appear in the SDK as a regular object ```ts client.doThing({ foo: { bar: "..." } }); ``` --- # February 15, 2024 ## 0.11.5 **`(fix):`** Previously `core.Stream` would not work in the Browser. Now the generated Fern SDK includes a polyfill for `ReadableStream` and uses `TextDecoder` instead of `Buffer`. **`(feat):`** add in a reference markdown file, this shows a quick outline of the available endpoints, it's documentation, code snippet, and parameters. This feature is currently behind a feature flag called `includeApiReference` and can be used ```yaml config: includeApiReference: true ``` ## 0.11.4 **`(fix):`** The `Fetcher` now supports sending binary as a request body. This is important for APIs that intake `application/octet-stream` content types or for folks that have .fernignored their and added custom utilities that leverage the fetcher. --- # February 13, 2024 ## 0.11.3 **`(fix):`** ensure SDK generator always uses `node-fetch` in Node.js environments. There is an experimental fetch packaged with newer versions of Node.js, however it causes unexpected behavior with file uploads. ## 0.11.2 **`(fix):`** ensure SDK generator does not drop additional parameters from requests that perform file upload. Previously, if an endpoint had `file` inputs without additional `body` parameters, query parameters were erroneously ignored. ## 0.11.1 **`(fix):`** The SDK generator no longer generates a `tsconfig.json` with `noUnusedParameters` enabled. This check was too strict. ## 0.11.0 **`(feat):`** The SDK generator now forwards information about the runtime that it is being used in. The header `X-Fern-Runtime` will report the runtime (e.g. `browser`, `node`, `deno`) and the header `X-Fern-Runtime-Version` will report the version. --- # February 11, 2024 ## 0.10.0 **`(feat):`** The SDK generator now supports whitelabelling. When this is turned on, there will be no mention of Fern in the generated code. **Note**: You must be on the enterprise tier to enable this mode. ## 0.9.7 **`(chore):`** Initialize this changelog --- # Python quickstart > Learn how to generate a Python SDK with Fern. Step-by-step guide to configure generators.yml, run fern generate, and create client libraries. Generate a Python SDK by following the instructions on this page. This page assumes that you have: * An initialized `fern` folder. See [Set up the `fern` folder](/sdks/overview/quickstart). * A GitHub repository for your SDK. See [Project Structure](/sdks/overview/project-structure). ### Pass `fern check` Run `fern check` to ensure that your API definition is valid. If there are any errors, fix them before proceeding. If you're using an OpenAPI Specification, check out all of our [supported extensions](/learn/api-definition/openapi/extensions). ### Add the SDK generator Run the following command to add the Python SDK generator to `generators.yml`: ```bash fern add fern-python-sdk --group python-sdk ``` `python-sdk` is the name of the `generators.yml` group that configures your Python SDK's output location and other metadata. You can customize this group name to differentiate between multiple SDKs across different languages (e.g., `ruby-sdk`, etc) in your organization. This command adds the following `group` to `generators.yml`: ```yaml title="generators.yml" python-sdk: # group name generators: - name: fernapi/fern-python-sdk version: 4.50.1 output: location: local-file-system path: ../sdks/python ``` ### Generate the SDK Run the following command to generate your SDK: ```bash fern generate --group python-sdk ``` If you have multiple APIs, use the [`--api` flag](/cli-api-reference/cli-reference/commands#api) to specify the API you want to generate: ```bash fern generate --group python-sdk --api your-api-name ``` This creates a `sdks` folder in your current directory. The resulting folder structure looks like this: Some files, including `pyproject.toml` and `README.md` , are only generated on paid plans. To get the fully generated SDK, schedule a [demo](https://buildwithfern.com/contact) or [email us](mailto:support@buildwithfern.com) . --- # Python configuration > Configuration options for the Fern Python SDK. You can customize the behavior of the Python SDK generator in `generators.yml`: ```yaml {6-15} title="generators.yml" groups: python-sdk: generators: - name: fernapi/fern-python version: 4.50.1 config: package_name: "your_package" client_class_name: "YourClient" additional_init_exports: - from: file_with_custom_function imports: - custom_function pydantic_config: skip_validation: true environment_class_name: "AcmeEnvironment" ``` Additional modules or classes to export from the package's `__init__.py` file. This allows you to customize what's available when users import your package. Each object should specify which file to import from and what to import: ```yaml config: additional_init_exports: - from: core.oauth_flow imports: - validate_token - from: utils.helpers imports: - format_currency - PhoneValidator ``` This enables users to access your custom functions directly: ```python from my_package import validate_token, format_currency, PhoneValidator ``` The module path to import from, using Python dot notation. Omit the `.py` extension and replace path separators with dots. For example, if you want to import from the file `core/oauth_flow.py`, specify that as `- from: core.oauth_flow`. List of class names, function names, or other objects to import from the specified file. The name of the generated client class. Must be PascalCase. For example, setting `client_class_name: "Acme"` generates a client that users import as `from your_package import Acme`. The chunk size to use (if any) when processing a response bytes stream within `iter_bytes` or `aiter_bytes` results in: `for chunk in response.iter_bytes(chunk_size=):` When enabled, generates [mock server (wire) tests](/sdks/deep-dives/testing#mock-server-tests) to verify that the SDK sends and receives HTTP requests as expected. When enabled, excludes type definitions from being exported in the package's `__init__.py` file, reducing the public API surface. Customize the name of the generated environment class/enum. By default, the environment class is named `{ClientName}Environment` (e.g., `AcmeEnvironment` for a client named `Acme`). This feature is available only for the [Pro and Enterprise plans](https://buildwithfern.com/pricing). To get started, reach out to [support@buildwithfern.com](mailto:support@buildwithfern.com). If you want to add custom dependencies to your generated SDK, you can specify them using this configuration. For example, to add a dependency on boto3, your config would look like: ```yaml config: extra_dependencies: boto3: 1.28.15 ``` This feature is available only for the [Pro and Enterprise plans](https://buildwithfern.com/pricing). To get started, reach out to [support@buildwithfern.com](mailto:support@buildwithfern.com). Specify additional development dependencies to include in the generated SDK's setup configuration. These are dependencies used for development and testing but not required by end users. Define optional dependency groups that users can install with your package using pip extras (e.g., `pip install your-package[extra-name]`). When enabled, generates a flatter package structure by reducing nested directories and modules. Whether to follow redirects by default in HTTP requests. Feature flag that improves imports in the Python SDK by removing nested `resources` directory Whether or not to include legacy wire tests in the generated SDK When enabled, generates utility methods for working with union types, including factory methods and visitor patterns. If true, treats path parameters as named parameters in endpoint functions. Feature flag that removes the usage of request objects, and instead uses parameters in function signatures where possible. Enables lazy loading of client imports. When enabled, modules and classes are imported only when first accessed rather than at package initialization. This reduces memory footprint when using a small portion of a large API, at the cost of a latency penalty when first accessing a client. Set to `false` to restore eager loading behavior. Specifies the Python package name that users will import your generated client from. For example, setting `package_name: "my_custom_package"` enables users to use `my_custom_package import Client` to import your client. This changes your declared python dependency, which is not meant to be done often if at all. This is a last resort if any dependencies force you to change your version requirements. Allow specifying arbitrary configuration to your packages `pyproject.toml` by adding a `pyproject_toml` block to your configuration whatever you include in this block will be added as-is to the `pyproject.toml` file. The config, as an example is: ```yaml config: pyproject_toml: | [tool.covcheck.group.unit.coverage] branch = 26.0 line = 62.0 [tool.covcheck.group.service.coverage] branch = 30.0 line = 67.0 ``` Feature flag that enables generation of Python websocket clients. When enabled, skips code formatting (like black) on the generated Python code. By default, the generator generates a client that times out after 60 seconds. You can customize this value by providing a different number or setting to `infinity` to get rid of timeouts. When enabled, includes the API name as part of the package structure and naming. Whether to generate Pydantic models that implement inheritance when a model utilizes the Fern `extends` keyword. Whether or not to generate `TypedDicts` instead of Pydantic Models for request objects. Whether or not to generate TypedDicts instead of Pydantic Models for file upload request objects. Note that this flag was only introduced due to an oversight in the `use_typeddict_requests` flag implementation; it should be removed in the future. ### client The `client` block provides advanced configuration for the generated client class and file structure. For most use cases, the top-level `client_class_name` option is sufficient. Use the `client` block when you need to customize filenames or have different internal and exported class names. ```yaml config: client: filename: "my_client.py" class_name: "MyClient" exported_filename: "my_client.py" exported_class_name: "MyClient" ``` The filename for the generated client file. The name of the generated client class. For most use cases, use the top-level `client_class_name` option instead. The filename of the exported client which will be used in code snippets. The name of the exported client class that will be used in code snippets. ### pydantic\_config Configure Pydantic model generation settings for your Python SDK. ```yaml config: pydantic_config: enum_type: "literals" extra_fields: "forbid" frozen: true include_union_utils: false include_validators: true orm_mode: false positional_single_property_constructors: false require_optional_fields: false skip_formatting: false skip_validation: true smart_union: true union_naming: "v0" use_inheritance_for_extended_models: true use_pydantic_field_aliases: false use_provided_defaults: true use_str_enums: true use_typeddict_requests: false wrapped_aliases: false ``` The type of enums to use in the generated models: * `literals`: Use Python Literal types, e.g. `MyEnum = Literal["foo", "bar"]` * `forward_compatible_python_enums`: Use Python Enum classes, with a `MyEnum._UNKNOWN` member for forward compatibility. `MyEnum._UNKNOWN.value` contains the raw unrecognized value. * `python_enums`: Your vanilla Python enum class, with the members defined within your API. How to handle extra fields not defined in the model schema. Whether Pydantic models should be frozen (immutable after creation). When enabled, the generator will output a Pydantic `__root__` class that will contain utilities to visit the union. For example, for the following union type: ``` types: Shape: union: circle: Circle triangle: Triangle ``` you will get a generated `Shape` class that has a factory and visitor: ```python # Use a factory to instantiate the union Shape.factory.circle(Circle(...)) # Visit every case in the union shape = get_shape() shape.visit( circle: lambda circle: do_something_with_circle(circle), triangle: lambda triangle: do_something_with_triangle(triangle), ) ``` Include custom validators in generated Pydantic models. Enable ORM mode for Pydantic models to work with ORMs like SQLAlchemy. When enabled, generates a custom `__init__` method for models with a single required field, allowing positional argument construction instead of requiring keyword arguments. ```python # Without positional_single_property_constructors (default) wrapper = Wrapper(value="my_value") # With positional_single_property_constructors enabled wrapper = Wrapper("my_value") ``` Enabling this option can cause backwards compatibility issues. If a model later adds another required field, the positional `__init__` will no longer be generated, causing runtime failures for existing code that uses positional arguments. Use keyword arguments for long-term stability. Custom package name for the generated models. Whether optional fields must be explicitly provided (cannot be omitted). Skip code formatting for generated Pydantic models. When enabled, disables Pydantic validation for API responses. This ensures that Pydantic does not immediately fail if the model being returned from an API does not exactly match the Pydantic model. This is meant to add flexibility should your SDK fall behind your API, but should be used sparingly, as the type-hinting for users will still reflect the Pydantic model exactly. Enable smart union handling in Pydantic models for better type discrimination. Control union naming strategy. If you are dealing with discriminated union members that already have the discriminant property on them (and they're only used in one union), you should prefer the global API config within your `generators.yml`: ```yaml - name: fernapi/fern-python-sdk version: 3.0.0-rc0 api: settings: unions: v1 ``` Use Pydantic field aliases for property names that differ from wire format. Leverage defaults specified in the API specification. Generate TypedDicts instead of Pydantic Models for request objects. By default, the generator generates pydantic models that are v1 and v2 compatible. However you can override them to: * `v1`: strictly use Pydantic v1 * `v2`: strictly use Pydantic v2 * `both`: maintain compatibility with both versions * `v1_on_v2`: use Pydantic v1 compatibility layer on v2 Enable wrapped aliases for Pydantic models. Only supported in Pydantic V1, V1\_ON\_V2, or V2. Generate Pydantic models that implement inheritance when a model utilizes the Fern `extends` keyword. --- # Publishing to PyPI > How to publish the Fern Python SDK to PyPI. Publish your public-facing Fern Python SDK to the [PyPI registry](https://pypi.org/). After following the steps on this page, you'll have a versioned package published on PyPI. Versioned package published on PyPI This page assumes that you have: * An initialized `fern` folder. See [Set up the `fern` folder](/sdks/overview/quickstart). * A GitHub repository for your Python SDK. See [Project structure](/sdks/overview/project-structure). * A Python generator group in `generators.yml`. See [Python Quickstart](quickstart#add-the-sdk-generator). ## Configure SDK package settings You'll need to update your `generators.yml` file to configure the package name, output location, and client naming for PyPi publishing. Your `generators.yml` [should live in your source repository](/sdks/overview/project-structure) (or on your local machine), not the repository that contains your Python SDK code. In the `group` for your Python SDK, change the output location in from `local-file-system` (the default) to `pypi` to indicate that Fern should publish your package directly to the PyPi registry: ```yaml title="generators.yml" {6-7} groups: python-sdk: generators: - name: fernapi/fern-python-sdk version: 4.50.1 output: location: pypi ``` Your package name must be unique in the PyPI repository, otherwise publishing your SDK to PyPI will fail. ```yaml title="generators.yml" {8} groups: python-sdk: generators: - name: fernapi/fern-python-sdk version: 4.50.1 output: location: pypi package-name: your-package-name ``` The `client-class-name` option controls the name of the generated client. This is the name customers use to import your SDK (`import { your-client-name } from 'your-package-name';`). ```yaml title="generators.yml" {9-10} groups: python-sdk: generators: - name: fernapi/fern-python-sdk version: 4.50.1 output: location: pypi package-name: your-package-name config: client_class_name: YourClientName # must be PascalCase ``` You can add publishing metadata to your PyPI package to improve discoverability and provide additional information to users. This metadata appears on your package's PyPI page and includes `keywords` for PyPI search and discovery, `documentation-link` for your package documentation, and `homepage-link` for your project homepage. You can additionally add general metadata for the SDK (description, contact email, author, license, etc.) at [the individual SDK level](/learn/sdks/reference/generators-yml#metadata-2) or [globally for all SDKs](/learn/sdks/reference/generators-yml#metadata). ```yaml title="generators.yml" {9, 13} groups: python-sdk: generators: - name: fernapi/fern-python-sdk version: 4.50.1 output: location: pypi package-name: your-package-name metadata: # Publishing metadata keywords: ["api", "sdk", "client"] documentation-link: "https://docs.yourcompany.com" homepage-link: "https://yourcompany.com" metadata: # General SDK metadata license: MIT config: client_class_name: YourClientName ``` ## Generate a PyPi token Log into [PyPi](https://pypi.org/) or create a new account. 1. Click on your profile picture. 2. Select **Account settings**. 3. Scroll down to **API Tokens**. 1. Click on **Add API Token** 2. Name your token and set the scope to the relevant projects. 3. Click **Create token** Creating a New API Token Save your new token – it won’t be displayed after you leave the page. ## Configure PyPi publication Add the path to your GitHub repository to `generators.yml`: ```yaml title="generators.yml" {11-12} groups: python-sdk: generators: - name: fernapi/fern-python-sdk version: 4.50.1 output: location: pypi package-name: your-package-name config: client_class_name: YourClientName github: repository: your-org/company-python ``` Add `token: ${PYPI_TOKEN}` to `generators.yml`. ```yaml {9} title="generators.yml" groups: python-sdk: generators: - name: fernapi/fern-python-sdk version: 4.50.1 output: location: pypi package-name: your-package-name token: ${PYPI_TOKEN} config: client_class_name: YourClientName github: repository: your-org/company-python ``` Optionally set the mode to control how Fern handles SDK publishing: * `mode: release` (default): Fern generates code, commits to main, and tags a release automatically * `mode: pull-request`: Fern generates code and creates a PR for you to review before release * `mode: push`: Fern generates code and pushes to a branch you specify for you to review before release You can also configure other settings, like the reviewers or license. Refer to the [full `github` (`generators.yml`) reference](/sdks/reference/generators-yml#github) for more information. ```yaml title="generators.yml" {14} groups: python-sdk: generators: - name: fernapi/fern-python-sdk version: 4.50.1 output: location: npm package-name: name-of-your-package token: ${PYPI_TOKEN} config: namespaceExport: YourClientName github: repository: your-org/your-repository mode: push branch: your-branch-name # Required for mode: push ``` ## Publish your SDK Decide how you want to publish your SDK to PyPi. You can use GitHub workflows for automated releases or publish directly via the CLI. Set up a release workflow via [GitHub Actions](https://docs.github.com/en/actions/get-started/quickstart) so you can trigger new SDK releases directly from your source repository. Open your Fern repository in GitHub. Click on the **Settings** tab in your repository. Then, under the **Security** section, open **Secrets and variables** > **Actions**. Adding GitHub Repository Secret You can also use the url `https://github.com//settings/secrets/actions`. 1. Select **New repository secret**. 2. Name your secret `PYPI_TOKEN`. 3. Add the corresponding token you generated above. 4. Click **Add secret**. PYPI_TOKEN secret 1. Select **New repository secret**. 2. Name your secret `FERN_TOKEN`. 3. Add your Fern token. If you don't already have one, generate one by running `fern token`. By default, the `fern_token` is generated for the organization listed in `fern.config.json`. 4. Click **Add secret**. Set up a CI workflow that you can manually trigger from the GitHub UI. In your repository, navigate to **Actions**. Select **New workflow**, then **Set up workflow yourself**. Add a workflow that's similar to this: ```yaml title=".github/workflows/publish.yml" maxLines=0 name: Publish Python SDK on: workflow_dispatch: inputs: version: description: "The version of the Python SDK that you would like to release" required: true type: string jobs: release: runs-on: ubuntu-latest steps: - name: Checkout repo uses: actions/checkout@v4 - name: Install Fern CLI run: npm install -g fern-api - name: Release Python SDK env: FERN_TOKEN: ${{ secrets.FERN_TOKEN }} PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} run: | fern generate --group python-sdk --version ${{ inputs.version }} --log-level debug ``` Navigate to the **Actions** tab, select the workflow you just created, specify a version number, and click **Run workflow**. This regenerates your SDK. Running Python publish workflow The rest of the release process depends on your chosen mode: * **Release mode (default):** If you didn't specify a `mode` or set `mode: release`, no further action is required. Fern automatically tags the new release with your specified version number and initiates the publishing workflow in your SDK repository. * **Pull request or push mode:** If you set `mode: pull-request` or `mode: push`, Fern creates a pull request or pushes to a branch respectively. Review and merge the PR (`pull-request`) or branch (`push`), then [tag a new release](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository) to initiate the publishing workflow in your SDK repository. Once the workflow completes, you can view your new release by logging into PyPi and navigating to **Your projects**. Set the `PYPI_TOKEN` environment variable on your local machine: ```bash export PYPI_TOKEN=your-actual-pypi-token ``` Regenerate your SDK, specifying the version: ```bash fern generate --group python-sdk --version ``` The rest of the release process depends on your chosen mode: * **Release mode (default):** If you didn't specify a `mode` or set `mode: release`, no further action is required. Fern automatically tags the new release with your specified version number and initiates the publishing workflow in your SDK repository. * **Pull request or push mode:** If you set `mode: pull-request` or `mode: push`, Fern creates a pull request or pushes to a branch respectively. Review and merge the PR (`pull-request`) or branch (`push`), then [tag a new release](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository) to initiate the publishing workflow in your SDK repository. Once the workflow completes, you can view your new release by logging into PyPi and navigating to **Your projects**. --- # Adding custom code > Learn how to add custom logic, methods, and dependencies to your Python SDK. Extend Fern-generated clients with custom code. This page covers how to add custom logic, methods, and dependencies to your Python SDK. Before getting started, [read about how Fern SDKs use custom code and learn about the `.fernignore` file](/sdks/overview/custom-code) . ## Adding custom logic To get started adding custom code: ### Create a new file and add your custom logic ```python title="src//helper.py" def my_helper() -> None: print("Hello World!") ``` ### Add your file to `.fernignore` ```yaml {3} title=".fernignore" # Specify files that shouldn't be modified by Fern src//helper.py ``` ### Consume the helper Now your users can consume the helper function by importing it from the SDK. ```python from package.helper import my_helper my_helper() ``` ## Adding custom SDK methods Fern also allows you to add custom methods to the SDK itself (e.g. `client.my_method()` ) by inheriting the Fern generated client and then extending it. See an example from ElevenLabs using this process in their [Python SDK](https://github.com/elevenlabs/elevenlabs-python/blob/main/src/elevenlabs/client.py). ### Update `generators.yml` configuration Name your Fern-generated client something like `BaseClient` to reflect that this client will be extended. Configure the generator to output the client in a file called `base_client.py`. ```yaml {4-8} title="generators.yml" - name: fernapi/fern-python-sdk version: "..." config: client: class_name: BaseClient # The name of the generated client you will extend filename: base_client.py # The name of the file the generated client will live in exported_class_name: YourClient # The name of the class you will be creating that extends the generated client exported_filename: client.py ``` ### Generate the SDK Trigger SDK generation by running `fern generate`: ```bash fern generate --group sdk ``` ### Import and extend the generated client First, import the Fern generated base clients from `.base_client.py` and extend them to create your custom clients. Then, add whatever methods you want. ```python title="src//client.py" from .base_client import BaseClient // import generated client class YourClient(BaseClient): // extend generated client def my_helper(self) -> None: print("Hello World!") def my_helper(self) -> None: print("Hello World") ``` See an example [client.py](https://github.com/elevenlabs/elevenlabs-python/blob/main/src/elevenlabs/client.py) from ElevenLabs. ### Update `.fernignore` Add the `client.py` to `.fernignore`. ```diff title=".fernignore" + src//client.py ``` See an example [.fernignore](https://github.com/elevenlabs/elevenlabs-python/blob/main/.fernignore) from ElevenLabs. ### Consume the method Now your users can consume the helper function by importing it from the SDK. ```python client.my_helper() ``` ## Adding custom dependencies This feature is available only for the [Pro and Enterprise plans](https://buildwithfern.com/pricing). To get started, reach out to [support@buildwithfern.com](mailto:support@buildwithfern.com). To add packages that your custom code requires, update your `generators.yml`. ```yaml {4-7} title="generators.yml" - name: fernapi/fern-python-sdk version: "..." config: extra_dependencies: numpy: '1.2.0' extra_dev_dependencies: requests_mock: '1.12.1' ``` --- # Dynamic authentication > Implement dynamic authentication patterns like short-lived JWT signing in Python SDKs using method overrides. Your API may require dynamic authentication where credentials need to be generated or refreshed for each request, such as signing short-lived JWTs or rotating tokens. Python SDKs support this pattern through method overrides. ## Method override pattern For Python SDKs, you can implement dynamic authentication by extending the generated client and overriding methods to inject authentication logic. ### Example: Short-lived JWT signing Here's how to implement JWT signing for Python SDKs: ### Create a wrapper client Create a custom client class that extends the generated Fern client and adds JWT signing logic: ```python title="src/wrapper/client.py" from .client import PlantStoreClient as FernClient import jwt import time from typing import Optional, Dict, Any class PlantStoreClient(FernClient): def __init__(self, *, private_key: str, environment: str): super().__init__(environment=environment) self._private_key = private_key def _generate_jwt(self) -> str: """Generate a short-lived JWT token valid for 15 seconds""" now = int(time.time()) payload = { "iat": now, "exp": now + 15, } return jwt.encode(payload, self._private_key, algorithm="RS256") def _with_jwt(self, request_options: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: """Inject JWT into request options""" token = self._generate_jwt() options = request_options or {} headers = options.get("headers", {}) headers["Authorization"] = f"Bearer {token}" options["headers"] = headers return options def get_plant(self, plant_id: str, *, request_options: Optional[Dict[str, Any]] = None): return super().plants.get(plant_id, request_options=self._with_jwt(request_options)) def create_plant(self, request: Any, *, request_options: Optional[Dict[str, Any]] = None): return super().plants.create(request, request_options=self._with_jwt(request_options)) # Override additional methods as needed... ``` ### Export the wrapper client Update your `__init__.py` to export the wrapper instead of the generated client: ```python title="src/__init__.py" from .wrapper.client import PlantStoreClient __all__ = ["PlantStoreClient"] ``` ### Add to `.fernignore` Protect your custom code from being overwritten: ```diff title=".fernignore" + src/wrapper + src/__init__.py ``` ### Use the client Users can use the client with automatic JWT signing: ```python from plant_store_sdk import PlantStoreClient import os client = PlantStoreClient( private_key=os.environ["PRIVATE_KEY"], environment="https://api.plantstore.com" ) # JWT is automatically signed and injected for each request plant = client.get_plant("monstera-123") new_plant = client.create_plant({ "name": "Fiddle Leaf Fig", "species": "Ficus lyrata" }) ``` This approach requires overriding each method individually. You'll need to override all methods that make API calls to ensure JWT authentication is applied consistently across your SDK. ## Other authentication patterns This same pattern works for other dynamic authentication scenarios: * **OAuth token refresh**: Automatically refresh expired access tokens before each request * **HMAC (Hash-based Message Authentication Code) signing**: Sign requests with HMAC signatures based on request content * **Rotating API keys**: Switch between multiple API keys based on rate limits * **Time-based tokens**: Generate tokens that include timestamps or nonces ## Important considerations ### Security considerations * **Secure key storage**: Never hardcode private keys; use environment variables or secure key management systems * **Avoid double authentication**: If your API already uses bearer token authentication in the Fern definition, be careful not to override the existing `Authorization` header. Consider using a different header name or conditionally setting the header ### Performance * **Token memoization**: Consider caching tokens to avoid regenerating them on every request. You can add a simple cache that refreshes tokens before they expire * **Grace period**: Refresh tokens slightly before they expire (e.g., 2 seconds early) to avoid edge cases where a token expires during request processing ### Header merging * **Preserve existing headers**: When injecting authentication headers, always merge with existing headers to avoid overwriting headers set by the SDK or user * **Request options**: Python SDKs accept `request_options` as a keyword argument that can include custom headers ### Time synchronization * **Clock drift**: Be aware of potential clock drift between your client and server. Consider adding tolerance to your token expiration checks * **Timestamp precision**: Use Unix timestamps (seconds since epoch) for `iat` and `exp` claims to match JWT standards ## Best practices * **Override all methods**: Ensure you override all API methods to maintain consistent authentication across your SDK * **Cache tokens appropriately**: Balance between security (shorter token lifetime) and performance (less frequent regeneration) * **Handle errors gracefully**: Implement retry logic for authentication failures and token refresh errors * **Test thoroughly**: Ensure your wrapper handles all edge cases, including concurrent requests, token expiration, and network failures * **Monitor token usage**: Log token generation and refresh events to help debug authentication issues in production ## See also * [Adding custom code](/sdks/generators/python/custom-code) - Python-specific customization guide * [Python configuration](/sdks/generators/python/configuration) - Full list of configuration options --- # January 29, 2026 ## 4.54.2 **`(fix):`** Generate CI workflow Python versions and PyPI trove classifiers dynamically based on the `pyproject_python_version` constraint. ## 4.54.1 **`(fix):`** Switch from `poetry install` to `poetry lock` after SDK generation. This performs dependency resolution and saves the lockfile without installing packages, which avoids failures when transitive dependencies require custom build tools. ## 4.54.0 **`(feat):`** Add `status_code` property to `HttpResponse` and `AsyncHttpResponse` classes. This allows users to access the HTTP status code when using `with_raw_response`. --- # January 28, 2026 ## 4.53.1 **`(fix):`** Fix literal and enum types being incorrectly JSON-serialized in multipart file upload requests. --- # January 27, 2026 ## 4.51.3 **`(fix):`** Fix WebSocket methods and iterators to avoid parsing binary messages as JSON. --- # January 26, 2026 ## 4.53.0 **`(feat):`** Add `import_paths` config option to auto-load user-defined files when the SDK is imported. This enables custom integrations (e.g., Sentry, logging) without modifying generated code. Files specified in the array (e.g., `["sentry_integration", "custom_logging"]`) are imported from the package root if they exist, using try/except to gracefully handle missing files. ## 4.52.0 **`(feat):`** Add support for inferred authentication. Fixes for wire test generation with inferred auth. ## 4.51.2 **`(fix):`** Skip generating raw client and `with_raw_response` property for intermediate clients that only have nested clients but no direct endpoints. This reduces unnecessary code generation and makes the SDK cleaner by only including raw client functionality where it's actually useful. ## 4.51.1 **`(fix):`** Fix WebSocket connections to merge `additional_query_parameters` from `request_options` into the connection URL. Query params now use the same encoding pattern as HTTP endpoints. ## 4.51.0 **`(feat):`** Add intelligent SSE parsing for discriminated unions via `parse_sse_obj()`. This function handles both data-level discrimination (discriminator inside JSON data payload) and event-level discrimination (discriminator at SSE envelope level). For event-level unions, it correctly parses the data field based on what the matching variant expects (string vs. complex object), enabling proper handling of streaming responses with mixed data types. ## 4.50.1 **`(fix):`** Fix duplicate imports in **init**.py when using additional\_init\_exports. When the same symbol was exported from both the regular types module and additional\_init\_exports, the generator would produce duplicate imports causing F811 "Redefinition of unused" ruff errors. The generator now deduplicates exports, with additional\_init\_exports taking precedence. --- # January 25, 2026 ## 4.50.0 **`(feat):`** Add `wire_tests` config group with `enabled` and `exclusions` options. The `exclusions` option allows excluding specific endpoints/services from wire test generation using definition-level selectors. The existing `enable_wire_tests` option is now deprecated in favor of `wire_tests.enabled`. --- # January 20, 2026 ## 4.49.0 **`(feat):`** Add `mypy_exclude` custom config option to exclude directories from mypy type checking. This is useful when `.fernignore` preserves directories (like `legacy/` or `tests/integration/`) that contain code incompatible with the generated SDK. --- # January 14, 2026 ## 4.48.1 **`(fix):`** Fix WireMock stub generation for streaming endpoints. When an endpoint has both streaming and non-streaming variants (via x-fern-streaming with stream-condition), the generated WireMock stubs now include request body matching criteria to differentiate between them. SSE stubs match on `stream: true` in the request body and have higher priority, ensuring wire tests correctly route streaming requests to the SSE stub. --- # January 13, 2026 ## 4.47.1 **`(chore):`** Update Dockerfile to use the latest generator-cli with improve reference.md generation. ## 4.47.0 **`(feat):`** Add `X-Fern-Runtime` (e.g. `python/3.12.7`) and `X-Fern-Platform` (e.g. `darwin/25.2.0`) telemetry headers to all requests for better runtime/platform observability. --- # January 10, 2026 ## 4.46.14 **`(fix):`** Fix Python wire test generation/runtime robustness for missing examples, OMIT handling, client setup, and multipart file uploads. --- # January 9, 2026 ## 4.46.13 **`(fix):`** Fixes Python SDK import generation to avoid invalid `._` module segments by deriving type paths from canonical declarations. ## 4.46.12 **`(fix):`** Support `bytes` as a response type for websocket channel methods. ## 4.46.11 **`(fix):`** Wire test generator now skips undefined example values and injects `X-Test-Id` in a constructor-compatible way via `headers` or `httpx_client`. --- # January 8, 2026 ## 4.46.10 **`(fix):`** Fix wire test generation to use endpoint ID for lookup instead of path matching. This fixes a bug where wire tests would call the wrong client methods when multiple namespaces have endpoints with the same HTTP method and path pattern (e.g., POST /v2/Services). ## 4.46.9 **`(fix):`** Fix wire test generation to filter out nop values when generating method arguments. This prevents invalid Python syntax like `param=` without a value when an example contains an invalid enum value or undefined property. --- # January 7, 2026 ## 4.46.8 **`(fix):`** Bump version to remove rc from version tag. ## 4.46.7-rc3 **`(fix):`** Fix wire test generation for streaming endpoints. Streaming methods return lazy iterators (Iterator\[bytes] or AsyncIterator\[bytes]) that don't execute the HTTP request until iterated. Wire tests now wrap streaming endpoint calls in 'for \_ in ...: pass' loops to ensure the HTTP request is actually made. This applies to streaming, streamParameter, and fileDownload response types. ## 4.46.7-rc2 **`(fix):`** Fixed Python SDK generation to use native Pydantic field aliases and improved core parsing so wire-key and nested/union validation works correctly across Pydantic v1/v2. --- # January 5, 2026 ## 4.46.7-rc1 **`(chore):`** Update Dockerfile to use the latest generator-cli with improve reference.md generation. --- # December 23, 2025 ## 4.46.7-rc0 **`(chore):`** Skip installation of generator-cli in Python SDK generator as it is already installed in the base image. --- # December 19, 2025 ## 4.46.6 **`(fix):`** Support custom `x-fern-sdk-method-name` on AsyncAPI operations. --- # December 18, 2025 ## 4.48.0 **`(feat):`** Add opt-in `pydantic_config.positional_single_property_constructors` to allow `Wrapper("value")` for single-required-field models (excluding discriminator literals). Note: can break if the model later adds required fields; kwargs are more stable. ## 4.46.5 **`(chore):`** Update to support IR version 62.6.0 with new WebSocketMessage.methodName field, webhook response descriptions, and OpenAPI explode parameter support. ## 4.46.4-rc2 **`(chore):`** Add sdkVersion as a top-level field in the generated metadata.json file. ## 4.46.4-rc0 **`(fix):`** Fix wire test generation to use `config.client.exported_class_name` for the client class name instead of deriving it from the organization and workspace names. This ensures wire tests import and instantiate the correct client class when a custom exported class name is configured. --- # December 17, 2025 ## 4.46.3 **`(fix):`** Fix empty request body issue where endpoints with all-optional fields would send an empty body instead of `{}`. When an endpoint has a request body type but all fields are optional, the SDK now correctly sends `{}` as valid JSON rather than omitting the body entirely. --- # December 16, 2025 ## 4.46.4-rc1 **`(fix):`** Fix URL path stripping when base URL contains path prefixes. ## 4.46.2 **`(fix):`** Fix handling of newlines in default values for strings when using `config.pydantic_config.use_provided_defaults`. ## 4.46.1 **`(fix):`** Fix OAuth token handling for optional expires\_in field with default fallback. ## 4.46.0 **`(feat):`** FastAPI Python codegen now emits parameter markers via `typing.Annotated[...]` with standard Python defaults for better FastAPI/Pydantic compatibility. --- # December 15, 2025 ## 4.45.10 **`(fix):`** Fix retry logic "off-by-two" error. The internal `retries` counter now starts at 0 instead of 2, and `max_retries` defaults to 2 when not specified. This ensures users get the expected number of retries (2 by default, or the configured `max_retries` value). --- # December 12, 2025 ## 4.45.9 **`(fix):`** Fix empty query params stripping existing URL query strings. When `params` and `additional_query_parameters` are both empty, httpx now receives `params=None` instead of `params=[]`, preserving any query parameters already present in the URL (e.g., pagination cursors like `?after=123`). ## 4.45.8 **`(fix):`** Ensures the root client always exposes a headers parameter and forwards it to the underlying ClientWrapper. ## 4.45.7 **`(fix):`** Fix client wrapper instantiation to use the correct bearer token parameter name, preventing incorrect `token=` references when custom auth parameter names are configured. --- # December 11, 2025 ## 4.45.6 **`(fix):`** Fix failing wire tests under `pytest-xdist` by using a single shared WireMock plugin. ## 4.45.5 **`(fix):`** Fix file upload conditional check using wire\_value instead of snake\_case parameter name, which caused mypy "name not defined" errors when the API field name differed from the Python parameter name (e.g., `MyFile` vs `my_file`). ## 4.45.4 **`(fix):`** Fix offset pagination to handle None items when calculating next page offset. --- # December 10, 2025 ## 4.45.3 **`(fix):`** Add return types to reference.md method signatures for consistency with other SDK generators. ## 4.45.2 **`(fix):`** Fix Python wire test generation by schema-based path/body name deconfliction and aligning client class resolution with the SDK's custom config rules. ## 4.45.1 **`(fix):`** Fix forward ref detection for complex circular type cycles. --- # December 9, 2025 ## 4.45.0 **`(feat):`** Add `coerce_numbers_to_str` option to `pydantic_config`. When enabled, numeric types (int, float, Decimal) will be coerced to strings during validation. This is useful for APIs that return numeric values as strings. ## 4.44.2 **`(fix):`** Fix enum-typed headers to use `.value` instead of `str()` for consistent wire format across all Python versions. Previously, `str(enum)` returned the enum name (e.g., `Operand.GREATER_THAN`) on Python `< 3.11`, but the wire value (e.g., `>`) on Python `>= 3.11` with StrEnum. ## 4.44.1 **`(fix):`** Remove `oauth-token-override` config flag. OAuth token override is now always enabled for OAuth client credentials flows, allowing users to authenticate with either client\_id/client\_secret OR a pre-generated bearer token directly via the `token` parameter without any configuration. --- # December 8, 2025 ## 4.44.0 **`(feat):`** Add Python 3.11+ StrEnum compatibility. Generated enums now use StrEnum for Python >= 3.11 and the (str, Enum) mixin for older versions, fixing compatibility issues with Python 3.11's stricter enum mixin handling. --- # December 6, 2025 ## 4.43.0 **`(feat):`** Add OAuth token override support. When `oauth-token-override: true` is configured, users can authenticate with either OAuth client credentials or a pre-generated bearer token directly via the `token` parameter. --- # December 5, 2025 ## 4.42.1 **`(fix):`** Fix OAuth flow regression where `SyncClientWrapper` and `AsyncClientWrapper` required a `token` parameter. The token parameter is now optional only for OAuth flows (matching TypeScript's behavior), while plain bearer auth continues to require a token when `isAuthMandatory` is true. --- # December 4, 2025 ## 4.41.11 **`(fix):`** Fix backslash escaping in endpoint and websocket docstrings. OpenAPI descriptions containing backslash sequences like `DOMAIN\username` now properly escape backslashes to avoid Python SyntaxError from invalid unicode escape sequences. ## 4.41.10 **`(fix):`** Adds `dynamic = ["version"]` to `pyproject.toml`, allowing for `uv` commands such as `uv sync` to work out-of-the-box. ## 4.41.9 **`(fix):`** Fix wire test WireMock container lifecycle to be compatible with pytest-xdist parallelization. The container is now started/stopped using pytest\_configure/pytest\_unconfigure hooks instead of a session-scoped fixture, ensuring only the controller process manages the container. --- # December 3, 2025 ## 4.41.8 **`(fix):`** Fix duplicate field names in discriminated union types. ## 4.41.7 **`(fix):`** Fix paginated response handling when response type is optional or nullable. ## 4.41.6 **`(fix):`** Fix Python wire test generation to drop literal-only params and fill in required file arguments so tests match the generated SDK signatures. ## 4.41.5 **`(fix):`** The `package_path` configuration now works as a suffix within the module hierarchy instead of a prefix. For example, `package_path: sub/dir` now generates to `src/name/sub/dir/...` enabling imports like `from name.sub.dir import Client`. ## 4.41.4 **`(fix):`** Ensure `UncheckedBaseModel.model_validate` in Pydantic v2 respects `FieldMetadata(alias=...)` so aliased fields validate correctly from JSON. --- # November 28, 2025 ## 4.42.0 **`(feat):`** Add async support for OAuth token provider. The generated SDK now includes an AsyncOAuthTokenProvider class that uses asyncio.Lock for async-safe token refresh, alongside the existing sync OAuthTokenProvider that uses threading.Lock. The async client now uses the async token provider for proper async token management. ## 4.41.3 **`(fix):`** Fix multipart form data requests to omit None values instead of converting them to empty strings. This prevents httpx from sending empty strings for optional parameters that should be absent. --- # November 26, 2025 ## 4.41.2 **`(fix):`** More fixes and improvements to wire tests. ## 4.41.1 **`(fix):`** More fixes and improvements to wire tests. ## 4.41.0 **`(feat):`** `package_path: sub/directory` generates the SDK into the specified subdirectory. Only top-level concerns (`pyproject.toml`, `README.md`, etc.) are exempt. --- # November 25, 2025 ## 4.40.0 **`(feat):`** Add support for X-RateLimit-Reset header Retry strategy matches other SDKs (1s initial delay, 60s max delay). ## 4.39.2 **`(fix):`** More fixes and improvements to wire tests. ## 4.39.1 **`(fix):`** Various fixes and improvements to wire tests. ## 4.39.0 **`(feat):`** Add environment\_class\_name config option to customize the environment class name. Default remains `{ClientName}Environment`. --- # November 24, 2025 ## 4.38.5 **`(fix):`** Fix discriminated union Field(discriminator=...) and UnionMetadata(discriminant=...) to use Python field names instead of JSON aliases for Pydantic v2 compatibility. --- # November 21, 2025 ## 4.38.4 **`(fix):`** Remove using generator-cli to push to GitHub for self-hosted SDKs; this is now handled in the local workspace runner. --- # November 20, 2025 ## 4.38.3-rc1 **`(feat):`** Add wire test generation behind `enable_wire_tests` flag. ## 4.38.3-rc0 **`(feat):`** Add support for custom pagination ## 4.38.2 **`(fix):`** Fix missing websocket services when using lazy imports ## 4.38.1 **`(fix):`** Add contents:read permission to generated publish workflow for OIDC authentication to fix actions/checkout\@v4 requirements. --- # November 19, 2025 ## 4.38.0 **`(feat):`** Add pytest-xdist for parallel test execution and upgrade CI Python version to 3.9 in generated SDKs. ## 4.37.1 **`(chore):`** Bump generator CLI version to publish new Docker image. --- # November 17, 2025 ## 4.37.0 **`(feat):`** Pagination: `page.response` is the typed API response object for each page (e.g., `ListUsersPaginationResponse`), not a raw HTTP wrapper. This is a typing-only improvement; no runtime behavior changes and existing code continues to work. If you explicitly type-annotate pagers, use two type parameters (`SyncPager[T, R]` / `AsyncPager[T, R]`). ```python --- # Iterate pages and access the typed response per page pager = client.users.list(...) for page in pager.iter_pages(): print(page.response) # typed response object ``` --- # November 14, 2025 ## 4.36.2 **`(fix):`** Fix circular reference issue for recursive types and unions. --- # November 12, 2025 ## 4.36.1 **`(fix):`** Resolve PydanticUserError for mutually recursive models in Pydantic v2. --- # November 11, 2025 ## 4.36.0 **`(feat):`** Add custom license file copying and GitHub installation token population for local generation workflows ## 4.35.3 **`(fix):`** Fix double Optional wrapping for unknown types in nullable fields by mapping unknown to Any instead of Optional\[Any]. --- # November 10, 2025 ## 4.35.2 **`(fix):`** Add back F401-ignored imports for circular references. ## 4.35.1 **`(fix):`** Generated Python SDKs no longer show SyntaxWarnings when API docs or enum values include backslashes. ## 4.35.0 **`(feat):`** Add automatic discriminated union support using Pydantic's Field(discriminator=...) to improve serialization performance. Benchmarks show a 2x speedup by eliminating sequential variant attempts and enabling O(1) variant selection. --- # November 7, 2025 ## 4.34.1 **`(fix):`** Fix websocket response type generation to use typing.Any when no server-to-client messages are defined, preventing mypy errors with empty Union types. --- # November 5, 2025 ## 4.34.0 **`(feat):`** Add support for disabling retries on endpoints --- # November 4, 2025 ## 4.33.0 **`(feat):`** Added Generation Metadata file to output --- # October 30, 2025 ## 4.32.3-rc1 **`(feat):`** Added logging to debug 4.32.3-rc0 ## 4.32.3-rc0 **`(feat):`** Add support for publishing to PyPI with attestations in auto-generated GHA ci.yml --- # October 29, 2025 ## 4.32.2 **`(chore):`** Update pyproject.toml headers to propagate project urls to pypi metadata generation --- # October 27, 2025 ## 4.32.1 **`(fix):`** Fix pydantic model alias generator to correctly serialize wrapped aliases in pydantic v2. --- # October 24, 2025 ## 4.32.0 **`(feat):`** Add support for setting the recursion limit above the default of 1000. Also removes unused imports that were previously F401-ignored. --- # October 23, 2025 ## 4.31.2 **`(fix):`** Fix union type deserialization to properly match discriminated unions based on literal field values (e.g., type discriminators) when nested fields have validation errors. --- # October 17, 2025 ## 4.31.1 **`(fix):`** Escape backslashes in docstrings to prevent SyntaxWarning for invalid escape sequences. --- # October 6, 2025 ## 4.31.0 **`(feat):`** - Removed external dependency on httpx-sse by bringing SSE handling in-house. * Fixed SSE handling of events longer than or containing escaped newlines. --- # October 2, 2025 ## 4.30.4-rc1 **`(fix):`** Cleared CVE-2025-27210 ## 4.30.4-rc0 **`(fix):`** Cleared CVEs in generator image --- # September 29, 2025 ## 4.30.3 **`(fix):`** Upgrade generator-cli dependency to fix local generation handling of .fernignore files. --- # September 27, 2025 ## 4.30.2 **`(fix):`** Fix enum generation to properly escape quotes and backslashes in enum values. --- # September 25, 2025 ## 4.30.1 **`(fix):`** Fix sdk `v1_on_v2` export of non-existent `IS_PYDANTIC_V2` variable. ## 4.30.0 **`(feat):`** Add support for PR mode for self-hosted/local sdk generation --- # September 23, 2025 ## 4.29.2 **`(chore):`** Added a note to the README on constructing Async httpx objects to pass into main Async clients. --- # September 22, 2025 ## 4.29.2-rc0 **`(fix):`** Exports in init files always reference the submodule instead of the current module. This should fix infinite recursion in libraries that inspect getattr, like freezegun. --- # September 18, 2025 ## 4.29.1 **`(fix):`** Fixes issue where colliding classes were not lazily imported correctly. ## 4.29.0 **`(feat):`** Add support for custom sections in the README.md via customSections config option --- # September 16, 2025 ## 4.28.5 **`(fix):`** Generator no longer fails on failed generator-cli installation --- # September 12, 2025 ## 4.28.4 **`(fix):`** Fix python sdk serialization to use dict instead of model\_dump. --- # September 10, 2025 ## 4.28.3 **`(fix):`** Never duplicate parameters in client constructors --- # September 9, 2025 ## 4.28.2 **`(fix):`** Nit in custom client snippet generation. --- # September 5, 2025 ## 4.28.1 **`(fix):`** Union member self-referencing dependencies are now correctly imported and forward referenced. This fixes compatibility with Pydantic >=2.11.0. --- # August 29, 2025 ## 4.28.0 **`(feat):`** Generator passes readme configs apiName, disabledSections, and whiteLabel. --- # August 27, 2025 ## 4.27.0-rc0 **`(feat):`** Client imports are now lazy loaded by default. This will greatly reduce memory footprint when using a small portion of a large API. The tradeoff is a latency penalty when first accessing a client. Users can opt in to eager loading (the old behavior) by setting the `lazy_imports` flag to `false` in their configuration. --- # August 26, 2025 ## 4.26.2 **`(fix):`** Upgrade docker image to use python 3.11.13 so that users can depend on packages that require python 3.11. --- # August 20, 2025 ## 4.26.1 **`(chore):`** Additional handling of inferred auth ## 4.26.0 **`(chore):`** Bumped IR version to 59. --- # August 5, 2025 ## 4.25.9 **`(feat):`** Fix: allow setting of package name and version in local docker generation ## 4.25.7-rc2 **`(feat):`** Minor bug fix: accessing version from publish config ## 4.25.7-rc1 **`(feat):`** Attempt to plumb version in Abstract Generator ## 4.25.8 **`(feat):`** Websocket patch: json load messages on dunder iter method --- # August 4, 2025 ## 4.25.7-rc0 **`(feat):`** Enforce nested folders for package names with a "." in them. --- # July 22, 2025 ## 4.25.6 **`(feat):`** Removed snippet generation --- # July 17, 2025 ## 4.25.5 **`(feat):`** Enabled "ignore" as an option for extra fields --- # July 15, 2025 ## 4.25.4 **`(fix):`** Updated construct\_type function to handles undiscriminated unions with lists, sets, and dictionaries of objects. --- # July 14, 2025 ## 4.25.3 **`(fix):`** Fix websocket connect method generation for single base URL environments. --- # July 11, 2025 ## 4.25.2 **`(fix):`** Generator fix: automatically switch tabs to spaces, following PEP8 standards. --- # July 10, 2025 ## 4.25.1 **`(fix):`** Correctly import websockets exceptions. --- # July 9, 2025 ## 4.25.0 **`(feat):`** Support async functions as websocket callback handlers. ## 4.24.3 **`(fix):`** Support websockets>=14 by using legacy client. ## 4.24.2 **`(fix):`** Emit ERROR events for JSON parsing errors in websocket connections. --- # July 7, 2025 ## 4.24.1 **`(fix):`** Parse websocket messages as JSON before Pydantic parsing. --- # July 3, 2025 ## 4.24.0 **`(feat):`** Add support for path parameters backed by variables supplied to the client constructor. --- # June 25, 2025 ## 4.23.2 **`(chore):`** Bump websockets dependency to >=12.0.0 to ensure compatibility with newer websocket implementations and improve stability. --- # June 24, 2025 ## 4.23.1 **`(chore):`** Bump pydantic-core dependency to >=2.18.2 to ensure compatibility with newer pydantic versions and improve performance. ## 4.23.0 **`(feat):`** Add support for custom headers parameter at the top level of the client constructor. ```python client = Client( headers={"X-Custom-Header": "custom-value"} ) ``` --- # June 20, 2025 ## 4.22.1-rc0 **`(feat):`** Lazily validate model serialization to reduce memory consumption. Pydantic 2.11.0 introduced an issue where the model\_serializer decorator set to wrap mode forced it to eagerly do schema validation at import time. Because we had this decorator on the UniversalBaseModel, it would try to validate the schemas of all the Model types at import time. This caused massive memory spikes for more complex SDKs, up to 2.6GB in some cases. This change essentially accomplishes the same logic of wrapping the serialization process and modifying the serialization structure of datetime fields. The difference is that we manually wrap, so we're able to defer model validation until runtime, drastically reducing our memory consumption. --- # June 11, 2025 ## 4.22.0 **`(feat):`** Support wrapped aliases in python for pydantic v2. ## 4.21.5 **`(fix):`** Generate README for github output mode. --- # June 5, 2025 ## 4.21.4 **`(feat):`** Add support for HEAD HTTP method in the generated client. --- # June 4, 2025 ## 4.21.3 **`(fix):`** Fix an issue where the websocket connect method did not correctly yield the websocket client. --- # May 27, 2025 ## 4.21.2 **`(chore):`** Handle HEAD HTTP method gracefully by treating it as a POST method when constructing the snippet registry, rather than failing. ## 4.21.1 **`(chore):`** Make sure to generate README and Reference even when generating in local mode (if self hosting is enabled). ## 4.21.0 **`(chore):`** Bump to v58 of IR. --- # May 20, 2025 ## 4.20.3 **`(fix):`** Fix handling of optional and unknown response types by not throwing errors when the response is empty. --- # May 13, 2025 ## 4.20.2 **`(fix):`** Support formatting the generated README.md and python code snippets. ## 4.20.1 **`(fix):`** Add support for the custom introduction setting in the generated README.md. ## 4.20.0 **`(feat):`** Generate standalone Pydantic models for each class definition for models that utilize the Fern `extends` keyword, as opposed to generating Pydantic models that implement inheritance. ## 4.19.7 **`(fix):`** Fix mypy errors related to type-shadowing `data` variables in generated streaming endpoints. --- # May 11, 2025 ## 4.19.6 **`(fix):`** Fix mypy errors related to automatic pagination in the python client. ## 4.19.5 **`(fix):`** Fix naming conflicts in streaming endpoints by renaming the stream method to \_stream in raw clients, preventing collisions with endpoint parameters that might also be named "stream", while maintaining proper functionality for streaming responses. ## 4.19.4 **`(feat):`** Fix handling of optional file parameters in multipart form data requests with httpx by properly checking for None values before attempting to include them in the request, preventing errors when optional file parameters are not provided. --- # May 9, 2025 ## 4.19.3 **`(fix):`** Fix pagination support in raw clients by properly indexing into response data, ensuring that raw client endpoints with pagination correctly iterate through paginated results. ## 4.19.2 **`(fix):`** Fix SSE streaming response handling by adding proper type casting to sse.data, ensuring correct data type conversion during stream processing. ## 4.19.1 **`(fix):`** Fix a mypy error in pydantic\_utilities.py by properly handling type annotations for Pydantic v1 and v2 compatibility, ensuring type checking passes correctly across different Pydantic versions. ## 4.19.0 **`(feat):`** Add support for generating proper Pydantic models that contain forward references wrapped in containers (e.g. list, optional, etc.) --- # May 8, 2025 ## 4.18.6 **`(fix):`** Fix string enum generation to properly handle enum values containing quotes by automatically escaping them, ensuring valid Python syntax for both single and double quoted string literals. ## 4.18.5 **`(fix):`** Support application/x-www-form-urlencoded content type for requests, allowing proper encoding of form data in API calls. ## 4.18.4 **`(fix):`** Fix requirements.txt generation to properly handle dependency version constraints, ensuring compatibility markers are correctly formatted. --- # May 6, 2025 ## 4.18.2 **`(fix):`** Fix README g ## 4.18.1 **`(fix):`** Update python-v2 generator invocation so that all relevant files like pyproject.toml and poetry.lock are pushed to the GitHub repository. ## 4.18.0 **`(fix):`** Add support for self-hosted mode, allowing users to push generated SDKs to their own GitHub repositories. This feature enables organizations to maintain private SDK repositories with custom configurations. --- # May 5, 2025 ## 4.17.1 **`(fix):`** Fix an issue where response `headers` were not available in the strongly typed error classes. --- # May 1, 2025 ## 4.18.3 **`(fix):`** Install the generator-cli at build time as a fallback if runtime installation fails. --- # April 30, 2025 ## 4.17.0 **`(feat):`** Add support for retrieving response headers for each page of paginated responses, instead of just the first page. --- # April 29, 2025 ## 4.16.2 **`(fix):`** Fixed an issue introduced in 4.14.0, where `bytes` and `text` responses were not handled correctly. --- # April 25, 2025 ## 4.16.1 **`(internal):`** Fixes an internal release issue in `4.16.0`. ## 4.16.0 **`(feat):`** Add support for retrieving response headers from the generated `ApiError` class. --- # April 24, 2025 ## 4.15.0 **`(feat):`** Add support for offset step pagination, where the offset position represents the element's index rather than the page number. **`(fix):`** Fixed an issue introduced in 4.14.0, where paginated endpoints were not returning the underlying data. ## 4.14.6 **`(fix):`** Fixed an issue where multipart/form-data content types are now explicitly sent when configured in the API definition. --- # April 23, 2025 ## 4.14.5 **`(fix):`** Fixed an issue introduced in 4.14.0, where SSE streaming responses were not yielded correctly. --- # April 22, 2025 ## 4.14.4 **`(fix):`** Fixed an issue where filename and plain text content-type parameters were being incorrectly serialized. ## 4.14.3 **`(fix):`** Add support for receiving raw responses from pagination endpoints. --- # April 13, 2025 ## 4.14.2 **`(fix):`** Fix an issue where TypedDicts with circular references were not correctly serialized. This issue only affected users that enabled `use_typeddict_requests`. --- # April 10, 2025 ## 4.14.1 **`(fix):`** The generated GitHub workflow now uses `ubuntu-latest` instead of `ubuntu-20.04` ## 4.14.0 **`(feat):`** Add support for receiving raw responses from streaming endpoints. **`(feat):`** Add support for excluding types from the generated `__init__.py` files. ```yaml config: exclude_types_from_init_exports: true ``` --- # April 9, 2025 ## 4.13.0 **`(feat):`** Adds support for overriding literal global headers in the client constructor (e.g. `version`). ```python client = Acme( ... version="1.0.0", ) ``` ## 4.12.1 **`(fix):`** Fixes an issue where dictionary types defined within TypedDicts incorrectly used the `typing_extensions.NotRequired` type. **`(fix):`** Fixes an issue where optional `core.File` parameters would cause `mypy` failures. **`(fix):`** Fixes a regression introduced in 4.12.0, where the non raw response client endpoints did not respect the allowed method keywords (e.g. `list` was generated as `list_`). ## 4.12.0 **`(fix):`** Resolve issues with paginated endpoints generating incorrect endpoint return types. --- # April 8, 2025 ## 4.11.0 **`(fix):`** Always represent nullable as Optional rather than NotRequired, only use NotRequired for optional in typeddicts. --- # April 7, 2025 ## 4.10.0 **`(feat):`** Add support for using TypedDicts for file upload request parameters. This flag should be used in conjunction with the `use_typeddict_requests` flag like so: ```yaml config: use_typeddict_requests: true use_typeddict_requests_for_file_upload: true ``` ## 4.9.0 **`(feat):`** Implement raw client support for accessing response headers and data in unary endpoints. ## 4.8.0 **`(feat):`** Add support for inlining path parameters --- # April 3, 2025 ## 4.7.0 **`(feat):`** Add support for user-agent header --- # April 1, 2025 ## 4.6.0 **`(feat):`** Add support for generating legacy wire tests, and disable them by default. These tests will be restored and improved in the future. Users can opt-in to generating legacy wire tests by setting the `include_legacy_wire_tests` flag to `true` in their configuration. ```yaml config: include_legacy_wire_tests: true ``` --- # March 28, 2025 ## 4.5.0 **`(feat):`** Add support for websocket code generation. --- # March 25, 2025 ## 4.4.0 **`(feat):`** Add support for raw bytes responses. --- # March 24, 2025 ## 4.3.21 **`(fix):`** Fix an issue where the default `timeout` was not being respected when a custom `httpx_client` was provided. --- # March 19, 2025 ## 4.3.20 **`(fix):`** Update formatting across all generated files. There are no behavioral changes, but large diffs are expected. --- # March 18, 2025 ## 4.3.19 **`(internal):`** Update the IR to v57. --- # March 14, 2025 ## 4.3.18 **`(fix):`** Fix an issue where the `request_options` parameter name is now properly respected when it's renamed due to conflicts with other parameter names. Previously, the code would still reference the original parameter name internally, causing errors. --- # March 13, 2025 ## 4.3.17 **`(fix):`** Fix an issue where parameter names that conflict with the `request_options` parameter are now properly deconflicted by prepending an underscore to the `request_options` parameter name. --- # March 6, 2025 ## 4.3.16 **`(fix):`** Fix an issue where GeneratorExit was unintentionally being swallowed by code blocks within the HttpClient.stream() contextmanager. --- # March 5, 2025 ## 4.3.15 **`(fix):`** Fix an issue where extraneous NameError-causing update\_forward\_refs invocations were being emitted. --- # February 20, 2025 ## 4.3.14 **`(feat):`** Set the default number of retries to 2 (was 0) to align with the generated README. --- # February 12, 2025 ## 4.3.13 **`(feat):`** The Python generator now supports conditioning dependencies on the Python version. --- # February 10, 2025 ## 4.3.12 **`(feat):`** The Python generator now autogenerates a requirements.txt file. --- # January 6, 2025 ## 4.3.11 **`(fix):`** pyproject.toml now has a `[project]` block making it Poetry v2 compatible. --- # December 20, 2024 ## 4.3.10 **`(fix):`** Pagination correctly uses specified defaults to support custom schemes. --- # December 8, 2024 ## 4.3.9 **`(fix):`** Fix indentation in generated README.md sections to ensure proper formatting and readability. --- # November 20, 2024 ## 4.3.8 **`(fix):`** Include content-type headers when available as part of endpoint request generation. --- # November 19, 2024 ## 4.3.7 **`(fix):`** Update multipart endpoint generation to propertly omit optional body parameters. --- # November 15, 2024 ## 4.3.6 **`(fix):`** Fix README.md and reference.md generation. --- # November 14, 2024 ## 4.3.5 **`(fix):`** Update README.md snippet builder to omit invalid snippets during readme config generation. --- # November 13, 2024 ## 4.3.4 **`(fix):`** Update shared http\_client.py to remove omitted entries during file upload requests. --- # October 21, 2024 ## 4.3.3 **`(fix):`** The generator now writes the reference.md configuration correctly, using `.dict()` instead of `.json()`. ## 4.3.2 **`(fix):`** The generator will now correctly default to the configured global `default_bytes_stream_chunk_size` when the `request_options` parameter is not provided. ## 4.3.1 **`(feat):`** Requests for file download will now allow users to pass in a `chunk_size` option that allows them to receive chunks of a specific size from the resultant `iter_bytes` invocation on the response byte stream. Concretely, a user would leverage the following: ```python client.download( ..., request_options={ "chunk_size": 1024 # 1MB } ) ``` --- # October 11, 2024 ## 4.2.8 **`(fix):`** The snippet writer now correctly handles base64 strings. --- # September 28, 2024 ## 4.2.7 **`(fix):`** The generated README will now have a section that links to the generated SDK Reference (in `reference.md`). ```md ## Reference A full reference for this library can be found [here](./reference.md). ``` --- # September 26, 2024 ## 4.2.7-rc4 **`(fix):`** Generated readmes now include the parameter name required for the request options parameter within the example snippets. ## 4.2.7-rc3 **`(fix):`** Now, when sending Snippet Templates back to Fern, the generator will not try to coerce a potentially missing ID into the `api_definition_id` field. This, had been a cause of the error log `Failed to upload snippet templates to FDR, this is ok: one of the hex, bytes, bytes_le, fields, or int arguments must be given`. ## 4.2.7-rc2 **`(fix):`** Pydantic utilities now correctly handles cases where you have a Pydantic model, with a list of pydantic models as a field, where those models have literals. Effectively, `deep_union_pydantic_objects` now handles lists of objects and merges them appropriately. --- # September 23, 2024 ## 4.2.7-rc1 **`(fix):`** When leveraging the `include_union_utils` configuration flag, the Pydantic models will no longer include transitive dependencies within `update_forward_ref` calls, since these should not be necessary. This effectively scopes back the changes introduced in 4.0.0-rc5, which included changes to improve circular reference handling in Pydantic models. ## 4.2.7-rc0 **`(fix):`** Dynamic header suppliers, as used within the OAuth provider are now invoked on every request, not just the first. This was a regression introduced within an earlier version that is now fixed. As a results of this fix, the `refresh_token` is now correctly refreshed. --- # September 20, 2024 ## 4.2.6 **`(fix):`** Serialization utilities (necessary when pydantic aliases are removed) now respects dictionaries as well. ## 4.2.5 **`(fix):`** Parameters of file upload functions now default to OMIT, not None, so that the SDK appropriately filters out unset parameters, while still allowing for user specified None values. --- # September 17, 2024 ## 4.2.4 **`(fix):`** Datetime examples are generated correctly once again. The `pydantic_utilities` file is python 3.8 compatible. --- # September 16, 2024 ## 4.2.3 **`(fix):`** The content type of file properties is now respected for multipart requests. For example, if you have a file property called `image` that has the content type `image/jpeg`, then it will be sent as: ```python "image": core.with_content_type(file=image, content_type="image/jpeg"), ``` ## 4.2.2 **`(fix):`** The content type of non-file properties is now respected for multipart requests. For example, if you have a type called `metadata` that has the content type `application/json`, then it will be sent as: ```python "metadata": (None, json.dumps(jsonable_encoder(metadata)), "application/json"), ``` --- # September 15, 2024 ## 4.2.1 **`(fix):`** When the generator runs bash commands such as `poetry install` and there is a failure, now the `stderr` and `stdout` is logged to help improve user debugging. --- # September 13, 2024 ## 4.2.0 **`(feat):`** Allow specifying arbitrary configuration to your packages `pyproject.toml` by adding a `pyproject_toml` block to your configuration whatever you include in this block will be added as-is to the `pyproject.toml` file. The config, as an example is: ```yaml config: pyproject_toml: | [tool.covcheck.group.unit.coverage] branch = 26.0 line = 62.0 [tool.covcheck.group.service.coverage] branch = 30.0 line = 67.0 ``` ## 4.1.0 **`(feat):`** Allow specifying pip extras within your `pyproject.toml`. The following config: ```yaml config: extra_dev_dependencies: covcheck: version: "^0.4.3" extras: ["toml"] ``` would add the following to your `pyproject.toml`: ```toml [tool.poetry.dev-dependencies] covcheck = { version = "^0.4.3", extras = ["toml"] } ``` ## 4.0.0 **`(fix):`** Generated tests that expect an empty result when they are of type `text` (not JSON) now appropriately expect an empty string instead of `None` for async functions as well. Version 3.3.4 fixed this for sync functions only, which was a bug. --- # September 12, 2024 ## 4.0.0-rc9 **`(fix):`** All Pydantic V2 warnings have been resolved ### What's been fixed * json\_encoders have been removed from Pydantic V2, and replaced with a `model_serializer` method. * additional model construction functions have been added when not leveraging pydantic field aliases to allow users to construct a model from JSOn without the need for dealiasing the object themselves. --- # September 11, 2024 ## 4.0.0-rc8 **`(fix):`** Pydantic models that call `update_forward_refs` on non-union circular reference dependencies now pass in `localns` for the current member, a field in Pydantic V1 that provides object contexts to models in the event objects are not fully rebuilt. ## 4.0.0-rc7 **`(fix):`** The generator now respects the old use\_str\_enums flag again, a regression was introduced where only the new flag `enum_type` was respected. ## 4.0.0-rc6 **`(fix):`** Pydantic models now call update forward refs on non-union circular references. This prevents runtime errors in certain cases where types self reference itself through a union. --- # September 10, 2024 ## 4.0.0-rc5 **`(fix):`** Pydantic models now call update forward refs on non-union circular references. This prevents runtime errors in certain cases where types self reference itself through a union. ## 4.0.0-rc4 **`(fix):`** Pydantic models now call update forward refs on non-union circular references. This prevents runtime errors in certain cases where types self reference itself through a union. ## 4.0.0-rc3 **`(fix):`** Pydantic models now call update forward refs on non-union circular references. This prevents runtime errors in certain cases where types self reference itself through a union. --- # September 6, 2024 ## 4.0.0-rc2 **`(fix):`** Update .dict calls in Pydantic V2 to be back to pre-3.10.4 logic for SDKs that continue using Pydantic aliases. ## 4.0.0-rc1 **`(fix):`** Update .dict calls in Pydantic V2 to be back to pre-3.10.4 logic. ### What's been fixed * Pydantic V2 `.dict` calls are updated to be back to pre-3.10.4 logic. This is fix a regression where nested literals were being omitted due to the Pydantic V2 serializers not respecting the recursive .dict logic, as Pydantic V2 shells out `model_dump` calls to Rust library and serializers, as opposed to recursively calling `model_dump`. It is expected that performance will not be degraded given the Rust-based serializers have optimized performance, compared to the Pydantic V1 .dict approach. --- # September 5, 2024 ## 4.0.0-rc0 **`(fix):`** Rerelease 3.11.0-rc0 as a major version, with a configuration flag to disable the behavior (`use_pydantic_field_aliases`), defaulted to `true` to preserve existing behavior. **`(internal):`** The generator now shares "as is" files with Pydantic and FastAPI generators. ### What's been fixed * Rerelease 3.11.0-rc0 as a major version, with a configuration flag to disable the behavior (`use_pydantic_field_aliases`), defaulted to `false` to introduce the break on a major version. To maintain parity with pre-3.11.0 behavior, update the flag to `true`: ```yaml - name: fernapi/fern-python-sdk version: 4.0.0-rc0 config: pydantic_config: use_pydantic_field_aliases: true ``` --- # September 4, 2024 ## 3.11.0-rc0 **`(chore):`** Remove Pydantic field aliases and leverage an internal representation. ### What's been fixed * Pydantic field aliases are removed and replaced with an internal representation. This allows for more robust handling of field aliases and prevents issues with Pydantic V2 and mypy. Previously, you'd have for V1 and V2 compatibility in Pydantic, you'd want to conditionally apply the config class within the base model, however this would lead to mypy errors when filling out a model with it's field alias. To solve this, We used the deprecated `class Config`, regardless of the Pydantic version to satisfy mypy, which lead to warnings in the console. Now, we've removed the field aliases and replaced them with an internal representation, which allows us to avoid pydantic config altogether. --- # September 2, 2024 ## 3.10.8 **`(fix):`** Allow for fields prefixed with the name `model`, a silent break introduced in Pydantic V2. --- # August 28, 2024 ## 3.10.7 **`(fix):`** When not leveraging mock integration tests, still run pytest over everything, not a specific directory. --- # August 16, 2024 ## 3.10.6 **`(fix):`** Pagination utilities assume `""` is a terminal signal for pagination. ### What's been fixed * Cursor-based pagination also assumes `""` is a terminal signal for pagination, same as if the next cursor were `None`. ## 3.10.3 **`(fix):`** Upgrade intermediate representation dependency to safely parse null unknown types. --- # August 14, 2024 ## 3.10.4 **`(chore):`** Improve performance of Pydantic `.dict` calls ### What's changed * `.dict` performance is improved, consolidating to a single call to Pydantic's `.dict` instead of 2 in attempts to remove unset optional values. ## 3.10.3 **`(fix):`** Query encoding now appropriately takes arrays of deep objects into account. --- # August 13, 2024 ## 3.10.2 **`(fix):`** Unions with utils now update forward refs again, a regression that was introduced in version 3.7.0 ## 3.10.1 **`(fix):`** If there are no autogenerated examples present, the Python SDK generator no longer fails. --- # August 9, 2024 ## 3.10.0 **`(feat):`** Introduce forward compatible Python enums ### What's new * Adds a new flag to generate forward compatible Python enums, as opposed to leveraging raw string enums as literals. This works through addding an "\_UNKNOWN" member to your enum set, the value of which is the raw value of the unrecognized enum. ## 3.9.0 **`(feat):`** Introduce Pythonic naming for discriminated union members through `union_naming` configuration flag. ### What's new * A new configuration is introduced to make discriminated union member naming more Pythonic. With V1 union naming, member names change from `_` to ``. Concretely, union members previously named `Chat_User` will now be named `UserChat` under the new configuration. ## 3.8.0 **`(chore):`** Generated SDKs now use ruff for linting and formatting instead of Black. --- # August 8, 2024 ## 3.7.0 **`(chore):`** Python circular referencing types are more robust. ## 3.6.0 **`(feat):`** The generator now respects returning nested properties from the returned object --- # August 5, 2024 ## 3.5.1 **`(fix):`** Auto-completion for unions leveraging union utils now works as expected. ### What's been fixed * The root type for unions with visitors now has it's parent typed correctly. This allows auto-complete to work once again on the union when it's nested within other pydantic models. ## 3.5.0 **`(chore):`** Generated code now respects the pydantic version configuration flag. ### What's changed * Improvement: The generated SDK now respects the pydantic version flag, generating V1 only code and V2 only code if specified. If not, the SDK is generated as it is today, with compatibility for BOTH Pydantic versions. This cleans up the generated code, and brings back features liked wrapped aliases for V1-only SDKs. ## 3.4.2 **`(fix):`** The Python generator now instantiates `Any` types as `Optional[Any]` to be able to mitigate breaks in Pydantic V2. --- # August 4, 2024 ## 3.4.1 **`(chore):`** Literal templates are generated if they are union members --- # August 2, 2024 ## 3.4.0 **`(internal):`** Generator code now uses Pydantic V2, no changes to generated code. ### What's changed * Internal: The SDK generator has now been upgraded to use Pydantic V2 internally. Note that there is no change to the generated code, however by leveraging Pydantic V2 you should notice an improvement in `fern generate` times. ## 3.3.4 **`(chore):`** Address a number of issues within generated unit tests. ### What's been fixed * Generated tests that expect an empty result when they are of type `text` (not JSON) now appropriately expect an empty string instead of `None`. ### What's changed * Improvement: Aliased literals are also defaulted within Pydantic models, whereas previously only direct literals were defaulted. * Improvement: Snippets now provide optional literals in functions and models. ## 3.3.3 **`(fix):`** The generator now allows you to extend aliased types (as long as they're objects). ## 3.3.2 **`(fix):`** Regression in readme generation introduced in 3.3.1 ## 3.3.1 **`(fix):`** Generated READMEs now reference RequestOptions as TypedDicts correctly. --- # August 1, 2024 ## 3.3.0-rc1 **`(fix):`** TypedDict snippets now include literals where available. --- # July 31, 2024 ## 3.3.0-rc0 **`(internal):`** Upgrade to IR 53.1.0 ### What's changed * Upgrade to IR 53.1.0 * The Python generator now creates snippet templates for undiscriminated unions. --- # July 29, 2024 ## 3.2.0-rc1 **`(fix):`** The generated README now imports `ApiError` as if it were from outside the module. --- # July 25, 2024 ## 3.2.0-rc0 **`(feat):`** The Python SDK can now be generated with TypedDicts as inputs. ### What's new * The Python SDK can now be generated such that inputs to requests are TypedDicts, instead of Pydantic models. This allows for consumers of the SDK to continue to have type hinting and autocomplete, but not need to import new object types when creating requests. --- # July 24, 2024 ## 3.1.0-rc0 **`(chore):`** The root client is now exported from the main `__init__.py`. ### What's changed * Improvement: The root client users interact with is now exported from the main `__init__.py`, this allows users to access the client via `from my_sdk import my_sdk_client` as opposed to `from my_sdk.client import my_sdk_client`. ### What's been removed * Note this comes with an edge-case break. In the unlikely event you have a type that conflicts in naming with the exported root client, that type model is post-fixed with "Model". e.g. a type `Merge` in an SDK exporting a client `Merge` becomes `MergeModel`. ## 3.0.0-rc2 **`(fix):`** `update_forward_refs` no longer raises errors, preserving original behavior, pre-3.x. --- # July 23, 2024 ## 3.0.0-rc1 **`(fix):`** `expected_types` within our test suite are now typed as `Tuple[typing.Any, typing.Any]`. ### What's been fixed * Sometimes mypy will error on the typing of `expected_types` within our test suite, despite them being labeled as `typing.Any`. This updates the types for tuples to `typing.Tuple[tying.Any, typing.Any]` to appease mypy. ## 3.0.0-rc0 **`(break):`** The generated models now support Pydantic V2 outright, it no longer uses `pydantic.v1` models. ### What's changed * The generated models now support Pydantic V2 outright, it no longer uses `pydantic.v1` models. * Public fields previously prefixed with `_` are now prefixed with `f_` (Pydantic V2 does not allow for `_` prefixes on public fields and Python does not allow for a numeric prefix) ### What's been removed * wrapped aliases outside of Pydantic V1 * custom root validators outside of Pydantic V1 --- # July 17, 2024 ## 2.15.6 **`(fix):`** The generated python SDK now requires an environment be specified if a default is not provided. ## 2.15.5 **`(fix):`** The generated python SDK Oauth client now no longer checks for an expiry when getting the access token if an expiry field is not configured. --- # July 16, 2024 ## 2.16.0 **`(feat):`** The generated SDK now allows for specifying whether or not to generate `streaming` functions as overloaded functions or separate functions. --- # July 10, 2024 ## 2.15.4 **`(fix):`** The generated python SDK now serializes bytes within JSON as a utf-8 encoded string. ## 2.15.3 **`(fix):`** The generated python SDK no longer runs into a recursion error during snippet generation. ## 2.15.2 **`(fix):`** The generated python SDK no longer treats `set` as a reserved word for method names. --- # July 9, 2024 ## 2.15.1 **`(fix):`** The unchecked base model no longer coerces None to a type. ### What's been fixed * The unchecked base model no longer coerces None to a type. * The http client appropriately defaults empty fields within RequestOptions. --- # July 3, 2024 ## 2.15.0 **`(feat):`** The generated python SDK now respects configured defaults from the API spec. --- # July 1, 2024 ## 2.14.1 **`(fix):`** typing within the Sync and AsyncPagers is now correctly passed through to the BasePager. ### What's been fixed * Sync and AsyncPage now pass through the generic type to BasePage, allowing the use of `.items`, etc. to be appropriately typed within your type checking system. ## 2.14.0 **`(fix):`** The offset page now allows for the usage of 0 as a page start. ### What's been fixed * offset page now allows for the usage of 0 as a page start, previously the use of `page or 1` made Python coerce booleans and become 1, ignoring the user-provided 0. ## 2.14.0-rc3 **`(feat):`** Generated readmes now include an "advanced" section. ### What's changed * Generated readmes now include an "advanced" section, outlining usage of retries, timeouts, error handling and usage of a custom client. ## 2.14.0-rc2 **`(chore):`** Async snippets now run the async function leveraging asyncio.run to be more copy-pastable. --- # June 27, 2024 ## 2.14.0-rc1 **`(fix):`** The fix from 2.5.2 is now case-insensitive ### What's been fixed * the fix from 2.5.2 is now case-insensitive Recap of 2.5.2: `Fix: Support `list`SDK method names instead of defaulting to`list\_`.` --- # June 26, 2024 ## 2.14.0-rc0 **`(feat):`** The Python SDK now generates an accompanying SDK reference (`reference.md`) for users to review the SDK methods at a glance within the SDK's GitHub repository. --- # June 25, 2024 ## 2.12.0-rc0 **`(feat):`** README generation now supports a section dedicated to streaming usage, as well as one for paginated endpoints. ### What's new * Feature: README generation now supports a section dedicated to streaming usage, as well as one for paginated endpoints. ### What's changed * Improvement: Paginated endpoint snippets now show using an iterator: ## 2.11.0-rc0 **`(chore):`** Snippet templates now support auth variables within the root client. ### What's changed * Improvement: The SDK now produces templates for the root clients within snippet-template.json. This allows users of the Templates API to pass in data for the auth variables present within the root client. --- # June 20, 2024 ## 2.13.1-rc0 **`(fix):`** The Python SDK now does not send additional properties via JSON or data if the request is leveraging the other field. ### What's been fixed * the Python SDK now does not send additional properties via JSON or data if the request is leveraging the other field. ### What's changed * Improvement: the Python SDK now copies unit tests over to the generated SDK for additional unit testing (separate from wire-format testing). ## 2.13.0-rc0 **`(internal):`** The Python SDK generator is now upgraded to IR V49. ## 2.10.2 **`(fix):`** The SDK now handles stream termination sequences like `[DONE]`. ### What's been fixed * The SDK now handles stream termination sequences like `[DONE]`. This is a typical way for LLM providers to communicate when the stream has ended. ## 2.10.1 **`(fix):`** Improve the SDK to not leak `JSONDecodeError` to SDK users. Instead, an `ApiError` will be thrown with the text content of the response. ## 2.10.0 **`(feat):`** Add support for higher quality `README.md` generation. ## 2.9.10 **`(fix):`** The generator now only specifies the readme location within pyproject.toml if one was successfully created. --- # June 19, 2024 ## 2.9.9 **`(internal):`** The generator now consumes IRv46. --- # June 18, 2024 ## 2.9.8 **`(chore):`** The python generator only adds a publish step in github actions if credentials are specified. --- # June 12, 2024 ## 2.9.7 **`(fix):`** The unchecked base model stops special casing defaults and pydantic v2. --- # June 11, 2024 ## 2.9.6 **`(fix):`** Offset based pagination is now 1-based, as opposed to 0 based ### What's been fixed * Offset based pagination is now 1-based, as opposed to 0 based * The HTTP client now passes in additional body properties from the request options, even if the body is empty (regression from the client migration in 2.8.0) --- # June 10, 2024 ## 2.9.5 **`(fix):`** Unions with elements that specify no properties are generated correctly. ### What's been fixed * Unions with elements that specify no properties are generated correctly. * Unions with a single type now have a valid type alias (rather than an invalid `typing.Union`). --- # June 7, 2024 ## 2.9.4 **`(fix):`** The unchecked base model now handles pulling the discriminant from a dict, not just a model/object. --- # June 6, 2024 ## 2.9.3 **`(fix):`** Snippet templates for discriminated unions now specify the `template_input` property which is required to actually see snippets of instantiating discriminated unions. ## 2.9.2 **`(fix):`** downgrades mypy so we can run it over all our files without concern for their pydantic bug ### What's been fixed * downgrades mypy so we can run it over all our files without concern for their pydantic bug * adds typehint to the response variable ## 2.9.1 **`(fix):`** The SDK removes unset query parameters from requests (regression from the client migration in 2.8.0) ### What's been fixed * The SDK removes unset query parameters from requests (regression from the client migration in 2.8.0) * The SDK fixes it's type for `files` parameters to the http client (regression from the client migration in 2.8.0) --- # June 5, 2024 ## 2.9.0 **`(fix):`** Snippets preserve trailing slashes ## 2.9.0-rc1 **`(fix):`** The new http client abstraction ensures a slash is postfixed to the baseurl --- # June 4, 2024 ## 2.9.0-rc0 **`(chore):`** The Python generator now runs custom unit tests in CI if configured. ## 2.8.2 **`(fix):`** The none-filtering function now supports mypy's invariance check. ## 2.8.1 **`(fix):`** The parameter comment/documentation for timeouts on the root client now reflects the custom timeout passed through within configuration. --- # June 3, 2024 ## 2.8.0 **`(chore):`** Endpoint function request logic has been abstracted into the request function of the wrapped httpx client. --- # May 31, 2024 ## 2.6.1 **`(internal):`** this adds a back door token getter function to OAuth clients to better test the functionality. --- # May 30, 2024 ## 2.7.0 **`(internal):`** Improvement: The generator now outputs an `exampleId` alongside each generated snippet so that we can correlate snippets with the relevant examples. This is useful for retrieving examples from Fern's API and making sure that you can show multiple snippets in the generated docs. ## 2.6.0 **`(chore):`** Support adding optional dependencies and extras to your generated `pyproject.toml`. ### What's changed * Improvement: Support adding optional dependencies and extras to your generated `pyproject.toml`. To use this configuration, please add the following: ## 2.5.7 **`(fix):`** tests now carry a type annotation for `expected_types` variable. --- # May 29, 2024 ## 2.5.6 **`(chore):`** Literal values are now all defaulted such that users are not required to plug in a redundant value. ## 2.5.5 **`(fix):`** Auto-Pagination now respects optional return values ### What's been fixed * Optional lists returned from pagination endpoints are now appropriately flattened such that the `Pager` return types are correctly `Pager[ListItem]` as opposed to `Pager[List[ListItem]]`. --- # May 28, 2024 ## 2.5.4 **`(internal):`** Add typing library for dateutils in testing lib to satisfy mypy errors. --- # May 24, 2024 ## 2.5.3 **`(chore):`** Stops specifying custom licenses manually, lets poetry handle adding them. --- # May 23, 2024 ## 2.5.2 **`(feat):`** Support `list` SDK method names instead of defaulting to `list_`. ## 2.5.1-rc0 **`(fix):`** Literal parameters are added back to the request body. ## 2.5.0-rc2 **`(fix):`** Do not attempt to run `fern test` in CI until the command is more widely rolled out. --- # May 22, 2024 ## 2.5.0-rc1 **`(chore):`** Address `propogate` -> `propagate` typo in python codegen. ## 2.5.0-rc0 **`(fix):`** This version addresses issues in unit test generation and reenables the creation of unit tests. --- # May 21, 2024 ## 2.4.0-rc0 **`(fix):`** The Python SDK generator now uses safe names wherever string concat is not used (like in client generation naming), so this will update module and parameter names. ## 2.3.4 **`(fix):`** Snippets and unit tests now correctly write optional request bodies when `inline_request_params` is set to `True`. ### What's been fixed * Snippets and unit tests now correctly write optional request bodies when `inline_request_params` is set to `True`. Previously the generator wrote snippets that inlined these parameters, which does not match the generated SDK itself. ## 2.3.3 **`(fix):`** Inlined body parameters now deconflict in naming with header and query parameters by prefixing the request objects name. ## 2.3.2 **`(fix):`** The query encoder now correctly handles none values ### What's been fixed * The `pyproject.toml` generator now writes authors in a valid format for `tool.poetry`, not just `project` * The query encoder now correctly handles none values ## 2.3.1 **`(fix):`** The `pyproject.toml` generator now includes project URLs when specified. ## 2.3.0 **`(chore):`** Users can now specify information that will appear in their pypi record. --- # May 20, 2024 ## 2.2.2 **`(fix):`** Inline request parameters now deconflict in naming with the unnamed path parameter arguments. ### What's been fixed * Inline request parameters now deconflict in naming with the unnamed path parameter arguments. Previously, when inlining request parameters into the method signature, we would not deconflict naming with the unnamed args preceding them. Now, conflicting unnamed parameters are post-fixed with an "\_". --- # May 17, 2024 ## 2.2.1 **`(internal):`** The generator now uses the latest FDR SDK. --- # May 16, 2024 ## 2.2.0 **`(chore):`** The generated SDK will now correctly encode deep object query parameters ### What's changed * The generated SDK will now correctly encode deep object query parameters. For example, if you have an object `{"test": {"nested": "object"}}` as a query parameter, we will now encode it as `test[nested]=object`. --- # May 15, 2024 ## 2.1.1 **`(chore):`** add enhanced snippet support for streaming endpoints. --- # May 14, 2024 ## 2.1.0 **`(feat):`** Add support for cursor and offset pagination ("auto-pagination"). ## 2.0.1 **`(fix):`** The python generator now only excludes unset fields that are not required. ### What's been fixed * the python generator previously used `exclude_unset` on pydantic models, however this would remove defaulted values. This change updates this to only exclude none fields that were not required. --- # May 9, 2024 ## 2.0.0 **`(break):`** Release of the Python SDK generator version 2, updating default configuration. ### What's changed * The python SDK is now on major version 2, there are no substantial logic changes, however default configuration has changed. To take this upgrade without any breaks, please add the below configuration to your `generators.yml` file: ## 1.7.0-rc0 **`(chore):`** you can now declare a new python version range for your `pyproject.toml`, which will declare a new version range for your pip package. ## 1.6.0-rc0 **`(chore):`** You can now specify dev dependencies from your `generators.yml` file --- # May 2, 2024 ## 1.5.3-rc0 **`(fix):`** the unchecked basemodel no longer tries to dereference an object if it's null. ## 1.5.2-rc0 **`(chore):`** The python generator now produces sync snippet templates, as opposed to just async templates as it was before --- # May 1, 2024 ## 1.5.1-rc5 **`(fix):`** Snippet templates now generate the correct imports for object types. ## 1.5.1-rc4 **`(fix):`** The SDK now generates discriminated union snippet templates correctly. ## 1.5.1-rc3 **`(chore):`** Union types leverage the fern aware base model to include JSON and Dict function overrides. ## 1.5.1-rc2 **`(fix):`** The vanilla pydantic base model now respects the `require_optional_fields` ### What's been fixed * The vanilla pydantic base model now respects the `require_optional_fields`, this became a regression in 1.5.1-rc0 when we started to inline union properties which leverages the vanilla base model. ## 1.5.1-rc1 **`(fix):`** Improve formatting within snippet templates. ### What's been fixed * Address formatting issues with snippet templates, we now strip newlines off OG snippets as well as plumb through indentation metadata to places that were previously missing it. --- # April 30, 2024 ## 1.5.0-rc0 **`(feat):`** The generator now supports inlining top-level request parameters instead of requiring users create a request object. --- # April 29, 2024 ## 1.4.0 **`(feat):`** keyword arguments are now ordered such that required params are ordered before optional params ### What's changed * keyword arguments are now ordered such that required params are ordered before optional params. Note that since these are kwargs, this is a non-breaking change. * docstrings now match numpydoc/PEP257 format --- # April 26, 2024 ## 1.5.1-rc0 **`(fix):`** Discriminated union variants that are objects now have inlined properties instead of extending a base type. --- # April 24, 2024 ## 1.4.0-rc3 **`(fix):`** pin mypy dependency to 1.9.0 to prevent introducing upstream bugs ### What's been fixed * Set `mypy` dev dependency in generated `pyproject.toml` to `1.9.0`. This prevents upstream `mypy` bugs from affecting user builds. Note that this is only a dev dependency, so it does not affect the behavior of the SDK. * Temporarily disable unit test generation. ### What's changed * Improvement: Use named parameters for all `httpx` request params. --- # April 23, 2024 ## 1.4.0-rc2 **`(fix):`** Initialize the OAuth token provider member variables to their default values before they are set. --- # April 22, 2024 ## 1.4.0-rc1 **`(feat):`** The python SDK generator now supports OAuth client generation for the client-credentials flow. ## 1.4.0-rc0 **`(chore):`** Generated clients now follow redirects by default. ### What's changed * Default generated clients to follow redirects by default, this effectively flips the `follow_redirects_by_default` flag to `True` and can be reverted with the following configuration: ## 1.3.1-rc0 **`(fix):`** the python SDK generator now checks to make sure a header is not null before casting it to a string. ## 1.3.0-rc1 **`(internal):`** add logging for python snippet template generation. --- # April 21, 2024 ## 1.3.0-rc0 **`(feat):`** Beta: The generator now registers snippet templates which can be used for dynamic SDK code snippet generation. --- # April 10, 2024 ## 1.2.0-rc2 **`(fix):`** The generator now correctly imports `json` when deserializing server sent events. ## 1.2.0-rc0 **`(internal):`** Consume IR v38 ### What's new * The generator now depends on v38 of Intermediate Representation which requires the latest CLI. As part of this, the generator now supports server sent events using `httpx-sse`. --- # April 4, 2024 ## 1.1.0-rc3 **`(fix):`** The skip validation code now works as expected. ### What's been fixed * There are a number of fixes to the skip validation code as well as tests to reflect those updates. ## 1.1.0-rc2 **`(fix):`** The generator now writes the skipped-validation `cast` with a suffixing new line so that the code compiles. ## 1.1.0-rc1 **`(fix):`** The generator no longer attempts to create a version file if Fern does not own generating the full package (e.g. in local generation). ### What's been fixed * The generator no longer attempts to create a version file if Fern does not own generating the full package (e.g. in local generation). It's too confusing for to make the relevant changes to the package set up, and is also arguably not even needed in local generation. --- # April 3, 2024 ## 1.1.0-rc0 **`(feat):`** The python SDK now includes a configuration option to skip pydantic validation. ### What's new * \[EXPERIMENTAL]: The python SDK now includes a configuration option to skip pydantic validation. This ensures that Pydantic does not immediately fail if the model being returned from an API does not exactly match the Pydantic model. This is meant to add flexibility, should your SDK fall behind your API, but should be used sparingly, as the type-hinting for users will still reflect the Pydantic model exactly. ## 1.0.1 **`(fix):`** Address Pydantic break when introducing `pydantic.v1` import within Pydantic V1 ### What's been fixed * Pydantic introduced a "break" to their 1.x libs by adding in a .v1 submodule that does not mirror the one that comes with pydantic v2. To get around this we now force the usage of the v1 submodule only if the pydantic version is v2. ## 0.13.4 **`(fix):`** revert changes introduced within 0.12.2 ### What's been fixed * revert the change from 0.13.2, the stream call returns a context manager, which is not awaited. The issue that this was meant to solve was actually fixed in version `0.12.2`. --- # April 2, 2024 ## 1.0.0 **`(break):`** The python SDK now defaults new (breaking configuration) to introduce general improvements. ### What's changed * Break: The python SDK now defaults new (breaking configuration) to introduce general improvements. * Improvement: The python SDK now supports specifying whether or not to follow redirects in requests by default, and exposes an option to override that functionality for consumers. --- # March 28, 2024 ## 0.13.3 **`(fix):`** Github workflows for publishing now work again (previously the trigger was incorrect). ## 0.13.2 **`(fix):`** Asynchronous calls to `httpx.stream` are now awaited. This is applicable to any file download or JSON streaming (chat completion) endpoints. --- # March 26, 2024 ## 0.13.1 **`(feat):`** discriminant values in unions are now defaulted such that callers no longer need to specify the discriminant --- # March 25, 2024 ## 0.13.0 **`(feat):`** the python SDK now exposes it's version through `__version__` to match module standards and expectations. --- # March 22, 2024 ## 0.12.5 **`(fix):`** the python SDK uses the timeout provided to the top level client as the default per-request ### What's been fixed * the python SDK uses the timeout provided to the top level client as the default per-request, previously if there was no timeout override in the RequestOptions, we'd default to 60s, even if a timeout was provided at the client level. --- # March 19, 2024 ## 0.12.4 **`(chore):`** Allow full forward compat with enums while keeping intellisense by unioning enum literals with `typing.AnyStr`. --- # March 18, 2024 ## 0.12.3 **`(feat):`** Allow bytes requests to take in iterators of bytes, mirroring the types allowed by HTTPX. ## 0.12.2 **`(fix):`** Fix the returned type and value contained within the retrying wrapper for the HTTPX client (http\_client.py). --- # March 14, 2024 ## 0.12.1 **`(chore):`** Improves example generation and snippets for union types, as well as multi-url environments. ### What's been fixed * Stringifies header arguments, HTTPX was previously hard failing for certain types ### What's changed * Improves example generation and snippets for union types, as well as multi-url environments. --- # March 11, 2024 ## 0.12.0 **`(feat):`** Auto-generated unit and integration tests against a mock server. ### What's new * Beta: The SDK now generates tests leveraging auto-generated data to test typing, as well as wire-formatting (e.g. the SDKs are sending and receiving data as expected). This comes out of the box within the generated github workflow, as well as through the fern cli: `fern test --command "your test command"`. --- # March 8, 2024 ## 0.11.10 **`(feat):`** Expose a feature flag to pass through additional properties not specified within your pydantic model from your SDK. ### What's new * Expose a feature flag to pass through additional properties not specified within your pydantic model from your SDK. This allows for easier forward compatibility should your SDK drift behind your spec. --- # March 4, 2024 ## 0.11.9 **`(chore):`** use docstrings instead of Pydantic field descriptions. --- # March 2, 2024 ## 0.11.8-rc1 **`(feat):`** Introduces a `max_retries` parameter to the RequestOptions dict accepted by all requests. ### What's changed * Beta: Introduces a `max_retries` parameter to the RequestOptions dict accepted by all requests. This parameter will retry requests automatically, with exponential backoff and a jitter. The client will automatically retry requests of a 5XX status code, or certain 4XX codes (429, 408, 409). --- # February 27, 2024 ## 0.11.8-rc0 **`(feat):`** introduces additional configuration to customize the client class and file name. ### What's changed * Beta: Introduce a `client` custom config that allows you to specify class\_name and filename for the client. This configuration can be used in several ways: ## 0.11.7 **`(feat):`** Introduces a flag `use_str_enums` to swap from using proper Enum classes to using Literals to represent enums. ### What's changed * Introduces a flag `use_str_enums` to swap from using proper Enum classes to using Literals to represent enums. This change allows for forward compatibility of enums, since the user will receive the string back. --- # February 26, 2024 ## 0.11.6 **`(feat):`** You can now specify envvars to scan for headers, not just auth scheme headers. --- # February 23, 2024 ## 0.11.5 **`(fix):`** Fix the usage of ApiError when leveraging auth envvars, when the schema for ApiError was changed, this usage was missed in the update. ## 0.11.4 **`(fix):`** We now grab enum values appropriately when enums are within unions. --- # February 22, 2024 ## 0.11.3 **`(fix):`** Transition from lists to sequences within function calls ### What's been fixed * Transition from lists to sequences within function calls, this is a fix as a result of how mypy handles type variance. This fix is only for function calls as testing shows that we do not hit the same issue within mypy with list\[union\[\*]] fields on pydantic objects. ### What's changed * Improvement: The Python SDK generator now defaults to `require_optional_fields = False`. This means that any requests that have optional fields no longer require a user to input data (or a `None` value) in. --- # February 21, 2024 ## 0.11.2 **`(feat):`** introduce configuration to flatten the directory structure ### What's changed * Improvement (Beta): The Python generator now supports a configuration option called `improved_imports`. --- # February 20, 2024 ## 0.11.1 **`(feat):`** Python now supports specifying files to auto-export from the root `__init__.py` file ### What's changed * Python now supports specifying files to auto-export from the root `__init__.py` file, this means you can export custom classes and functions from your package for users to access like so: * Add a docstring for base clients to explain usage, example: --- # February 19, 2024 ## 0.11.0 **`(feat):`** Python now supports a wider range of types for file upload ### What's been fixed * Python now supports API specifications that leverage lists for file upload. Previously, Fern incorrectly made all `list` type requests simply `file`. ### What's changed * Python now supports a wider range of types for file upload, mirroring the `httpx` library used under the hood, these are grouped under a new type `File`: ## 0.10.3 **`(fix):`** Several bugfixes were made to related to literal properties ### What's been fixed * Several bugfixes were made to related to literal properties. If a literal is used as a query parameeter, header, path parameter, or request parameter, the user no longer has to explicitly pass it in. --- # February 18, 2024 ## 0.10.2 **`(fix):`** The SDK always sends the enum wire value instead of the name of the enum. ### What's been fixed * The SDK always sends the enum wire value instead of the name of the enum. * Revert #2719 which introduced additional issues with circular references within our Python types. --- # February 14, 2024 ## 0.10.1 **`(feat):`** Add support for a RequestOptions object for each generated function within Python SDKs ### What's changed * Add support for a RequestOptions object for each generated function within Python SDKs. This parameter is an optional final parameter that allows for configuring timeout, as well as pass in arbitrary data through to the request. RequestOptions is a TypedDict, with optional fields, so there's no need to instantiate an object, just pass in the relevant keys within a dict! --- # February 13, 2024 ## 0.10.0 **`(break):`** The generator no longer supports Python 3.7 ### What's been removed * The generator no longer supports Python 3.7 * The `backports` dependency has been removed --- # February 11, 2024 ## 0.9.1 **`(fix):`** Remove literals from SDK function signatures, as they are not modifiable for end users ### What's been fixed * Remove literals from SDK function signatures, as they are not modifiable for end users. * Acknowledge the optionality of a `File` property, previously we were requiring all `File` type inputs, even if they were specified as optional within the OpenAPI or Fern definition. Now, we check if the parameter is required and make the parameter optional if it is not. ## 0.9.0 **`(feat):`** The SDK generator now supports whitelabelling ### What's new * The SDK generator now supports whitelabelling. When this is turned on, there will be no mention of Fern in the generated code. --- # January 29, 2024 ## 0.8.3-rc0 **`(fix):`** Increase recursion depth to allow for highly nested and complex examples ### What's been fixed * Increase recursion depth to allow for highly nested and complex examples, this is a temporary solution while the example datamodel is further refined. --- # January 28, 2024 ## 0.8.2-rc0 **`(fix):`** The Python SDK better handles cyclical references ### What's been fixed * The Python SDK better handles cyclical references. In particular, cyclical references are tracked for undiscriminated unions, and update\_forward\_refs is always called with object references. --- # January 26, 2024 ## 0.8.1 **`(feat):`** The generated SDK respects environment variables for authentication if specified ### What's new * If the auth scheme has environment variables specified, the generated python client will scan those environment variables. --- # January 25, 2024 ## 0.8.0 **`(fix):`** Enums in inlined requests send the appropriate value. --- # January 21, 2024 ## 0.7.7 **`(internal):`** Initialize the changelog --- # Go quickstart > Learn how to generate a Go SDK with Fern. Step-by-step guide to configure generators.yml, run fern generate, and create Go client libraries. Generate a Go SDK by following the instructions on this page. This page assumes that you have: * An initialized `fern` folder. See [Set up the `fern` folder](/sdks/overview/quickstart). * A GitHub repository for your SDK. See [Project Structure](/sdks/overview/project-structure). ### Pass `fern check` Run `fern check` to ensure that your API definition is valid. If there are any errors, fix them before proceeding. If you're using an OpenAPI Specification, check out all of our [supported extensions](/learn/api-definition/openapi/extensions). ### Add the SDK generator Run the following command to add the Go SDK generator to `generators.yml`: ```bash fern add fern-go-sdk --group go-sdk ``` `go-sdk` is the name of the `generators.yml` group that configures your Go SDK's output location and other metadata. You can customize this group name to differentiate between multiple SDKs across different languages (e.g., `ruby-sdk`, etc) in your organization. This command adds the following `group` to `generators.yml`: ```yaml title="generators.yml" go-sdk: # group name generators: - name: fernapi/fern-go-sdk version: 1.23.4 output: location: local-file-system path: ../sdks/go ``` ### Generate the SDK Run the following command to generate your SDK: ```bash fern generate --group go-sdk ``` If you have multiple APIs, use the [`--api` flag](/cli-api-reference/cli-reference/commands#api) to specify the API you want to generate: ```bash fern generate --group go-sdk --api your-api-name ``` This creates a `sdks` folder in your current directory. The resulting folder structure looks like this: --- # Go configuration > Configuration options for the Fern Go SDK. You can customize the behavior of the Go SDK generator in `generators.yml`: ```yaml {6-7} title="generators.yml" groups: go-sdk: generators: - name: fernapi/fern-go-sdk version: 1.23.4 config: packageName: acme output: location: local-file-system path: ../generated/go ``` When enabled, ensures that all required properties are always included in API requests, even if they have default values or are otherwise optional in the implementation. Customizes the name of the client constructor function. This allows you to specify a custom name for the function that users will call to create a new instance of the client. Specifies the name of the generated client struct. This determines the primary client type name that users will interact with in the generated Go SDK. Sets the name of the exported client that will be used in code snippets and documentation examples. This is useful for customizing how the client appears in generated documentation. Generates [mock server (wire) tests](/sdks/deep-dives/testing#mock-server-tests) to verify that the SDK sends the correct HTTP requests and correctly handles responses per the API spec. When enabled, Docker is required as a runtime dependency to run the generated tests. Use this option if you plan to depend on the generated Go SDK from within your project, and **not** depend on it as a separate, published Go module. If you plan to to distribute the generated Go SDK as a separate, published Go module, use the `module` configuration option instead. You can generate the Go SDK code into a `gen/go/api` package with the following `generators.yml` configuration: ```yaml {7-8} default-group: local groups: local: generators: - name: fernapi/fern-go-sdk version: 0.13.0 config: importPath: github.com///generated/go output: location: local-file-system path: ../generated/go ``` You must update the `` and `` placeholders with the relevant elements in your `go.mod` path. In this case, the generated Go SDK uses the same `go.mod` path used by the rest of your Go module. When enabled, includes legacy client options for backward compatibility with older versions of the SDK. This is useful for maintaining compatibility when upgrading SDK versions. Controls whether file upload properties are generated as inline request properties instead of separate parameters. When enabled, file upload fields become part of the request struct rather than being passed as individual function parameters. When enabled, path parameters are inlined into request types rather than being passed as separate function parameters. This creates a more unified request structure where path parameters are included in the request object. Use this option if you plan to distribute the generated Go SDK as a separate, published Go module. If you only plan to use the generated SDK within your own Go module, use the `importPath` configuration option instead. You can generate the Go SDK code into a separate module (defined with its own `go.mod`) with the following `generators.yml` configuration: ```yaml {7-9} default-group: local groups: local: generators: - name: fernapi/fern-go-sdk version: 0.13.0 config: module: path: github.com// output: location: local-file-system path: ../generated/go ``` This configuration will generate a `go.mod` alongside the rest of the Go SDK code at the target output location. With this, `import` statements within the generated Go SDK are all resolved from the configured module path. By default, the generated `go.mod` will be set to `1.13`. You can override this behavior by specifying the `version` key: ```yaml {10} default-group: local groups: local: generators: - name: fernapi/fern-go-sdk version: 0.13.0 config: module: path: github.com// version: "1.19" output: location: local-file-system path: ../generated/go ``` If you want to depend on the generated Go SDK locally (without distributing it as a separate Go module), and you use the `module` configuration option, you will need to modify your project's top-level `go.mod` to include a [`replace`](https://go.dev/doc/modules/gomod-ref#replace) statement: ```go module github.com/your/module require "github.com/your/sdk" v0.0.0 replace "github.com/your/sdk" v0.0.0 => "path/to/generated/sdk" ``` Controls the organization of the generated package structure. Choose 'flat' for a flatter package structure with fewer nested directories, or 'nested' for a more hierarchical organization that mirrors your API structure. Specifies the package name for the generated Go code. This determines the package declaration that will appear at the top of generated Go files and affects how users import the SDK. Controls the union type generation strategy. Use 'v0' for the legacy union implementation or 'v1' for the newer, more robust union handling approach that provides better type safety and discriminated union support. When enabled, uses `io.Reader` interface for handling byte request bodies instead of byte slices. This is more memory-efficient for large payloads and follows Go best practices for streaming data. --- # Publishing as a Go module > Learn how to publish your Fern-generated Go SDK to pkg.go.dev. Configure generators.yml and release versioned Go modules. Publish your public-facing Fern Go SDK to [pkg.go.dev](https://proxy.golang.org/). After following the steps on this page, you'll have a versioned package published on pkg.go.dev. Versioned package published on Pkgsite This page assumes that you have: * An initialized `fern` folder. See [Set up the `fern` folder](/sdks/overview/quickstart). * A GitHub repository for your SDK. See [Project Structure](/sdks/overview/project-structure). To successfully publish your SDK as a Go module, your repository must have: * **Public** visibility * An [approved license](https://pkg.go.dev/license-policy) (e.g. [MIT](https://opensource.org/license/mit), [Apache](https://www.apache.org/licenses/LICENSE-2.0)) ## Configure `generators.yml` Go publishes via Git repositories, so remove the auto-generated `output` and `config` properties. Instead, add the path to your GitHub repository: ```yaml {6-7} groups: go-sdk: generators: - name: fernapi/fern-go-sdk version: 1.23.4 github: repository: devalog/company-go ``` ## Publish to pkg.go.dev At this point, you're ready to generate a release for your SDK. Regenerate your SDK and publish it on pkg.go.dev: ```bash fern generate --group go-sdk --version ``` Local machine output will verify that the release is pushed to your repository and tagged with the version you specified. Navigate to `https://pkg.go.dev/github.com///` and send a request to index your package. In a few minutes, your new release should be published to [https://pkg.go.dev/](https://pkg.go.dev/)! After releasing a new version, it may take a few minutes for pkg.go.dev to index and display the update. You can also try checking to see if the Go proxy has indexed your module at `https://proxy.golang.org/github.com///@v/list`. pkg.go.dev indexing usually happens within 5-15 min of the proxy picking it up. For more information, see Go's documentation on [Adding a package](https://pkg.go.dev/about#adding-a-package). --- # Adding custom code > Learn how to add custom logic and methods to your Go SDK with Fern. Extend generated clients with helper functions and custom code. This page covers how to add custom logic and methods to your Go SDK. Before getting started, [read about how Fern SDKs use custom code and learn about the `.fernignore` file](/sdks/overview/custom-code) . ## Adding custom logic To get started adding custom code: ### Create a new file and add your custom logic ```go title="helper.go" func MyHelper() { fmt.Println("Hello World!") } ``` ### Add your file to `.fernignore` ```yaml {3} title=".fernignore" # Specify files that shouldn't be modified by Fern helper.go ``` ### Consume the helper Now your users can consume the helper function by importing it from the SDK. ```go import "github.com/package/example" example.MyHelper(); ``` ## Adding custom SDK methods Fern also allows you to add custom methods to the SDK itself (e.g. `client.my_method()` ) by inheriting the Fern generated client and then extending it. ### Update `generators.yml` configuration Name your Fern-generated client something like `BaseClient` to reflect that this client will be extended. ```yml {4} title="generators.yml" - name: fernapi/fern-go-sdk version: "..." config: clientName: BaseClient ``` ### Import and extend the generated client First, import the Fern generated base client and extend it. Then, add whatever methods you want. ```go title="client/my_client.go" type MyClient struct { *Client // Embed the Fern generated client. } func NewMyClient(opts ...option.RequestOption) *MyClient { return &MyClient{ Client: NewClient(opts...), } } func (m *MyClient) MyHelper() { fmt.Println("Hello World!") } ``` ### Update `.fernignore` Add the `client/my_client.go.` to `.fernignore`. ```diff title=".fernignore" + client/my_client.go ``` ### Consume the method Instead of constructing the generated client, your users will want to construct the extended client. ```go title="main.go" import exampleclient "github.com/package/example/client" client := exampleclient.NewMyClient(): ``` Now your users can consume the helper function by importing it from the SDK. ```go client.MyHelper() ``` --- # January 26, 2026 ## 1.23.4 **`(fix):`** Fix unsafe pointer dereference in cycle.go. ## 1.23.3 **`(fix):`** Fix wire test generation for exhaustive fixture. This includes several fixes: * Fix int vs int64 type mismatch for long types by explicitly casting to int64 * Fix enum values to use .Ptr() method for pointer types * Fix field names to use Go exported names (e.g., FieldString instead of String) * Add Bytes helper function for \[]byte pointer types * Skip endpoints returning primitive date types in wire tests (workaround for Go SDK date parsing issue where time.Time expects RFC3339 datetime format) --- # January 25, 2026 ## 1.23.2 **`(fix):`** Fix undiscriminated union type matching in dynamic snippets and wire tests. Previously, when converting example values to undiscriminated union types, the generator would accept the first type that didn't throw an error, even if the conversion resulted in a nop (no-op). This caused empty struct literals to be generated instead of properly initialized union variants. The fix now skips types that result in nop conversions and continues to the next type in the union. --- # January 23, 2026 ## 1.23.1 **`(fix):`** Fix non-deterministic import ordering in generated Go files. Imports are now sorted alphabetically by alias, preventing unnecessary churn in automated seed updates. ## 1.23.0 **`(feat):`** Add RecvRaw method to stream API and improve SSE terminator handling for more robust server-sent event processing --- # January 21, 2026 ## 1.22.9 **`(chore):`** Update IR version to 61 to support Generation Metadata feature and maintain consistency with seed configuration. --- # January 14, 2026 ## 1.22.8 **`(fix):`** Fix internal v1-side failure to pass alwaysSendRequiredProperties when visiting inlined request bodies. --- # January 13, 2026 ## 1.22.7 **`(chore):`** Update Dockerfile to use the latest generator-cli with improve reference.md generation. ## 1.22.6 **`(fix):`** Update CI workflow to match robust wiremock testing implementation from seed configuration. The GitHub Actions workflow now uses unique project naming, proper port extraction, and reliable cleanup with separate setup/test/teardown steps to prevent Docker Compose conflicts and ensure consistent test execution. --- # January 12, 2026 ## 1.22.5 **`(fix):`** Fix dynamic snippets for optional aliases to literal types. Previously, the generator would produce invalid Go code like `&SortField("DEFAULT")` which tries to take the address of a type conversion. Now it correctly uses the primitive's pointer helper function (e.g., `fern.String("DEFAULT")`) for optional literal aliases. --- # January 8, 2026 ## 1.22.4 **`(fix):`** Fix wiremock port collisions when running wire tests in parallel. The docker-compose configuration now uses ephemeral ports (0:8080) instead of fixed port 8080, and the generated test code reads the WIREMOCK\_PORT environment variable to discover the dynamically assigned port at runtime. ## 1.22.3 **`(fix):`** Fix OAuth form URL encoding to respect custom MarshalJSON methods. The form URL encoding now marshals the request to JSON first, then converts to form data, ensuring fields like `grant_type` that are added via custom MarshalJSON are included in the request body. --- # January 6, 2026 ## 1.22.2 **`(fix):`** Make OAuth wire tests dynamic to support different SDK structures. The OAuth test generator now extracts service information (client accessor path, method names, field names) directly from the IR, enabling wire tests to work across different OAuth configurations without hardcoded assumptions. --- # January 5, 2026 ## 1.22.1 **`(fix):`** Add 'v' prefix to sdkVersion in metadata.json to follow Go module versioning conventions. ## 1.22.0 **`(feat):`** Generate error\_codes.go per-namespace for multi-namespace Go SDKs. Each namespace now has its own error\_codes.go file containing only the error codes and error types from that namespace, rather than a single global file with all errors. --- # December 18, 2025 ## 1.21.8 **`(fix):`** Add request scoping to wire tests using X-Test-Id header. Each test now sends a unique header that is used to filter WireMock request verification, enabling safe concurrent test execution without interference between tests. ## 1.21.7 **`(chore):`** Fix nil check in caller ## 1.21.6 **`(chore):`** Add GO\_V2\_PATH environment variable support for configurable v2 binary path during local development and testing ## 1.21.5 **`(fix):`** Fix duplicate test function generation in wire tests. When multiple endpoints map to the same test function name, subsequent occurrences now get numeric suffixes (e.g., Test2, Test3) to avoid Go compilation errors while preserving all test coverage. ## 1.21.4 **`(chore):`** Add sdkVersion as a top-level field in the generated metadata.json file. --- # December 17, 2025 ## 1.21.3 **`(fix):`** Fix multi-URL environment resolution to fall back to client-level environment when per-request environment is not specified. This ensures endpoints correctly resolve their base URL when the environment is set at client construction time. --- # December 16, 2025 ## 1.21.2 **`(fix):`** Fix retry logic to reset request body before each retry attempt. ## 1.21.1 **`(fix):`** Fix OAuth token handling for optional expires\_in field. Use pointer conversion for optional request fields and check ExpiresIn as pointer type with default fallback. --- # December 15, 2025 ## 1.21.0 **`(feat):`** Add support for multi-URL environments via `x-fern-server-name` extension. APIs with multiple base URLs per environment can now route different endpoints to different base URLs automatically. The SDK generates a named `Environment` struct with fields for each base URL, and endpoints resolve their base URL using the `ResolveEnvironmentBaseURL` function. --- # December 12, 2025 ## 1.20.2 **`(fix):`** Fix OAuth token fetching to use GetOrFetch instead of GetToken. ## 1.20.1 **`(fix):`** Improve OAuth token fetching with concurrency protection and better error handling. Multiple concurrent requests now share a single token fetch instead of each triggering their own. Added nil pointer checks for OAuth responses and a 1-hour default expiry fallback when the server doesn't provide an expires\_in value. --- # December 11, 2025 ## 1.20.0 **`(feat):`** Add `errorCodes` config option with values `per-endpoint` or `global`. The `global` mode (default) generates a shared `error_codes.go` file for all errors. The `per-endpoint` mode generates error handling code inline for each endpoint, which is more robust for namespaced APIs or APIs where different endpoints have different error schemas for the same status code. --- # December 10, 2025 ## 1.19.0 **`(feat):`** Add OAuth token fetching support. The SDK now automatically fetches and caches OAuth tokens using client credentials when configured. Tokens are refreshed automatically when expired. --- # December 2, 2025 ## 1.18.4 **`(fix):`** Fix snippet generation for object types with optional fields that have no example value. Previously, these fields would generate invalid Go code with `` instead of being omitted. --- # November 26, 2025 ## 1.18.3 **`(fix):`** Fix handling of reserved identifiers in field names and make dynamic snippets match. ## 1.18.2 **`(fix):`** `QueryValuesWithDefaults` now handles `nil` inputs safely. --- # November 24, 2025 ## 1.18.1 **`(fix):`** Fix linting in test files --- # November 21, 2025 ## 1.18.0 **`(feat):`** Add support for custom pagination (with particular implementation) Fix dynamic snippets handling for alias of collection literals. ## 1.17.1 **`(fix):`** Remove using generator-cli to push to GitHub for self-hosted SDKs; this is now handled in the local workspace runner. --- # November 19, 2025 ## 1.17.0 **`(feat):`** Provide Page.Response for accessing the full response type returned by the call to the relevant endpoint. Pagination now automatically includes the following fields on each page: ```go type Page[Cursor comparable, T any, R any] struct { Results []T Response R RawResponse PageResponse[Cursor, T, R] StatusCode int Header http.Header ... } ``` where `Results` is the standard slice of results, sufficient for most use cases; `Response` is the full response type of the HTTP call, which includes the `Results` as a sub-attribute; `RawResponse`, which exposes the underlying pagination mechanism if need; and `StatusCode` and `Header`, raw HTTP response metadata corresponding to the data returned by `withRawResponse()` on non-paginated endpoints. ## 1.16.5 **`(fix):`** Fix Basic auth header formatting to remove erroneous whitespace between username and password. Passwords with colons are now properly supported per RFC 7617 specification. ## 1.16.4 **`(chore):`** Reasonable default for empty request bodies in wiremock json mappings. ## 1.16.3 **`(chore):`** Bump generator CLI version to publish new Docker image. --- # November 18, 2025 ## 1.16.2 **`(fix):`** Ensure wire tests run in CI correctly with docker compose strategy. ## 1.16.1 **`(chore):`** Update documentation on retrieving the raw response for paginated/non-paginated endpoints. --- # November 17, 2025 ## 1.16.0 **`(feat):`** Provide Page.Header and Page.StatusCode for accessing the headers and status codes of paginated responses; unlike for non-paginated responses, this raw data is always included in the response. ## 1.15.2 **`(fix):`** Fix dynamic snippets behavior to use same defaults for inline request parameters. --- # November 13, 2025 ## 1.15.1 **`(fix):`** Fix issue where unmarshaling optional bodies for requests with non-primitive query params tried to assign a value type to a pointer field. --- # November 11, 2025 ## 1.15.0 **`(feat):`** Add custom license file support for local generation and normalize version format with 'v' prefix following Go conventions --- # November 7, 2025 ## 1.14.2 **`(fix):`** - more flexible SSE parsing logic --- # November 5, 2025 ## 1.14.1 **`(fix):`** - wire tests respect root package name as alias --- # November 4, 2025 ## 1.14.0 **`(feat):`** Added Generation Metadata file to output --- # October 29, 2025 ## 1.13.17 **`(fix):`** - expose raw paginated response * fix server-sent events streaming functionality --- # October 21, 2025 ## 1.13.16 **`(chore):`** Refactor wire test generation to use the new mock utils. ## 1.13.15 **`(fix):`** Fix for regression to streaming endpoints call --- # October 12, 2025 ## 1.13.14 **`(fix):`** Fix for default request values and nullable types. --- # October 8, 2025 ## 1.13.13 **`(fix):`** final fix for embedded local packages ## 1.13.12 **`(fix):`** must pin wiremock indirect dependencies to later fixed versions --- # October 6, 2025 ## 1.13.11 **`(fix):`** must pin wiremock dependencies to versions that still support go 1.23 ## 1.13.10 **`(fix):`** fix regression - v2 should not produce go.mod files for embedded local packages (use of importPath option) --- # October 3, 2025 ## 1.13.9 **`(fix):`** Fix code snippets in the README to alias root imports with the configured package name. --- # October 2, 2025 ## 1.13.8 **`(fix):`** use correct port for wire tests in containerized environments (seed and CI) ## 1.13.7 **`(fix):`** Fix to allow wire tests to run in containerized environments (seed and CI) ## 1.13.6 **`(fix):`** Remove occasional double-running of a build step. --- # October 1, 2025 ## 1.13.5 **`(fix):`** Restructure wire tests into separate per-service packages. --- # September 30, 2025 ## 1.13.4 **`(fix):`** Upgrade generator-cli dependency to fix local generation handling of .fernignore files. ## 1.13.3 **`(fix):`** Add reserved keywords alias anti-collision to v2 generator logic. --- # September 29, 2025 ## 1.13.2 **`(fix):`** Added functionality to generated wire tests. --- # September 25, 2025 ## 1.13.1 **`(fix):`** Stop generating go.mod file in go-v2 sdk generation. ## 1.13.0 **`(feat):`** Add support for PR mode for self-hosted/local sdk generation ## 1.12.6 **`(fix):`** Fix name collision between receiver and parameter. --- # September 24, 2025 ## 1.12.5 **`(chore):`** Internal cleaning, cosmetic changes in dynamic snippet output. ## 1.12.4 **`(chore):`** Upgrade to IRv60. ## 1.12.3 **`(fix):`** Handle error codes using a shared error decoder. ## 1.12.2 **`(fix):`** Fix small inconsistencies in dynamic snippets logic blocking wire test generation --- # September 23, 2025 ## 1.12.1 **`(chore):`** Document setters and explicit null in `README.md`. --- # September 18, 2025 ## 1.12.0 **`(feat):`** Add support for custom sections in the README.md via `customSections` config option. ## 1.11.3 **`(chore):`** Update retrier to match strategy with TS SDKs exactly; in particular, don't use jitter on `retry-after` and instead respect it exactly. ## 1.11.2 **`(fix):`** Fixes bit field initialization for properties with indices >= 64. --- # September 17, 2025 ## 1.11.1 **`(fix):`** Fixes an issue where the generated usage snippets in the README.md was not prioritizing user defined example values over autogenerated example values. ## 1.11.0 **`(feat):`** Add config flag `exportAllRequestsAtRoot`, which restructures the repo such that all request types are exposed through the root-level namespace. --- # September 16, 2025 ## 1.10.0 **`(feat):`** Adds setter methods for all objects; these also mark their respective fields as required, such that you can now specify explicit null values for optional fields. --- # September 12, 2025 ## 1.9.0 **`(feat):`** Add config flag `gettersPassByValue`, which ensures that GetXYZ() methods on responses return dereferenced versions of optional arguments that are never nil. --- # September 10, 2025 ## 1.8.1 **`(fix):`** Add back support for local filesystem output mode. --- # September 9, 2025 ## 1.8.0 **`(feat):`** Retries now check `Retry-After` and `X-RateLimit-Reset` before defaulting to exponential backoff. --- # August 29, 2025 ## 1.7.0 **`(feat):`** Add support for the `apiName`, `disabledFeatures`, and `whiteLabel` readme config options. --- # August 27, 2025 ## 1.6.7 **`(fix):`** Removes legacy logic for flat package layout. --- # August 26, 2025 ## 1.6.6-rc0 **`(fix):`** Fixes the ignoring of a default for `page` in pagination requests. --- # August 25, 2025 ## 1.6.5-rc0 **`(fix):`** Fix certain instances of fmt.Sprintf'd values failing to be dereferenced. --- # August 22, 2025 ## 1.6.4-rc0 **`(fix):`** Redesign the client to share RequestOptions across all subclients. --- # August 21, 2025 ## 1.6.3 **`(fix):`** Update the dynamic snippet generator to handle list values in the request body. Previously, it would throw an error. ## 1.6.2 **`(feat):`** Add support for handling `default`s for query parameters. --- # August 20, 2025 ## 1.6.1 **`(feat):`** Add reference.md doc generation ## 1.6.0 **`(feat):`** Add support for specifying a custom subdirectory to generate into. ## 1.5.8 **`(fix):`** Fix named string literals in undiscriminated unions. --- # August 7, 2025 ## 1.5.7-rc0 **`(fix):`** Fix go sse event stream handling. ## 1.5.6 **`(chore):`** Publishing new version after reverting bad commit that released an rc version 1.5.5-rc0. --- # August 1, 2025 ## 1.5.4 **`(fix):`** If enum values contain a slash, the go generator now effectively escapes these and makes sure that the Go SDK will still compile. --- # July 25, 2025 ## 1.5.3 **`(fix):`** Fix a regression where the `useReaderForBytesRequest` configuration option was not being respected after `1.5.0`. --- # July 21, 2025 ## 1.5.2 **`(fix):`** Make sure that optional headers and query params are properly dereferenced before being sent to the server. ## 1.5.1 **`(fix):`** Enum headers are now correctly serialized in API requests. When an endpoint specifies an enum type for a header parameter, the SDK will automatically serialize the enum value to its string representation as expected by the API. ## 1.5.0 **`(internal):`** Update the primary client to delegate to the new raw client to reduce code duplication. --- # July 1, 2025 ## 1.4.0 **`(feat):`** Add support for receiving raw response headers from API calls with the new `WithRawResponse` client field for multipart/form-data endpoints. --- # June 26, 2025 ## 1.3.0 **`(feat):`** Add support for receiving raw response headers from API calls with the new `WithRawResponse` client field. ```go response, err := client.WithRawResponse.GetUser(...) fmt.Printf("Got response headers: %v", response.Header) ``` **`(feat):`** Bump the minimum Go version to `1.18` because generics are now required by the SDK. Version 1.18 was originally released over three years ago, so this is well within the official Go support window found at [https://go.dev/doc/devel/release#policy](https://go.dev/doc/devel/release#policy) --- # June 3, 2025 ## 1.2.0 **`(feat):`** Add support for generating `README.md` when filesystem publishing is enabled. --- # May 22, 2025 ## 1.1.0 **`(feat):`** Add support for HEAD method requests. These client methods return the raw `http.Header` type. **`(fix):`** Update the file header to follow `go:generate` naming conventions. For details, see [https://pkg.go.dev/cmd/go#hdr-Generate\_Go\_files\_by\_processing\_source](https://pkg.go.dev/cmd/go#hdr-Generate_Go_files_by_processing_source) --- # May 20, 2025 ## 1.0.0 **`(feat):`** Major version release to update the generator's default set of configuration options. The following configuration options have been updated: * `alwaysSendRequiredProperties` is now `true` by default. * `inlineFileProperties` is now `true` by default. * `inlinePathParameters` is now `true` by default. * `useReaderForBytesRequest` is now `true` by default. * `union` is now `v1` by default. --- # May 14, 2025 ## 0.38.0 **`(feat):`** Add support for the `useReaderForBytesRequest` configuration option, which generates `io.Reader` request parameters instead of `[]byte` request parameters. --- # May 13, 2025 ## 0.37.5 **`(fix):`** Add support for the custom introduction setting in the generated README.md. --- # May 8, 2025 ## 0.37.4 **`(fix):`** Fix an issue where enum values containing double quotes were not properly escaped in generated code. --- # May 1, 2025 ## 0.37.3 **`(fix):`** Install the generator-cli at build time as a fallback if runtime installation fails. --- # March 13, 2025 ## 0.37.2 **`(fix):`** Fix an issue where the `go-v2` generator call prevented the `go` generator from succeeding in remote code generation environments. ## 0.37.1 **`(fix):`** Fix an issue where the primary Go files were not being written due to README.md generation. ## 0.37.0 **`(internal):`** Upgrade to IRv57. **`(feat):`** Add support for automatic `README.md` generation. --- # February 17, 2025 ## 0.36.5 **`(fix):`** Fix an issue where `map` values were not correctly serialized as deep object query parameters. --- # February 5, 2025 ## 0.36.4 **`(fix):`** Fix an issue where the `go-v2` generator call prevented the `go` generator from succeeding in remote code generation environments. --- # February 4, 2025 ## 0.36.3 **`(fix):`** Fix an issue where the version header specified by the user wasn't being used. --- # January 26, 2025 ## 0.36.2 **`(fix):`** Fix cursor pagination stopping condition when the cursor types do not match (e.g. a `*string` cursor type with a `string` next cursor type). --- # January 23, 2025 ## 0.36.1 **`(fix):`** Fix offset pagination method generation for non-integer offset parameters (e.g. `float64`). --- # January 22, 2025 ## 0.36.0 **`(feat):`** Adds support for a few new configuration options, all of which are shown below: ```yaml - name: fern-api/fern-go-sdk version: 0.36.0 config: packageLayout: flat clientName: Acme clientConstructorName: New ``` With this, the generated SDK will all be deposited at the root of the module, and the client can be constructed like so: ````go package main import ( "context" "fmt" "log" acme "github.com/acme/acme-go" ) func main() { client := acme.New() response, err := client.GetUser( context.Background(), &acme.GetUserRequest{ ID: "85307b0b-094b-41b5-b61d-347ca15e5da2", }, ) if err != nil { log.Fatal(err) } fmt.Println(response) } ``` ```` --- # January 17, 2025 ## 0.35.2 **`(fix):`** Fixes an issue where certain literal string values were incorrectly generated in undiscriminated unions. **`(fix):`** Fixes an issue where custom names applied to a basic auth scheme were not preserved. --- # January 3, 2025 ## 0.35.1 **`(fix):`** Fixes an issue where the delimiter length was included during stream data read, even when the delimiter was missing, leading to a `bufio.ErrAdvanceTooFar` error --- # December 12, 2024 ## 0.35.0 **`(feat):`** Add runtime validation for discriminated unions to prevent users from accidentally sending the wrong type of value. With this, users will be expected to set exactly one of the union's values like so: ````go package example type Animal struct { Type string Cat *Cat Dog *Dog } func do() { union := &Animal{ Cat: &Cat{ Name: "Fluffy", }, } } ``` If the user sets _both_ `Cat` and `Dog`, the user will receive an error when the type is serialized to JSON (i.e. in the `json.Marshaler` implementation). ## 0.34.0 **`(feat):`** Add support for sending the `User-Agent` header on every request. Go packages are uniquely identified by their full module path, so the `User-Agent` header is generated in the `/` format, e.g. ``` User-Agent: github.com/acme/acme-go/1.0.0 ``` ```` --- # November 21, 2024 ## 0.33.0 **`(feat):`** Add support for the `inlinePathParameters` configuration option, which generates path parameters in the generated request type (if any) instead of as separate positional parameters. ```yaml # generators.yml - name: fern-api/fern-go-sdk version: 0.33.0 config: inlinePathParameters: true ``` --- # November 20, 2024 ## 0.32.1 **`(internal):`** Improve the aesthetics of the generated code, and reduce the amount of repetition in each of the generated endpoints. This change has zero impact on the behavior of the generated SDK. --- # November 18, 2024 ## 0.32.0 **`(feat):`** Add support for the `inlineFileProperties` configuration option, which generates file properties in the generated request type instead of as separate positional parameters. ```yaml # generators.yml - name: fern-api/fern-go-sdk version: 0.32.0 config: inlineFileProperties: true ``` **`(fix):`** Fixes an issue where the new `core.MultipartWriter` was generated for SDKs that didn't define any file upload endpoints. **`(internal):`** Simplify the generated code from the new `core.MultipartWriter` introduced in 0.29.0 by refactoring `internal.WithMultipartContentType` as `internal.WithDefaultContentType`. ## 0.31.3 **`(fix):`** Updates the retrier to stop retrying on `409 Conflict` HTTP status codes by default. --- # November 15, 2024 ## 0.31.2 **`(internal):`** Add an `internal` package, which now contains the internal functionality previously included in the `core` package (e.g. `core.Caller` -> `internal.Caller`). Although technically a breaking change in terms of the module itself, this change was always the intention, and should have zero impact on users. Any `core` type that is meant for public consumption remains in the exported `core` package (e.g. `core.APIError` and `core.RequestOption`). ## 0.31.1 **`(internal):`** Adds additional tests to confirm the behavior of the `core.Retrier`. No functional, user-facing changes are included. --- # November 14, 2024 ## 0.31.0 **`(feat):`** Improves type file layout with zero impact on backwards compatibility. Shared types are now more accurately placed in the `types.go` file, whereas types referenced by a single service are now placed in a file that matches the service's filename (e.g. user.go). --- # November 8, 2024 ## 0.30.0 **`(feat):`** Add support for nil-safe getter methods. Callers can more easily access nested properties by chaining together getter method calls instead of a long series of `!= nil` checks. ## 0.29.0 **`(feat):`** All SDKs now include an exported `FileParam` type that can be used to configure the `Content-Type` of file upload properties. **`(fix):`** Resolves an issue where multipart/form-data lists were incorrectly serialized as JSON. They are now added as individual parts. **`(internal):`** Refactor file upload endpoint generation with the new `core.MultipartWriter`. This significantly improves the aesthetics of the generated code. --- # November 7, 2024 ## 0.28.3 **`(internal):`** Upgrade to IRv53. --- # November 6, 2024 ## 0.28.2 **`(fix):`** Fix an issue where undiscriminated unions were not round-trippable whenever the union is the zero value of the type (e.g. `0` for `int`). --- # October 29, 2024 ## 0.28.1 **`(fix):`** Fix an issue where optional, allow-multiple query parameter snippets were not rendered. **`(fix):`** Fix an issue where service headers were not included in the generated in-lined request. **`(fix):`** Fix an issue where literal types were included as path parameter arguments. --- # October 25, 2024 ## 0.28.0 **`(feat):`** Add support for the exportedClientName configuration, which can be used to customize the generated client name and constructor included in snippets. Note that this configuration option assumes that the SDK includes a hand-written client constructor defined in the client package. --- # September 29, 2024 ## 0.27.0 **`(feat):`** Add support for SSE (Server-Sent Events) streaming responses. The user-facing interface for streaming responses remains the same between standard HTTP streaming and SSE. --- # September 26, 2024 ## 0.26.0 **`(feat):`** Add support for sending custom Content-Type header values defined in the API. --- # September 9, 2024 ## 0.25.0 **`(feat):`** Add support for sending extra body properties and query parameters via `RequestOption`. --- # September 8, 2024 ## 0.24.0 **`(feat):`** Add support for reading headers from environment variables (e.g. `X-API-Version`). --- # September 6, 2024 ## 0.23.7 **`(fix):`** Fixes an issue where optional `unknown` values (typed as `interface{}`) were mistakenly dereferenced. --- # September 5, 2024 ## 0.23.6 **`(internal):`** No changes. ## 0.23.5 **`(fix):`** Fix an issue where `long` type examples (generated as `int64` in Go) were not successfully converted to their equivalent `string` representation for snippets. --- # August 30, 2024 ## 0.23.4 **`(internal):`** No changes. ## 0.23.3 **`(internal):`** No changes. --- # August 26, 2024 ## 0.23.2 **`(internal):`** No changes. --- # August 19, 2024 ## 0.23.1 **`(fix):`** Fix literal value deserialization. ### What's changed * Updates object and undiscriminated union deserialization to return an error whenever any literal values do not exist or are mismatched. --- # August 7, 2024 ## 0.23.0 **`(feat):`** Add support for always sending required properties. ### What's new * Added the `alwaysSendRequiredProperties` configuration option. When `alwaysSendRequiredProperties` is enabled, required properties are never omitted in the type's wire representation. Any required property that is not explicitly set will send the default value for that type. --- # July 22, 2024 ## 0.22.3 **`(fix):`** Fix an issue where APIs that specify the `property-name` error discrimination strategy would receive JSON decode errors instead of the server's error. --- # July 4, 2024 ## 0.22.2 **`(fix):`** Request types set to `nil` no longer send an explicit `null` value. --- # June 11, 2024 ## 0.22.1 **`(fix):`** Array of `deepObject` query parameters are correctly serialized. --- # May 21, 2024 ## 0.22.0 **`(feat):`** Add support for retrieving extra properties from response objects. ### What's new * Extra properties decoded from response objects are retained and accessible via the `GetExtraProperties` method. --- # May 17, 2024 ## 0.21.3 **`(internal):`** The generator now uses the latest FDR SDK. --- # May 7, 2024 ## 0.21.2 **`(fix):`** In-lined request body properties no longer include a non-empty `url` struct tag. --- # April 29, 2024 ## 0.21.1 **`(fix):`** The Go generator now escapes path parameters that would previously create invalid URLs (e.g. "\example"). **`(internal):`** Refactor endpoint URL mapping with `core.EncodeURL`. ## 0.21.0 **`(feat):`** Add support for cursor and offset pagination. --- # April 26, 2024 ## 0.20.2 **`(internal):`** Enhance extra property serialization performance. **`(internal):`** Generate additional extra property tests into the SDK. **`(fix):`** Resolve a non-deterministic key ordering issue for snippets of type `unknown`. **`(fix):`** Resolve an issue with discriminated union serialization. --- # April 25, 2024 ## 0.20.1 **`(fix):`** The `omitempty` struct tag is now only used for nil-able types. **`(fix):`** Update the query encoder to prevent unintentional errors whenever the `omitempty` is used for a non-optional field. --- # April 24, 2024 ## 0.20.0 **`(feat):`** The Go generator now supports extra properties. --- # April 16, 2024 ## 0.19.0 **`(feat):`** The Go generator now supports environment variable scanning. --- # April 15, 2024 ## 0.18.3 **`(fix):`** Path parameters are now applied in the correct order. --- # April 2, 2024 ## 0.18.2 **`(fix):`** Custom authorization header schemes had their values overridden by request options, which required using the generated request option at every call-site. --- # March 12, 2024 ## 0.18.1 **`(fix):`** Go snippets correctly handle unknown examples. --- # March 4, 2024 ## 0.18.0 **`(feat):`** Add support for simpler unions, which is configurable with `union: v1` (if omitted, the default `v0` version will be used). **`(feat):`** Add support for multiple files in upload endpoints. --- # February 26, 2024 ## 0.17.0 **`(internal):`** No changes since previous release candidate. --- # February 23, 2024 ## 0.17.0-rc1 **`(fix):`** Snippets for aliases to optional primitive values. --- # February 21, 2024 ## 0.17.0-rc0 **`(fix):`** Package documentation is now generated into the correct package's `doc.go`. **`(feat):`** Add support for generated endpoint snippets. --- # February 12, 2024 ## 0.16.0 **`(feat):`** The generator now supports whitelabelling. --- # February 9, 2024 ## 0.15.0 **`(feat):`** Enforce RFC3339 for date\[time] serialization in request bodies. --- # February 7, 2024 ## 0.14.1 **`(fix):`** Query parameter support for optional `time.Time` types. --- # February 6, 2024 ## 0.14.0 **`(feat):`** Add support for `deepObject` query parameters. **`(chore):`** Refactor query parameter serialization with `url` struct tags. --- # January 31, 2024 ## 0.13.0 **`(feat):`** Add `packageName` generator configuration. **`(feat):`** Add support for `bytes` request bodies wrapped in an in-lined request. ## 0.12.1 **`(fix):`** `text/plain` response handling. --- # January 30, 2024 ## 0.12.0 **`(feat):`** Add support for `bytes` request bodies with `Content-Type` set to `application/octet-stream`. --- # January 29, 2024 ## 0.11.0 **`(feat):`** Add automatic retry with exponential backoff. --- # January 25, 2024 ## 0.10.0 **`(feat):`** Refactor `ClientOption` as `RequestOption`. **`(feat):`** Add `includeLegacyClientOptions` generator configuration. **`(feat):`** Support idempotency headers as a special `RequestOption` only available on idempotent endpoints. **`(fix):`** Placement of path parameter documentation. **`(fix):`** Naming collision issue for undiscriminated unions that define more than one literal. --- # January 10, 2024 ## 0.9.4 **`(fix):`** File upload requests that specify query parameters. --- # December 4, 2023 ## 0.9.3 **`(fix):`** Optional query parameter dereferencing issue. --- # November 30, 2023 ## 0.9.2 **`(fix):`** Append version suffix for modules tagged with major versions greater than `1.X.X`. --- # November 8, 2023 ## 0.9.1 **`(fix):`** Support boolean literals. **`(fix):`** Union subtypes with no properties are now go 1.13 compatible. --- # October 31, 2023 ## 0.9.0 **`(feat):`** Add support for streaming endpoints. **`(feat):`** Add support for non-primitive file upload properties. **`(chore):`** Refactor `core.DoRequest` with `core.Caller` abstraction. **`(chore):`** Update pinned dependencies in generated `go.mod`. --- # Java quickstart > Learn how to generate a Java SDK with Fern. Step-by-step guide to configure generators.yml, run fern generate, and create client libraries. Generate a Java SDK by following the instructions on this page. This page assumes that you have: * An initialized `fern` folder. See [Set up the `fern` folder](/sdks/overview/quickstart). * A GitHub repository for your SDK. See [Project Structure](/sdks/overview/project-structure). ### Pass `fern check` Run `fern check` to ensure that your API definition is valid. If there are any errors, fix them before proceeding. If you're using an OpenAPI Specification, check out all of our [supported extensions](/learn/api-definition/openapi/extensions). ### Add the SDK generator Run the following command to add the Java SDK generator to `generators.yml`: ```bash fern add fern-java-sdk --group java-sdk ``` `java-sdk` is the name of the `generators.yml` group that configures your Java SDK's output location and other metadata. You can customize this group name to differentiate between multiple SDKs across different languages (e.g., `ruby-sdk`, etc) in your organization. This command adds the following `group` to `generators.yml`: ```yaml title="generators.yml" java-sdk: # group name generators: - name: fernapi/fern-java-sdk version: 3.34.7 output: location: local-file-system path: ../sdks/java ``` ### Generate the SDK Run the following command to generate your SDK: ```bash fern generate --group java-sdk ``` If you have multiple APIs, use the [`--api` flag](/cli-api-reference/cli-reference/commands#api) to specify the API you want to generate: ```bash fern generate --group java-sdk --api your-api-name ``` This creates a `sdks` folder in your current directory. The resulting folder structure looks like this: --- # Java configuration > Configure your Java SDK generator with custom client names, package prefixes, builder patterns, and Maven publishing options for Fern. You can customize the behavior of the Java SDK generator in `generators.yml`: ```yaml {7-9} title="generators.yml" groups: java-sdk: generators: - name: fernapi/fern-java-sdk version: 3.34.7 config: client-class-name: YourApiClient ``` Customizes the name of the base API exception class that all API-specific exceptions will extend. This allows you to define a custom base exception class name for better integration with your existing error handling patterns. Specifies the name of the base exception class that all generated exceptions will inherit from. This provides a common parent class for all SDK exceptions, enabling consistent exception handling patterns. The provided string will be used as the client class name. When enabled, generates `OptionalNullable` types for merge patch request fields to distinguish between three states: absent (field not provided), null (field explicitly set to null), and present (field has a non-null value). This enables proper handling of JSON Merge Patch semantics where omitting a field, setting it to null, and providing a value have different meanings. This feature is available only for the [Pro and Enterprise plans](https://buildwithfern.com/pricing). To get started, reach out to [support@buildwithfern.com](mailto:support@buildwithfern.com). Example: ```yaml custom-dependencies: - "implementation com.foo:bar:0.0.0" - "testImplementation com.foo:bar:0.0.0" - "api com.foo:bar:0.0.0" ``` When enabled, disables validation checks in builder patterns for required properties. This removes compile-time checks that ensure all required fields are set before building an object, providing more flexibility but less safety. When enabled, generates extensible builder classes that support customization through inheritance. This allows you to [add custom code](/sdks/generators/java/custom-code#adding-custom-client-configuration) to extend the generated builders with additional functionality. When enabled, generates enum classes that can handle unknown values gracefully. This allows the SDK to process new enum values that may be added to the API without breaking existing client code, improving forward compatibility. When enabled, generates inline types for nested schemas instead of creating separate classes. This results in cleaner type definitions where nested objects are defined within their parent types, reducing the number of generated files. When enabled, generates public constructors for model types. When enabled, generates [mock server (wire) tests](/sdks/deep-dives/testing#mock-server-tests) to verify that the SDK sends and receives HTTP requests as expected. When enabled, generates unknown or untyped properties as structured JSON objects instead of raw Object types. This provides better type safety and easier manipulation of dynamic JSON content while maintaining flexibility for unknown data structures. Controls whether file upload properties are generated as inline request properties instead of separate method parameters. When enabled, file fields become part of the request object rather than being passed as individual function arguments. When enabled, path parameters are included as properties in the request object instead of being passed as separate method parameters. This creates a more unified request structure where all parameters are grouped together. Controls Jackson's JSON serialization behavior for optional fields. Use 'non-empty' to exclude null and empty values, or 'non-absent' to only exclude null values while preserving empty collections and strings. Determines the organization of generated Java packages. Choose 'nested' for a hierarchical package structure that mirrors your API organization, or 'flat' for a simpler structure with fewer nested packages. By default, the generated SDK will use the package prefix `com.{orgName}.api`, where `{orgName}` is your Fern organization name (defined in `fern.config.json`). To override this, you can specify the `package-prefix` field in your `generators.yml` configuration. ``` config: package-prefix: my.new.package ``` Publish target for Maven packages. Use `central` for Maven Central Portal or `ossrh` for legacy Nexus Repository. When enabled, generates `java.time.LocalDate` instead of `String` for Fern date types. This provides better type safety and enables compile-time validation for date values, while maintaining the same string wire format for API communication. When enabled, generates wrapper types for each alias to increase type-safety. For example, if you have an alias `ResourceId: string` then if this is true, the generator will generate a `ResourceId.java` file. If false, it will just treat it as `java.util.String`. ## Publishing metadata configuration options If you want to customize how your publishing metadata looks in your `build.gradle` file, update the `metadata` field in `generators.yml`. ```yml {4-9} generators: - name: fernapi/fern-java-sdk version: 2.7.0 metadata: author: "AuthorName" email: "example@email.com" package-description: "Your site description here" reference-url: "https://example.com" license: "MIT" ``` Specifies the author name that will appear in the generated package metadata and build configuration files. Sets the contact email address for the package author that will be included in the generated package metadata. Defines the software license for the generated SDK. Choose from standard licenses like 'MIT' or 'Apache-2.0', or specify a custom license name. Provides a description of the SDK package that will appear in package metadata and documentation. This helps users understand what the SDK is for and its purpose. Sets the reference URL (typically the API documentation or project website) that will be included in the package metadata for users to find additional information. --- # Publishing to Maven Central > Learn how to publish your Fern-generated Java SDK to Maven Central. Complete guide covering authentication, GPG signatures, and automated releases. Publish your public-facing Fern Java SDK to the [Maven Central registry](https://central.sonatype.com/). After following the steps on this page, you'll have a versioned package published on Maven Central. This page assumes that you have: * An initialized `fern` folder. See [Set up the `fern` folder](/sdks/overview/quickstart). * A GitHub repository for your Java SDK. See [Project structure](/sdks/overview/project-structure). * A Java generator group in `generators.yml`. See [Java Quickstart](quickstart#add-the-sdk-generator). ## Configure Maven Central publication You'll need to update your `generators.yml` file to configure the output location, target repository, and publishing mode. Your `generators.yml` [should live in your source repository](/sdks/overview/project-structure) (or on your local machine), not the repository that contains your Java SDK code. In the `group` for your Java SDK, change the output location in `generators.yml` from `local-file-system` (the default) to `maven` to indicate that Fern should publish your package directly to the Maven Central registry. Then, add `publish-to: central` to indicate that the publish target is the new Maven Central Portal (Sonatype). To publish to the legacy Nexus Repository, use `publish-to: ossrh`. ```yaml {6-9} title="generators.yml" groups: java-sdk: generators: - name: fernapi/fern-java-sdk version: 3.34.7 output: location: maven config: publish-to: central ``` Add the path to the GitHub repository containing your Java SDK: ```yaml {10-11} title="generators.yml" groups: java-sdk: generators: - name: fernapi/fern-java-sdk version: 3.34.7 output: location: maven config: publish-to: central github: repository: your-org/company-java ``` Optionally set the mode to control how Fern handles SDK publishing: * `mode: release` (default): Fern generates code, commits to main, and tags a release automatically * `mode: pull-request`: Fern generates code and creates a PR for you to review before release * `mode: push`: Fern generates code and pushes to a branch you specify for you to review before release You can also configure other settings, like the reviewers or license. Refer to the [full `github` (`generators.yml`) reference](/sdks/reference/generators-yml#github) for more information. ```yaml title="generators.yml" {12-13} groups: java-sdk: generators: - name: fernapi/fern-java-sdk version: 3.34.7 output: location: maven config: publish-to: central github: repository: your-org/company-java mode: push branch: your-branch-name # Required for mode: push ``` ## Set up Maven Central publishing authentication Log into [Maven Central](https://central.sonatype.com/) or create a new account. 1. Click on your username, then select **View Namespaces**. Click **Register New Namespace**. 2. Enter your company website or GitHub account in reverse domain name format and go through the verification process. Add the namespace you just verified in Maven Central to the `coordinate` field. This specifies how your Java SDK will be published and referenced in the Maven Central respository. ```yaml {8} title="generators.yml" groups: java-sdk: generators: - name: fernapi/fern-java-sdk version: 3.34.7 output: location: maven coordinate: com.company:sdk-name # groupId:artifactId config: publish-to: central github: repository: your-org/company-java ``` 1. Back in Maven Central, click on your username, then select **View Account** 2. Click on **Generate User Token**, then click **Ok** to confirm generation. This will invalidate any existing token. Save your username and password tokens – they won’t be displayed after you leave the page. Add `username: ${MAVEN_USERNAME}` and `password: ${MAVEN_PASSWORD}` to `generators.yml` to tell Fern to use the `MAVEN_USERNAME` and `MAVEN_PASSWORD` environment variable for authentication when publishing to the Maven Central registry. ```yaml {9-10} title="generators.yml" groups: java-sdk: generators: - name: fernapi/fern-java-sdk version: 3.34.7 output: location: maven coordinate: com.company:sdk-name username: ${MAVEN_USERNAME} password: ${MAVEN_PASSWORD} config: publish-to: central github: repository: your-org/company-java ``` ## Generate GPG Signature Next, set up code signing credentials by generating or identifying a GPG key ID, password, and secret key. Maven Central requires all artifacts to be digitally signed with PGP/GPG keys. If you don't have gpg installed, you can download the binary from [https://gnupg.org/download/index.html](https://gnupg.org/download/index.html) , or install it via package manager. If you already have a GPG key, you can list your keys: ```sh gpg --list-secret-keys --keyid-format LONG ``` If you don't have a GPG key, you can generate a new one: ```sh gpg --gen-key ``` You'll be prompted to create a new username and passphrase. Export your key so you can store it in an environment variable later on: ```sh gpg --export-secret-keys --armor YOUR_KEY_ID ``` Be sure to replace `YOUR_KEY_ID` with the key ID of the key you want to export. More information is available on [Maven Central's GPG validation page](https://central.sonatype.org/publish/requirements/gpg/) . Add the `keyId`, `password`, and `secretKey` from the previous step to `generators.yml`: ```yaml {11-14} title="generators.yml" groups: java-sdk: generators: - name: fernapi/fern-java-sdk version: 3.34.7 output: location: maven coordinate: com.company:sdk-name username: ${MAVEN_USERNAME} password: ${MAVEN_PASSWORD} signature: keyId: ${MAVEN_SIGNATURE_SECRET_KEY_ID} password: ${MAVEN_SIGNATURE_PASSWORD} secretKey: ${MAVEN_SIGNATURE_SECRET_KEY} config: publish-to: central github: repository: your-org/company-java ``` Finally, upload your key to public key servers so Maven Central can access the signature: ```bash # Upload to multiple key servers gpg --keyserver keyserver.ubuntu.com --send-keys YOUR_KEY_ID gpg --keyserver keys.openpgp.org --send-keys YOUR_KEY_ID gpg --keyserver pgp.mit.edu --send-keys YOUR_KEY_ID ``` ## Publish your SDK Decide how you want to publish your SDK to Maven Central. You can use GitHub workflows for automated releases or publish directly via the CLI. Set up a release workflow via [GitHub Actions](https://docs.github.com/en/actions/get-started/quickstart) so you can trigger new SDK releases directly from your source repository. Open your source repository in GitHub. Click on the **Settings** tab. Then, under the **Security** section, open **Secrets and variables** > **Actions**. You can also use the url `https://github.com//settings/secrets/actions`. 1. Select **New repository secret**. 2. Name your secret `FERN_TOKEN`. 3. Add your Fern token. If you don't already have one, generate one by running `fern token`. By default, the `fern_token` is generated for the organization listed in `fern.config.json`. 4. Click **Add secret**. Add the following repository secrets by selecting **New repository secret** for each: 1. `MAVEN_USERNAME` - Your Maven Central username 2. `MAVEN_PASSWORD` - Your Maven Central password 3. `MAVEN_SIGNATURE_SECRET_KEY_ID` - Your GPG key ID 4. `MAVEN_SIGNATURE_PASSWORD` - Your GPG passphrase 5. `MAVEN_SIGNATURE_SECRET_KEY` - Your GPG secret key Set up a CI workflow that you can manually trigger from the GitHub UI. In your repository, navigate to **Actions**. Select **New workflow**, then **Set up workflow yourself**. Add a workflow that's similar to this: ```yaml title=".github/workflows/publish.yml" maxLines=0 name: Publish Java SDK on: workflow_dispatch: inputs: version: description: "The version of the Java SDK that you would like to release" required: true type: string jobs: release: runs-on: ubuntu-latest steps: - name: Checkout repo uses: actions/checkout@v4 - name: Install Fern CLI run: npm install -g fern-api - name: Release Java SDK env: FERN_TOKEN: ${{ secrets.FERN_TOKEN }} MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} MAVEN_SIGNATURE_SECRET_KEY_ID: ${{ secrets.MAVEN_SIGNATURE_SECRET_KEY_ID }} MAVEN_SIGNATURE_PASSWORD: ${{ secrets.MAVEN_SIGNATURE_PASSWORD }} MAVEN_SIGNATURE_SECRET_KEY: ${{ secrets.MAVEN_SIGNATURE_SECRET_KEY }} run: | fern generate --group java-sdk --version ${{ inputs.version }} --log-level debug ``` You can alternatively configure your workflow to execute `on: [push]`. Navigate to the **Actions** tab, select the workflow you just created, specify a version number, and click **Run workflow**. This regenerates your SDK. The rest of the release process depends on your chosen mode: * **Release mode (default):** If you didn't specify a `mode` or set `mode: release`, no further action is required. Fern automatically tags the new release with your specified version number and initiates the publishing workflow in your SDK repository. * **Pull request or push mode:** If you set `mode: pull-request` or `mode: push`, Fern creates a pull request or pushes to a branch respectively. Review and merge the PR (`pull-request`) or branch (`push`), then [tag a new release](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository) to initiate the publishing workflow in your SDK repository. Once the workflow completes, you can view your new release by logging into Maven Central and navigating to **View Deployments**. Set the Maven Central environment variables on your local machine: ```bash export MAVEN_USERNAME=your-maven-username export MAVEN_PASSWORD=your-maven-password export MAVEN_SIGNATURE_SECRET_KEY_ID=your-gpg-key-id export MAVEN_SIGNATURE_PASSWORD=your-gpg-passphrase export MAVEN_SIGNATURE_SECRET_KEY=your-gpg-secret-key ``` Regenerate your SDK, specifying the version: ```bash fern generate --group java-sdk --version ``` The rest of the release process depends on your chosen mode: * **Release mode (default):** If you didn't specify a `mode` or set `mode: release`, no further action is required. Fern automatically tags the new release with your specified version number and initiates the publishing workflow in your SDK repository. * **Pull request or push mode:** If you set `mode: pull-request` or `mode: push`, Fern creates a pull request or pushes to a branch respectively. Review and merge the PR (`pull-request`) or branch (`push`), then [tag a new release](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository) to initiate the publishing workflow in your SDK repository. Once the command completes, you can view your new release by logging into Maven Central and navigating to **View Deployments**. --- # Adding custom code > Augment your Java SDK with custom utilities This page covers how to add custom logic, methods, and dependencies to your TypeScript SDK. Before getting started, [read about how Fern SDKs use custom code and learn about the `.fernignore` file](/sdks/overview/custom-code) . ## Adding custom logic To get started adding custom code: ### Create a new file and add your custom logic ```java title="src/main/java//Helper.java" package com.example.helper; public class Helper { public static void myHelper() { System.out.println("Hello World!"); } } ``` ### Add your file to `.fernignore` ```yaml {3} title=".fernignore" # Specify files that shouldn't be modified by Fern src/main/java//Helper.java ``` ### Consume the helper Now your users can consume the helper function by importing it from the SDK. ```java import com.example.helper.Helper; public class Main { public static void main(String[] args) { Helper.myHelper(); } } ``` ## Adding custom SDK methods Fern also allows you to add custom methods to the SDK itself (e.g. `client.my_method()` ) by inheriting the Fern generated client and then extending it. ### Update `generators.yml` configuration Name your Fern-generated client something like `BaseClient` to reflect that this client will be extended. ```yml {4} title="generators.yml" - name: fernapi/fern-java-sdk version: "..." config: client-class-name: BaseClient ``` ### Import and extend the generated client First, import the Fern generated base client and extend it. Then, add whatever methods you want. ```java title="src/main/java/com/example/MyClient.java" package com.example; import com.example.client.BaseClient; public class MyClient extends BaseClient { // extend the Fern generated client public void myHelper() { System.out.println("Hello World!"); } } ``` ### Update `.fernignore` Add the `MyClient.java` to `.fernignore`. ```diff title=".fernignore" + src/main/java/com/example/MyClient.java ``` ### Consume the method Now your users can consume the helper function by importing it from the SDK. ```java client.myHelper(); ``` ## Adding custom client configuration The Java SDK generator supports builder extensibility through an opt-in self-type pattern. When enabled via the `enable-extensible-builders` flag, generated builders can be extended while maintaining type safety during method chaining. Common use cases include: * **Dynamic URL construction**: Replace placeholders with runtime values (e.g., `https://api.${TENANT}.example.com`) * **Custom authentication**: Implement complex auth flows beyond basic token authentication * **Request transformation**: Add custom headers or modify requests globally * **Multi-tenant support**: Add tenant-specific configuration and headers ### Enable extensible builders Add the flag to your `generators.yml`: ```yaml {7} title="generators.yml" groups: local: generators: - name: fernapi/fern-java-sdk version: 2.39.6 config: enable-extensible-builders: true ``` ### How it works Generated builders use the self-type pattern for type-safe method chaining: ```java public abstract class BaseClientBuilder> { protected abstract T self(); public T token(String token) { return self(); // Returns your custom type, not BaseClientBuilder } } ``` ### Create a custom builder Extend the generated builder: ```java title="src/main/java/com/example/CustomApiBuilder.java" public class CustomApiBuilder extends BaseClientBuilder { @Override protected CustomApiBuilder self() { return this; } @Override protected void setEnvironment(ClientOptions.Builder builder) { // Customize environment URL String url = this.environment.getUrl(); String expandedUrl = expandEnvironmentVariables(url); builder.environment(Environment.custom(expandedUrl)); } @Override protected void setAdditional(ClientOptions.Builder builder) { // Add custom headers builder.addHeader("X-Request-ID", () -> UUID.randomUUID().toString()); } } ``` ### Use your custom builder ```java BaseClient client = new CustomApiBuilder() .token("my-token") // returns CustomApiBuilder .tenantId("tenant-123") // returns CustomApiBuilder .timeout(30) // returns CustomApiBuilder .build(); client.users().list(); ``` ### Update `.fernignore` Add your custom builder to `.fernignore` so Fern won't overwrite it: ```diff title=".fernignore" + src/main/java/com/example/CustomApiBuilder.java ``` ### Default implementation If you don't need to extend the builder, use the provided `Impl` class: ```java BaseClient client = BaseClientBuilder.Impl() .token("my-token") .timeout(30) .build(); ``` ### Method reference Each method serves a specific purpose and is only generated when needed: | Method | Purpose | Available When | | ---------------------------- | -------------------------------------------------- | --------------------------- | | `self()` | Returns the concrete builder type for chaining | Always (abstract) | | `setEnvironment(builder)` | Customize environment/URL configuration | Always | | `setAuthentication(builder)` | Modify or add authentication | Only if API has auth | | `setCustomHeaders(builder)` | Add custom headers defined in API spec | Only if API defines headers | | `setVariables(builder)` | Configure API variables | Only if API has variables | | `setHttpClient(builder)` | Customize OkHttp client | Always | | `setTimeouts(builder)` | Modify timeout settings | Always | | `setRetries(builder)` | Modify retry settings | Always | | `setAdditional(builder)` | Final extension point for any custom configuration | Always | | `validateConfiguration()` | Add custom validation logic | Always | ### Common patterns ```java @Override protected void setEnvironment(ClientOptions.Builder builder) { String url = this.environment.getUrl() .replace("/api/", "/tenants/" + tenantId + "/"); builder.environment(Environment.custom(url)); } ``` ```java @Override protected void setAuthentication(ClientOptions.Builder builder) { super.setAuthentication(builder); // Keep existing auth builder.addHeader("Authorization", () -> "Bearer " + tokenProvider.getAccessToken() ); } ``` ```java @Override protected void setEnvironment(ClientOptions.Builder builder) { String url = this.environment.getUrl(); // Replace ${VAR_NAME} with environment variables Pattern pattern = Pattern.compile("\\$\\{([^}]+)\\}"); Matcher matcher = pattern.matcher(url); StringBuffer result = new StringBuffer(); while (matcher.find()) { String envVar = System.getenv(matcher.group(1)); matcher.appendReplacement(result, envVar != null ? envVar : matcher.group(0)); } matcher.appendTail(result); builder.environment(Environment.custom(result.toString())); } ``` ```java @Override protected void setAdditional(ClientOptions.Builder builder) { builder.addHeader("X-Request-ID", () -> UUID.randomUUID().toString()); builder.addHeader("X-Tenant-ID", this.tenantId); if (FeatureFlags.isEnabled("new-feature")) { builder.addHeader("X-Feature-Flag", "new-feature"); } } ``` ### Requirements * **Fern Java SDK version**: 2.39.6 or later * **Configuration**: `enable-extensible-builders: true` in `generators.yml` ## Adding custom dependencies This feature is available only for the [Pro and Enterprise plans](https://buildwithfern.com/pricing). To get started, reach out to [support@buildwithfern.com](mailto:support@buildwithfern.com). To add packages that your custom code requires, update your `generators.yml`. ```yaml {4-7} title="generators.yml" - name: fernapi/fern-java-sdk version: "..." config: custom-dependencies: - org.apache.commons:commons-lang3:3.12.0 - org.slf4j:slf4j-api:2.0.7 ``` --- # February 2, 2026 ## 3.34.7 **`(fix):`** Add pre-flight check for git availability when using self-hosted GitHub mode. The CLI now verifies git is installed before attempting to clone, providing a clear error message if git is not found. Also adds improved error logging with diagnostics when git clone fails. --- # January 29, 2026 ## 3.34.6 **`(fix):`** Fix wire test generation importing types from the wrong package when multiple services have endpoints with the same HTTP method and path. The generator now uses endpoint IDs to resolve the correct endpoint instead of relying solely on method and path matching. --- # January 26, 2026 ## 3.34.5 **`(fix):`** Fix streaming endpoints incorrectly setting `Accept: application/json` header. Streaming endpoints (SSE, NDJSON, etc.) now omit the Accept header entirely, allowing the server to negotiate the appropriate streaming format. ## 3.34.4 **`(fix):`** Fix Java SDK compilation error when a path parameter is named `key`. The lambda variable in `requestOptions.getQueryParameters().forEach((key, value) -> {...})` was shadowing the path parameter, causing a "variable key is already defined" compilation error. Lambda variables are now prefixed with underscore to avoid conflicts. --- # January 23, 2026 ## 3.34.3 **`(fix):`** Fix Java SDK generation failure when an environment name is a Java reserved keyword (e.g., "default") for multi-environment APIs. ## 3.34.2 **`(fix):`** Change wire tests to use resource files for JSON strings above a certain length to prevent undue stress to :spotlessJava and cut down on code duplication. --- # January 22, 2026 ## 3.34.1 **`(fix):`** Fix `output-directory` config option to also apply to test files. When using `source-root` mode, test files are now written directly to the output path instead of always using `src/test/java/`. --- # January 21, 2026 ## 3.34.0 **`(feat):`** Add `output-directory` config option to control where Java files are written during local generation. * `project-root` (default): Files written to `/src/main/java/` (current behavior) * `source-root`: Files written directly to `/` (pre-v3.8.2 behavior for embedding SDKs into existing projects) This allows customers embedding SDKs into existing projects to avoid double `src/main/java` paths. ## 3.33.2 **`(chore):`** Re-publish to verify Docker Hub and generator registry sync. ## 3.33.1 **`(fix):`** Fix compilation error in generated InputStream overloads for file upload endpoints. The `requestOptions.getQueryParameters()` code block is now only emitted in methods that have `RequestOptions` as a parameter. --- # January 20, 2026 ## 3.33.0 **`(feat):`** Generate body-only method overloads for endpoints with required body and optional headers/query params. This prevents breaking changes when optional headers or query params are added to existing endpoints. ## 3.32.1 **`(fix):`** Update container to fix CVE-2026-23745 (node-tar path traversal via hardlinks/symlinks) and CVE-2025-66293 (libpng out-of-bounds read). Patches npm's bundled tar to 7.5.3 and updates libpng16-16 to the latest available version. --- # January 15, 2026 ## 3.32.0 **`(feat):`** Add endpoint-level security support with routing auth providers. APIs can now define different authentication requirements per endpoint using the ENDPOINT\_SECURITY auth mode. The SDK generates individual auth providers (Bearer, Basic, ApiKey, OAuth, InferredAuth) and a RoutingAuthProvider that routes requests to the appropriate provider based on each endpoint's security requirements. Supports OR (any of) and AND (all of) auth requirement combinations. To enable, add `auth: endpoint-security: {}` to your api.yml and define per-endpoint auth in your service definitions using the `auth` field on each endpoint. ## 3.31.0 **`(feat):`** Add `additionalQueryParameters` support to `RequestOptions`, allowing users to add query parameters to API requests at runtime. Query parameters added via RequestOptions override any request-defined parameters with the same key. This mirrors the existing `addHeader` pattern. Usage example: ```java client.endpoint( Request.builder().build(), RequestOptions.builder() .addQueryParameter("key", "value") .build() ); ``` ## 3.30.0 **`(feat):`** Add `enable-gradle-profiling` configuration option for profiling Gradle commands during generation. ## 3.29.2 **`(fix):`** Add `notify`, `notifyAll`, and `wait` to reserved method names to prevent generated SDK methods from conflicting with final methods in Java's Object class. This fixes compilation errors when an API has a subpackage named "notify" (e.g., Twilio's Notify API). ## 3.29.1 **`(fix):`** Fix `_Builder` class to support all builder methods (url, timeout, environment, maxRetries, httpClient, addHeader) so method chaining works in any order. This allows customers upgrading from 3.18.x who wrote `builder().url().token()` to continue working without compile errors. Configuration values set on `_Builder` are now properly passed through to `_TokenAuth` and `_CredentialsAuth` when `token()` or `credentials()` is called. --- # January 14, 2026 ## 3.29.0 **`(feat):`** Add backward-compatible `builder()` method for OAuth client credentials authentication. This restores support for the classic builder pattern `Client.builder().token("...")` and `Client.builder().credentials("...", "...")` alongside the existing `withToken()` and `withCredentials()` shortcuts. This prevents breaking changes for customers who upgraded. --- # January 13, 2026 ## 3.28.2 **`(chore):`** Update Dockerfile to use the latest generator-cli with improve reference.md generation. ## 3.28.1 **`(fix):`** Update libtasn1-6 and gnupg packages in container to fix CVE-2021-46848, CVE-2025-13151, CVE-2025-68973. --- # January 12, 2026 ## 3.28.0 **`(chore):`** Upgrade IR version to 63. --- # January 6, 2026 ## 3.27.6 **`(feat):`** Generate overloads without request wrapper when all query parameters are optional. This prevents compile breaks when optional query parameters are added to endpoints. For example, `getLatestInsurance(String userId)` and `getLatestInsurance(String userId, RequestOptions requestOptions)` overloads are now generated in addition to the request wrapper variants. --- # January 5, 2026 ## 3.27.5-rc4 **`(fix):`** Add fallback SDK name generation for X-Fern-SDK-Name header when no explicit maven config is provided. This ensures local generation matches remote generation for GitHub output mode. --- # December 24, 2025 ## 3.27.5-rc3 **`(fix):`** Retry Publishing of rc2 --- # December 23, 2025 ## 3.27.5-rc2 **`(fix):`** Install fast-content-type-parse dependency required by @octokit/request\@10.0.7 CVE patch. ## 3.27.5-rc1 **`(chore):`** Add debug logging to generator agent methods to help diagnose issues with README and reference generation. ## 3.27.5-rc0 **`(chore):`** Skip installation of generator-cli in Java V2 generator as it is already installed in the base image. --- # December 18, 2025 ## 3.27.4 **`(fix):`** Fix OAuth client credentials flow to include custom headers, timeouts, and retries in token requests by using ClientOptions.Builder.from() pattern. ## 3.27.3 **`(fix):`** Fix streaming endpoint return types to use Iterable instead of Optional, fix missing ArrayList import for empty list literals, and fix OAuth wire tests to use withCredentials() pattern. ## 3.27.2 **`(chore):`** Support configurable Node.js and Java V2 executable paths via NODE\_PATH and JAVA\_V2\_PATH environment variables for local seed testing. ## 3.27.1 **`(chore):`** Add sdkVersion as a top-level field in the generated metadata.json file. --- # December 17, 2025 ## 3.27.0 **`(feat):`** Add `gradle-central-dependency-management` configuration option (boolean, default false). When enabled, this skips generating the `repositories` block in `build.gradle` files, allowing `dependencyResolutionManagement` in `settings.gradle` with `RepositoriesMode.FAIL_ON_PROJECT_REPOS` to work correctly. This should be used in conjunction with `gradle-plugin-management` when configuring central repository management on enterprise networks. Configuration example: ```yaml config: gradle-central-dependency-management: true gradle-plugin-management: | pluginManagement { repositories { maven { url 'https://internal-artifactory.example.com/gradle-plugins/' } } } dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { maven { url 'https://internal-artifactory.example.com/maven-releases/' } } } ``` ## 3.26.0 **`(feat):`** Add `gradle-plugin-management` configuration option to inject custom plugin management and dependency resolution configuration into `settings.gradle`. This enables SDK generation on enterprise networks that cannot access the Gradle Plugin Portal (`plugins.gradle.org`) by configuring internal Artifactory/Nexus repositories for plugin resolution. Configuration example: ```yaml config: gradle-plugin-management: | pluginManagement { repositories { maven { url 'https://internal-artifactory.example.com/gradle-plugins/' } } } dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { maven { url 'https://internal-artifactory.example.com/maven-releases/' } } } ``` **`(fix):`** Fix `gradle-distribution-url` override in Java V2 generator to properly create the `gradle/wrapper` directory before writing `gradle-wrapper.properties`. ## 3.25.1 **`(fix):`** Fix form-urlencoded request body handling to properly serialize request objects using Jackson's convertValue, preserving wire names from @JsonProperty annotations. --- # December 16, 2025 ## 3.25.0 **`(feat):`** Add `gradle-distribution-url` configuration option to allow overriding the Gradle wrapper distribution URL. This enables SDK generation on enterprise networks that cannot access `services.gradle.org` by pointing to an internal Gradle distribution mirror. Configuration example: ```yaml config: gradle-distribution-url: https://internal-mirror.example.com/gradle/gradle-8.14.3-bin.zip ``` ## 3.24.5 **`(fix):`** Fix OAuth token handling for optional expires\_in field with default fallback, and skip literal properties in OAuth request building. ## 3.24.4 **`(fix):`** Mitigate OutOfMemoryError when generating SDKs for large specs. (Specifically, the IR preprocessing preprocessing step now modifies the JSON tree in-place and avoids calling `.deepCopy()`.) ## 3.24.3 **`(fix):`** Update libpng16-16 in container to fix CVE-2025-64720, CVE-2025-65018, CVE-2025-64505, CVE-2025-64506. --- # December 15, 2025 ## 3.24.2 **`(fix):`** Pass full `ClientOptions` instead of just `httpClient()` to custom pagination `create()` method. This gives custom pager implementations access to all client configuration including base URL, headers, and other options needed for making subsequent pagination requests. --- # December 11, 2025 ## 3.24.1 **`(fix):`** Fix Jackson deserialization conflict when a property starts with `with` (e.g., `withLabel`) and another property matches the suffix (e.g., `label`). --- # December 9, 2025 ## 3.24.0 **`(feat):`** Add support for configuring the default timeout via `default-timeout-in-seconds` in generators.yml. Previously, the default timeout was hardcoded to 60 seconds. Now you can customize it: Configuration example: ```yaml config: default-timeout-in-seconds: 120 ``` ## 3.23.4 **`(chore):`** OAuth token override is now always enabled for APIs with OAuth client credentials authentication. The `oauth-token-override` config flag has been removed - SDK users can always choose between providing a pre-generated bearer token directly or using the OAuth client credentials flow. Generated usage: ```java // Option 1: Direct bearer token (bypass OAuth flow) SeedApiClient client = SeedApiClient.withToken("my-pre-generated-bearer-token") .url("https://api.example.com") .build(); // Option 2: OAuth client credentials flow (automatic token management) SeedApiClient client = SeedApiClient.withCredentials("your-client-id", "your-client-secret") .url("https://api.example.com") .build(); ``` --- # December 8, 2025 ## 3.23.3 **`(fix):`** Fix OptionalNullable query parameters to correctly apply .orElse(default) for parameters with default values. Previously, only java.util.Optional was recognized for default value handling, causing OptionalNullable parameters to be passed directly without unwrapping. Now both Optional and OptionalNullable types are handled correctly: parameters with defaults use .orElse(default), and parameters without defaults use appropriate presence checks (!isAbsent() for OptionalNullable, isPresent() for Optional). ## 3.23.2 **`(fix):`** Revert OAuth staged builder compatibility changes. --- # December 6, 2025 ## 3.23.1 **`(fix):`** Fix duplicate case label compilation errors when multiple error types map to the same HTTP status code. The generator now deduplicates errors by status code, keeping the first error declaration for each code. This prevents Java compilation errors in generated switch statements. --- # December 5, 2025 ## 3.23.0 **`(feat):`** Add OAuth token override support with compile-time safe staged builder pattern. When `oauth-token-override: true` is configured, SDK users can choose between the OAuth client credentials flow or providing a pre-generated bearer token directly. Configuration example: ```yaml config: oauth-token-override: true ``` Generated usage: ```java // Option 1: Direct bearer token (bypass OAuth flow) SeedApiClient client = SeedApiClient.withToken("my-pre-generated-bearer-token") .url("https://api.example.com") .build(); // Option 2: OAuth client credentials flow (automatic token management) SeedApiClient client = SeedApiClient.withCredentials("your-client-id", "your-client-secret") .url("https://api.example.com") .build(); ``` ## 3.22.0 **`(feat):`** Add support for inferred authentication schemes. Inferred auth allows SDKs to automatically fetch tokens from custom (non-OAuth) token endpoints using `scheme: bearer` with `get-token` configuration. The generated `InferredAuthTokenSupplier` class handles token caching and automatic refresh with a 2-minute buffer before expiry. Configuration example: ```yaml auth: scheme: bearer get-token: endpoint: POST auth.retrieveToken ``` Generated usage: ```java SeedApiClient client = SeedApiClient.builder() .apiKey("your-api-key") .build(); // Token is automatically fetched and refreshed as needed ``` --- # December 4, 2025 ## 3.21.1 **`(fix):`** Fix header parameters with `x-fern-parameter-name` to use the correct HTTP header name (wire value) instead of the SDK parameter name. ## 3.21.0 **`(fix):`** Remove unused kotlin-stdlib from Gradle base image to address CVE-2020-29582 in container. --- # December 2, 2025 ## 3.20.2 **`(fix):`** Improve generator logging by removing verbose "java v2 generator" status messages and adding per-file logging. Each generated file is now logged individually, matching the C# generator pattern. --- # November 27, 2025 ## 3.20.1 **`(fix):`** Fix StreamTest generator to use Java 8 compatible constructs. Replaced List.of() and Map.of() (Java 9+) with Arrays.asList() and a createMap() helper method using HashMap. --- # November 26, 2025 ## 3.20.0 **`(fix):`** Update vulnerable dependencies. --- # November 25, 2025 ## 3.19.0 **`(feat):`** Add wire test support for OAuth APIs and multi-URL environments. Wire tests now: * Properly mock OAuth token endpoints with per-test token enqueuing * Use `.clientId()/.clientSecret()` for OAuth-authenticated APIs * Support custom OAuth headers (e.g., `apiKey`) required by token endpoints * Configure `Environment.custom()` builder for multi-URL environment APIs * Handle flexible JSON comparison allowing extra default fields in responses ## 3.18.13 **`(fix):`** Skip wire test generation for OAuth and multi-URL environment APIs temporarily. ## 3.18.12 **`(fix):`** Fix Java dynamic snippets for query parameters with `allow-multiple: true` and optional types. Snippets now generate `List` instead of `List>`, which matches the SDK builder's convenience overload. ## 3.18.11 **`(fix):`** Fix dynamic snippets to preserve schema parameter order for staged builders. --- # November 24, 2025 ## 3.18.10 **`(fix):`** Fix Java dynamic snippets when use-local-date-for-dates is enabled. Snippets for date fields now generate LocalDate.parse(...) instead of string literals, matching SDKs configured to use LocalDate for dates. This fixes compilation errors in generated dynamic snippets for Java v2 when the use-local-date-for-dates flag is true. ## 3.18.9 **`(fix):`** Fix wire test generation to use OptionalNullable when collapse-optional-nullable is enabled. Wire tests now correctly generate OptionalNullable.absent() and OptionalNullable.of() instead of Optional.empty() and Optional.of() for optional request bodies and method arguments when collapse-optional-nullable: true is configured. This includes support for nested optional/nullable types which collapse into a single `OptionalNullable`. --- # November 23, 2025 ## 3.18.8 **`(fix):`** Skip InputStream overload generation for file upload endpoints with inline path parameters. This prevents compilation errors where InputStream methods would reference non-existent request parameters when path parameters are inlined. --- # November 22, 2025 ## 3.18.7 **`(fix):`** Skip InputStream overload generation for file upload endpoints with query parameters. This prevents compilation errors where InputStream methods would reference non-existent request parameters when accessing query parameters. ## 3.18.6 **`(fix):`** Fix compilation errors in raw clients when inlinePathParameters is enabled. Raw client methods now correctly use path parameters directly instead of attempting to access non-existent request objects. --- # November 21, 2025 ## 3.18.5 **`(fix):`** Remove using generator-cli to push to GitHub for self-hosted SDKs; this is now handled in the local workspace runner. --- # November 20, 2025 ## 3.18.4 **`(fix):`** Fix missing @JsonInclude header on certain instances of `OptionalNullable<>`. ## 3.18.3 **`(fix):`** Fix OptionalNullable compilation errors when collapse-optional-nullable is enabled. Corrected type witness syntax to generate `OptionalNullable.absent()` and prevented double-wrapping of OptionalNullable types. ## 3.18.2 **`(fix):`** Fix bugs in 3.17.0's addition of InputStream-based method overloads. ## 3.18.1 **`(fix):`** Fix bytes response support and snippet generation. Bytes responses now return `byte[]` instead of throwing exceptions. Empty bytes request bodies in snippets now generate valid default arguments. --- # November 19, 2025 ## 3.18.0 **`(feat):`** Add support for custom bidirectional pagination. APIs using custom pagination (e.g., HATEOAS links) can configure a custom pager name and receive skeleton classes with bidirectional navigation methods (`nextPage()`, `previousPage()`, `hasNext()`, `hasPrevious()`). Configuration: ```yaml customConfig: custom-pager-name: MyCustomPaginator ``` ## 3.17.1 **`(chore):`** Bump generator CLI version to publish new Docker image. --- # November 18, 2025 ## 3.17.0 **`(feat):`** Add InputStream-based method overloads for file upload endpoints. For each single-file upload endpoint, the generator now creates 4 additional overloads that accept InputStream + filename instead of File objects: * method(InputStream stream, String filename) * method(InputStream stream, String filename, MediaType mediaType) * method(InputStream stream, String filename, RequestOptions requestOptions) * method(InputStream stream, String filename, MediaType mediaType, RequestOptions requestOptions) This enables streaming file uploads without requiring files to be written to disk first. The implementation uses the existing FileStream wrapper class and InputStreamRequestBody for OkHttp integration. Note: Okio automatically closes the stream after upload, but users should still use try-with-resources for proper resource management. ## 3.16.1 **`(fix):`** Fix OAuth client credentials token supplier to support custom properties and headers. OAuth token endpoints can now include custom headers (e.g., x-api-key) and custom body properties (e.g., entity\_id) in addition to standard OAuth fields (client\_id, client\_secret, scopes). This enables authentication with non-standard OAuth implementations that require additional parameters. --- # November 14, 2025 ## 3.16.0 **`(feat):`** Add opt-in use-local-date-for-dates config flag to generate java.time.LocalDate instead of String for Fern date types. ## 3.15.1 **`(fix):`** Fix SDK generation failures for endpoints with custom pagination. Endpoints using `x-fern-pagination: type: custom` now generate successfully, returning the raw response type without automatic pagination wrappers. --- # November 13, 2025 ## 3.15.0 **`(feat):`** Upgrade dependencies: okhttp 4.12.0 -> 5.2.1, jackson 2.17.2 -> 2.18.2, \[internal use only] mockito 3.11.2 -> 4.11.0. ## 3.14.14 **`(fix):`** Fix streaming method names and request types in wire tests. Wire tests now correctly normalize streaming endpoints to use `.methodStream()` naming pattern and `MethodStreamRequest` types, while non-streaming endpoints use `.method()` and `MethodRequest`. This eliminates "incompatible types" compilation errors where streaming method calls were paired with non-streaming response types. ## 3.14.13 **`(fix):`** Revert unchecked operations warning fix in StreamTest generator due to type inference compilation errors. The previous fix (3.14.0) caused "incompatible types: inference variable T has incompatible equality constraints `Map`,`Map`" errors when compiling generated StreamTest.java files. Restores the original implementation using raw types. ## 3.14.12 **`(fix):`** Fix dynamic snippets compilation errors for literal-typed parameters. Literal-typed parameters (e.g., prompt with literal string value, stream with literal false) are now correctly filtered from builder method calls in generated snippets, as these fields only have hardcoded getters without corresponding setters. This maintains parity with Java v1 behavior where literal fields are excluded from all class builders (both model and request classes). ## 3.14.11 **`(fix):`** Fix jsonEquals helper method not being generated in wire tests. The generator now correctly calls closeTestClass() to emit the jsonEquals helper method that enables numeric equivalence comparison in wire test assertions. --- # November 12, 2025 ## 3.14.10 **`(fix):`** Fix wire test failures for numeric type mismatches and header serialization. Wire tests now use numeric equivalence comparison to handle integer vs double type differences from OpenAPI specs. Headers are no longer incorrectly serialized into JSON request bodies - they now use @JsonIgnore and are sent only as HTTP headers. ## 3.14.9 **`(fix):`** Fix wire test compilation errors when using staged builders with collections. Builder method calls now correctly order required fields before collections like Lists, Sets, and Maps. ## 3.14.8 **`(fix):`** Fix critical wire test generation failures causing build crashes. Implemented service name resolution to handle IR vs Dynamic IR mismatches and added graceful error handling instead of build failures. --- # November 11, 2025 ## 3.14.7 **`(fix):`** Fix inconsistent behavior between local and remote Java generation by ensuring license files are copied and platform headers are populated in all generation scenarios ## 3.14.6 **`(chore):`** Upgrade Gradle wrapper from 7.4.2 to 8.14.3. This update brings Java 24 support, GraalVM Native Image toolchain selection, enhanced test reporting, and build authoring improvements. The bundled Gradle wrapper files now use the latest stable Gradle 8.x release. ## 3.14.5 **`(fix):`** Fix SDK generation failures for OpenAPI specs with nullable container types. The generator now properly handles nullable containers in response parsing and pagination, treating them distinctly from optional containers. Also adds support for literal container detection with improved error diagnostics. This fixes "Unexpected container type" errors that occurred when processing APIs with nullable types or array examples in query parameters. ## 3.14.4 **`(fix):`** Replace gradle wrapper command with resource copy to eliminate internet requests during SDK generation. Gradle wrapper files are now copied from bundled resources instead of being downloaded via `gradle wrapper` command. All `./gradlew` invocations during generation have been removed to avoid network calls and HTTP proxy issues. ## 3.14.3 **`(fix):`** Skip empty object validation in wire tests for optional request bodies. When request bodies are optional(nullable(T)) where T has only optional properties, wire tests now correctly skip `{}` validation when Optional.empty() is passed, matching actual SDK behavior. --- # November 7, 2025 ## 3.14.2 **`(fix):`** Fix double-wrapping of Optional.empty() in request bodies. Wire tests and dynamic snippets now correctly generate Optional.empty() instead of Optional.of(Optional.empty()) for optional request bodies. ## 3.14.1 **`(fix):`** Fix wire test failures by pruning union base properties from expected JSON. The Java generator does not generate base properties for union types, so wire test expectations now exclude these fields to match actual SDK serialization behavior. ## 3.14.0 **`(feat):`** Add support for WebSocket channels with bidirectional communication. Generated WebSocket clients provide automatic reconnection with exponential backoff, strongly-typed message handlers, and message queuing during disconnections. Clients are accessible via factory methods in subpackage clients. ```java // Create WebSocket client with path and query parameters RealtimeWebSocketClient ws = client.realtime().realtimeWebSocket( "session-123", Optional.of("gpt-4"), Optional.of(0) ); // Register handlers and connect ws.onReceive(message -> System.out.println("Received: " + message.getAlpha())); ws.onConnected(() -> System.out.println("Connected!")); ws.connect().get(); // Send typed messages ws.sendSend(SendEvent.builder() .sendText("Hello WebSocket!") .sendParam(42) .build()); ``` --- # November 5, 2025 ## 3.13.0 **`(feat):`** Added Generation Metadata file to output. ## 3.12.1 **`(fix):`** Fix query and header parameters leaking into request body JSON. Only body parameters are now serialized in the request payload. --- # November 4, 2025 ## 3.12.0 **`(feat):`** Add support for API-level path parameters. Path parameters defined at the API level (e.g., `/test/{pathParam}`) are now configurable via the root client builder (`.pathParam(value)`). ## 3.11.7 **`(fix):`** Fix ApiError toString() to display JSON-serialized body instead of hashcode (e.g., `{"title": "Bad Request", ...}` instead of `BadRequestProblems@4ac5ea99`). ## 3.11.6 **`(fix):`** Fix path parameter prefixes (e.g., `v{version}`) being split into separate segments, producing URLs like .../v/1 instead of .../v1. ## 3.11.5 **`(fix):`** Extract error body parsing to ObjectMappers.parseErrorBody() utility method. When servers return XML/HTML errors instead of JSON, the utility gracefully falls back to raw string instead of throwing JsonProcessingException, preserving HTTP status codes and error details. ## 3.11.4 **`(fix):`** The `NullableNonemptyFilter` now correctly handles `OptionalNullable.isAbsent()` to exclude absent fields from JSON serialization in PATCH requests. --- # November 3, 2025 ## 3.11.3 **`(fix):`** Fix `collapse-optional-nullable` config not being applied in download files mode. ## 3.11.2 **`(fix):`** Fix IllegalStateException: closed on error responses. Generated clients were calling responseBody.string() twice (once in success handler, once in error handler), but OkHttp's ResponseBody can only be read once. Now pre-reads response body before success check for JSON/text responses. ## 3.11.1 **`(fix):`** Disable wire tests by default for Java SDKs while issues are being resolved. --- # October 31, 2025 ## 3.11.0 **`(feat):`** Add support for three-state nullable fields in PATCH requests via `collapse-optional-nullable` config. When enabled, optional nullable fields use `OptionalNullable` to distinguish between omitted fields, explicit null values, and actual values. This enables proper PATCH request semantics for APIs that need to differentiate between "not specified" and "set to null". ```yaml customConfig: collapse-optional-nullable: true ``` Generated usage: ```java UpdateRequest.builder() .fieldName(OptionalNullable.absent()) // Omit field .anotherField(OptionalNullable.ofNull()) // Clear field .valueField(OptionalNullable.of("value")) // Set value .build(); ``` --- # October 30, 2025 ## 3.10.5 **`(fix):`** Revert support for three-state nullable fields in PATCH requests introduced in 3.10.0 (PR #10104). Restores `Optional` semantics and removes the `use-nullable-for-optional-fields` config and related `Nullable` handling. --- # October 29, 2025 ## 3.10.4 **`(fix):`** Fix compilation errors when using boolean or long query parameters. ## 3.10.3 **`(fix):`** Use Gradle wrapper for Spotless formatting instead of requiring gradle in PATH. --- # October 28, 2025 ## 3.10.2 **`(fix):`** Fix sync client delegation causing array query parameter compilation errors. Generator was using incorrect class names, breaking delegation and causing inline HTTP generation. ## 3.10.1 **`(fix):`** Fixed nullable annotation generation in builder setters when `use-nullable-annotation` is enabled. Builder setter parameters for nullable fields now correctly use `@org.jetbrains.annotations.Nullable` instead of incorrectly attempting to use the `Nullable` container class as an annotation. Also removed `@Nullable` from path parameters as they are always required in REST APIs. ## 3.10.0 **`(feat):`** Add support for three-state nullable fields in PATCH requests via `use-nullable-for-optional-fields` config. When enabled, optional fields use `Nullable` instead of `Optional` to distinguish between omitted fields, explicit null values, and actual values. ## 3.9.4 **`(chore):`** Documenting `.withRawResponse()` in `README.md`. --- # October 27, 2025 ## 3.9.3 **`(fix):`** Retries now check `Retry-After` and `X-RateLimit-Reset` before defaulting to exponential backoff. --- # October 23, 2025 ## 3.9.2 **`(fix):`** Fix nullable field serialization in PATCH requests with wrapped request bodies. Explicit null values (Nullable.ofNull()) are now correctly serialized as `{"field": null}` instead of being omitted like Nullable.empty(). ## 3.9.1 **`(fix):`** Fix raw client methods to return union types instead of first variant when using response properties (x-fern-sdk-return-value) with discriminated or undiscriminated unions. --- # October 21, 2025 ## 3.9.0 **`(feat):`** Add support for README example style configuration via `exampleStyle` field. When set to "minimal", generated README.md files show streamlined code examples with only required parameters, reducing verbosity for better readability. Defaults to "comprehensive" to maintain backward compatibility. --- # October 20, 2025 ## 3.8.12 **`(fix):`** Fixed wire test generation for application/x-www-form-urlencoded requests. Wire tests now correctly validate form-encoded request bodies instead of attempting to parse them as JSON, eliminating JsonParseException failures in generated test suites. --- # October 16, 2025 ## 3.8.11 **`(fix):`** Fix Java SDK generator to preserve original environment names for multi-URL environments (e.g., "E2E" instead of "E\_2\_E"). Single-URL environments remain unchanged for backward compatibility. --- # October 9, 2025 ## 3.8.10 **`(fix):`** Fixed inconsistent file placement for resource-based core files. All Java files now use standard src/main/java/ structure in local generation mode. --- # October 8, 2025 ## 3.8.9 **`(fix):`** Fixed dynamic snippets incorrectly placing HTTP headers in request builders. Headers now correctly use RequestOptions.builder().addHeader() for body requests. --- # October 5, 2025 ## 3.8.8 **`(fix):`** Fix: Don't run spotlessApply if gradlew doesn't exist. --- # October 4, 2025 ## 3.8.7 **`(fix):`** Fixed spotlessCheck in generated SDKs. --- # October 2, 2025 ## 3.8.6 **`(fix):`** Fixed SSE stream terminator parsing for OpenAI-style `data: [DONE]` format. Terminators are now checked after data extraction and only at event boundaries to prevent data loss. ## 3.8.5 **`(fix):`** Fix SSE parser concatenating multiple events into malformed JSON. Events are now properly separated at blank line boundaries per SSE specification, with correct handling of multiline data fields and stream terminators. --- # October 1, 2025 ## 3.8.3 **`(fix):`** Upgrade generator-cli dependency to fix local generation handling of .fernignore files. ## 3.8.2 **`(fix):`** Fix local file system generation to use proper Gradle directory structure (src/main/java). Source files are now correctly placed at src/main/java/com/package instead of com/package at the root. --- # September 30, 2025 ## 3.8.4 **`(fix):`** Fixed code generation for undiscriminated unions with optional types. Generated code now correctly wraps optional values with `Optional.of()`, and wire tests are properly generated by default. ## 3.8.1 **`(fix):`** Append decimal to whole number double literals to prevent compilation errors. --- # September 29, 2025 ## 3.8.0 **`(feat):`** Add `getResponse()` method to `BasePage` for accessing pagination metadata like cursor tokens. This enables stateless pagination by providing access to the full API response object. Usage example: ```java SyncPagingIterable users = client.users().list(); users.getResponse().ifPresent(response -> { String cursor = response.getNext(); // Use cursor for stateless pagination }); ``` ## 3.7.0 **`(feat):`** Wire tests are now enabled by default for all Java SDKs, providing comprehensive HTTP protocol validation tests using MockWebServer. Wire tests validate request/response serialization, HTTP methods, headers, and API contract adherence. To disable wire tests, explicitly set `enable-wire-tests: false` in your generator configuration. --- # September 28, 2025 ## 3.6.3 **`(fix):`** Fixed OAuth auth clients not receiving variables needed for token endpoints with path parameters. --- # September 25, 2025 ## 3.6.2 **`(fix):`** Fixed SDK variable setters incorrectly referencing non-existent `clientOptionsBuilder`. Variables now store in instance fields and apply via `setVariables()` method. ## 3.6.1 **`(fix):`** Fixed wire tests failing with `InvalidDefinitionException` for `Optional` serialization by using the configured `ObjectMappers.JSON_MAPPER` instead of plain `ObjectMapper`. ## 3.6.0 **`(feat):`** Add support for PR mode for self-hosted/local sdk generation. ## 3.5.10 **`(fix):`** Snippets now show client-level variables in builder instead of method parameters. --- # September 24, 2025 ## 3.5.9 **`(fix):`** Fixed missing `java.util.Optional` import in dynamic snippets generation for wire tests. --- # September 23, 2025 ## 3.5.8 **`(fix):`** Fixed wire test generation for union services and added automatic pagination package detection. --- # September 22, 2025 ## 3.5.7 **`(fix):`** Fixed `NullPointerException` in builder setters when collections are null by adding null checks before `addAll()`/`putAll()` calls. ## 3.5.6 **`(fix):`** Fixed wire test generation: paginated endpoints return `SyncPagingIterable`, auth methods use correct builder patterns --- # September 20, 2025 ## 3.5.5 **`(fix):`** Fixed wire test compilation errors: pagination types now use raw responses, union factory methods use correct variant names, and empty optionals generate `Optional.empty()` instead of invalid `Optional.of()` calls --- # September 18, 2025 ## 3.5.4 **`(fix):`** Fixed wire test compilation errors by adding missing imports for request/response types and correcting primitive type mapping. --- # September 17, 2025 ## 3.5.3 **`(fix):`** Fixes an issue where the generated usage snippets in the README.md was not prioritizing user defined example values over autogenerated example values. ## 3.5.2 **`(fix):`** customReadmeSections from the generator invocation config are included in the README.md ## 3.5.1 **`(chore):`** Refactored wire test generator to modular architecture for improved maintainability. Enhanced JSON formatting in tests with proper multi-line string concatenation for better readability. --- # September 16, 2025 ## 3.5.0 **`(feat):`** Enhanced wire testing framework with comprehensive SDK validation capabilities. Wire tests now include header validation from IR examples, multi-URL environment configuration support, complex type validation for unions/nullable/generic types, and full pagination testing with `Iterable` support. ## 3.4.1 **`(fix):`** Fix compilation errors when undiscriminated unions contain multiple members that resolve to the same Java type (e.g., multiple strings, string vs string enum). The generator now correctly disambiguates duplicate method signatures by adding numeric suffixes (of2, of3, visit2, visit3) to factory and visitor methods when needed. --- # September 15, 2025 ## 3.4.0 **`(feat):`** Add support for custom sections in the README.md via `customSections` config option. ## 3.3.0 **`(feat):`** Wire tests now automatically configure authentication based on the API's auth scheme (Bearer, Basic, Header/Custom, OAuth, or Inferred) instead of using hardcoded tokens. Real authentication values are extracted from IR examples when available, making tests more accurate and maintainable. ## 3.2.2 **`(fix):`** Fix nullable request bodies with Optional fields to correctly generate .isPresent() checks on the Optional field itself, rather than on the entire request object. ## 3.2.1 **`(fix):`** Changed Optional.of() to Optional.ofNullable() to handle null values gracefully, allowing users to reset to default version. --- # September 11, 2025 ## 3.2.0 **`(feat):`** Add comprehensive request and response body validation to wire tests for Java SDKs. Wire tests now validate that SDKs correctly serialize request bodies and deserialize response bodies, catching regressions in JSON handling. ## 3.1.0 **`(feat):`** Support Maven publishTarget from IR for local filesystem SDK generation. --- # September 10, 2025 ## 3.0.1 **`(fix):`** Fix compilation errors in generated SDK snippets for collections with optional types and unknown size arrays. Generated documentation (README.md and reference.md) now shows cleaner, more idiomatic Java code examples using `Arrays.asList()` directly instead of unnecessary `ArrayList` wrapping. --- # September 9, 2025 ## 3.0.0 **`(break):`** The SDK generator now defaults to forward-compatible enums, providing resilience against new enum variants added on the backend. This is a breaking change that affects the structure of generated enum types. To revert to the previous behavior with traditional Java enums, add the following configuration to your `generators.yml` file: ```yaml generators: - name: fernapi/fern-java-sdk config: enable-forward-compatible-enums: false ``` **`(feat):`** Forward-compatible enums are now enabled by default. Generated SDKs will no longer throw errors when encountering unknown enum variants, instead handling them gracefully with an UNKNOWN value. This is particularly important for: * Mobile applications that cannot be easily updated * Maintaining backward compatibility when backend adds new enum values * Arrays of enum values where new variants previously caused client failures With forward-compatible enums, the generated code changes from traditional Java enums to class-based enums that support unknown values through a visitor pattern. --- # September 3, 2025 ## 2.43.3 **`(fix):`** Bugfix to make sure that the Java SDK compiles when header based versioning with defaults is enabled. ## 2.43.2 **`(fix):`** Fix custom license name extraction in build.gradle to display actual license names from LICENSE files instead of toString() representations. The generator now reads the first line of custom LICENSE files and displays it as the license name. --- # September 2, 2025 ## 2.43.1 **`(fix):`** Fix Maven Central signing configuration to correctly use 3-parameter useInMemoryPgpKeys() method. The signing block was incorrectly using MAVEN\_SIGNATURE\_SECRET\_KEY as the key ID parameter instead of MAVEN\_SIGNATURE\_KID, causing Sonatype Central validation failures during deployment. --- # August 29, 2025 ## 2.43.0 **`(feat):`** Add support for the `apiName` and `disabledFeatures` readme config options. --- # August 27, 2025 ## 2.42.1 **`(fix):`** Fix nullable fields incorrectly requiring non-null values in staged builders when use-nullable-annotation is enabled. --- # August 25, 2025 ## 2.42.0 **`(feat):`** Add support for semantic distinction between `nullable` and `optional` types via `use-nullable-annotation` flag. When enabled, `nullable` generates as raw type `T` with `@Nullable` annotation, while `optional` remains as `Optional`. This provides proper API semantics for fields that can be null vs those that may be absent from requests. ```yaml customConfig: use-nullable-annotation: true ``` --- # August 19, 2025 ## 2.41.3 **`(feat):`** Add convenient `addHeader()` method to SDK builders for adding custom headers without requiring OkHttpClient customization or inheritance. ## 2.41.2 **`(feat):`** Link reference.md in the README.md. --- # August 15, 2025 ## 2.41.1 **`(fix):`** Fix integer overflow when processing OpenAPI specs with large integer values in examples. Values exceeding Java's Integer range are automatically converted to long type to prevent generation failures. --- # August 14, 2025 ## 2.41.0 **`(feat):`** Add support for generating wire tests via `enable-wire-tests` flag. Wire tests verify HTTP protocol communication using MockWebServer and are generated for all endpoints in a service. ```yaml customConfig: enable-wire-tests: true ``` Generated tests include: * Working 404/500 error tests that compile immediately * Success test templates with TODO comments for customization * Proper handling of staged vs regular builders * Constants for all magic strings for better maintainability Note: Complex request bodies and response validation require manual customization. --- # August 13, 2025 ## 2.40.0 **`(feat):`** Add support for client-side default parameter values via `use-default-request-parameter-values` flag. When enabled, query and header parameters with defaults become Optional types and defaults are automatically applied when not provided. Example: ```yaml customConfig: use-default-request-parameter-values: true ``` Generated code: ```java // Parameters with defaults become Optional private final Optional perPage; // Has default: 50 // Defaults are applied automatically QueryStringMapper.addQueryParameter(httpUrl, "per_page", request.getPerPage().orElse(50), false); ``` --- # August 5, 2025 ## 2.39.6 **`(feat):`** Add opt-in extensible builder pattern via `enable-extensible-builders` flag. When enabled, builders use the self-type pattern allowing users to extend generated builders while maintaining type safety. Example: ```java class CustomBuilder extends BaseClientBuilder { @Override protected CustomBuilder self() { return this; } public CustomBuilder workspaceId(String id) { // custom logic return this; } } ``` ## 2.39.5 **`(fix):`** Fix undiscriminated union deserialization to catch all RuntimeException types instead of just IllegalArgumentException. --- # August 4, 2025 ## 2.39.4 **`(fix):`** Ensure JUnit dependencies are always added when test files are generated ## 2.39.3 **`(fix):`** Fix compilation error when using boolean path parameters by properly handling primitive boolean to String conversion --- # July 31, 2025 ## 2.39.2 **`(fix):`** Fix javadoc compilation errors by using HTML entities for special characters in builder examples --- # July 25, 2025 ## 2.39.1 **`(fix):`** Refactor builder extension pattern to use Template Method with dynamic generation. Configuration methods are only generated based on API spec (auth, headers, variables). All methods are protected for override. --- # July 24, 2025 ## 2.39.0 **`(feat):`** Enable builder extensibility for generated SDK clients. Builders are no longer marked as final, allowing users to extend them and customize client behavior. Added protected buildClientOptions() method for customization hooks and static from() method to ClientOptions.Builder for copying existing configurations. This enables use cases like environment variable expansion in URLs and custom authentication methods. --- # July 23, 2025 ## 2.38.8 **`(fix):`** Fix byte array convenience methods to include all parameters when delegating to InputStream methods. ## 2.38.7 **`(fix):`** Swap InputStreamRequestBody arguments to match constructor. --- # July 21, 2025 ## 2.38.6 **`(fix):`** Add explicit type to pagination lambda parameters. --- # July 18, 2025 ## 2.38.5 **`(chore):`** Remove internal OkHttp utility dependency and use a more robust file closing method. --- # July 17, 2025 ## 2.38.4 **`(fix):`** Fix stream SSE test to use Java 8 compatible stream collection method. --- # July 16, 2025 ## 2.38.3 **`(fix):`** Add reference.md generation for Java SDKs. --- # July 9, 2025 ## 2.38.2 **`(fix):`** Fix java sdk readme generation to properly create maven shield. --- # June 23, 2025 ## 2.38.1 **`(fix):`** Fix JavaDoc generation to properly escape dollar signs (\$) when using JavaPoet. When generating JavaDoc comments with JavaPoet, dollar signs need to be escaped as `$$` to prevent JavaPoet from interpreting them as template variables. This ensures that dollar signs in documentation are rendered correctly in the final generated code. ## 2.38.0 **`(chore):`** Add support for custom config publish-to to enable publishing to Maven Central with proper metadata and signing configuration. ```yaml customConfig: publish-to: central ``` This configuration enables automatic publishing to Maven Central with proper metadata and signing configuration. ## 2.37.2 **`(chore):`** No changes. Publishing changes from 2.37.1-rc0 and 2.37.1-rc1 to release track. --- # June 16, 2025 ## 2.37.1-rc1 **`(fix):`** Remove Content-Type from headers when request has no body --- # June 13, 2025 ## 2.37.1-rc0 **`(fix):`** Fix array query params are treated as exploded: true --- # June 4, 2025 ## 2.37.0 **`(feat):`** Add support for generating a full project in filesystem mode. --- # June 3, 2025 ## 2.36.5 **`(internal):`** Update the IR to v58. --- # May 21, 2025 ## 2.36.4 **`(fix):`** Generates docs for method types. --- # May 20, 2025 ## 2.36.3 **`(fix):`** Updates the generator to always commit changes, even if there are none, in self-hosted mode. This allows users to make sure that the generator actually ran and attempted to make a commit. --- # May 15, 2025 ## 2.36.2 **`(fix):`** Fix the generated README.md for the `maxRetries` configuration option, which is now shown on the client constructor. --- # May 13, 2025 ## 2.36.1 **`(fix):`** Add support for the custom introduction setting in the generated README.md. --- # May 11, 2025 ## 2.36.0 **`(feat):`** Support sending requests with content type application/x-www-form-urlencoded. --- # May 1, 2025 ## 2.35.3 **`(fix):`** Rerelease with the latest generator-cli. ## 2.35.2 **`(fix):`** Install the generator-cli at build time as a fallback if runtime installation fails. ## 2.35.1 **`(fix):`** Self hosted github user defaults to `fern-api[bot]`. ## 2.35.0 **`(fix):`** Support pushing to GitHub enterprise. ## 2.34.0 **`(fix):`** Upgrade to irV57 --- # April 28, 2025 ## 2.33.4 **`(fix):`** (Corrected from 2.33.2) Use non-deprecated method to create request body ## 2.33.3 **`(fix):`** Suppress unchecked cast warning for undiscriminated union visitor --- # April 25, 2025 ## 2.33.2 **`(fix):`** Use non-deprecated method to create request body --- # April 24, 2025 ## 2.33.1 **`(fix):`** Fix inline overrides undoing allow-multiple parameterization --- # April 23, 2025 ## 2.33.0 **`(fix):`** Support for literals in union types --- # April 21, 2025 ## 2.32.9 **`(fix):`** Auth header prefix should prepend with a concatenation operator --- # April 9, 2025 ## 2.32.8 **`(fix):`** Use safe name for version enum ## 2.32.7 **`(fix):`** Run v2 generation for SDK generator only ## 2.32.6 **`(fix):`** Fix getting the default version of an api versions enum to not require the `CURRENT` entry --- # April 8, 2025 ## 2.32.5 **`(fix):`** Fix inlining forward-compatible enums --- # April 1, 2025 ## 2.32.4 **`(fix):`** Fix typos in README generator ## 2.32.3 **`(fix):`** Add logging for Java v2 generator call ## 2.32.2 **`(fix):`** Add fallback snippet renderer for readme generation --- # March 31, 2025 ## 2.32.1 **`(fix):`** Fix pagination in raw clients --- # March 29, 2025 ## 2.32.0 **`(feat):`** Generate snippet.json --- # March 27, 2025 ## 2.31.0 **`(fix):`** Apply content type to request body creation ## 2.30.0 **`(feat):`** Include response headers in API exceptions ## 2.29.0 **`(fix):`** Query params respect allow-multiple --- # March 26, 2025 ## 2.28.0 **`(feat):`** Expose response headers --- # March 24, 2025 ## 2.27.1 **`(fix):`** Change method to `public static void main(String[] args)` in snippet generation --- # March 21, 2025 ## 2.27.0 **`(feat):`** Support automatic README.md generation --- # March 13, 2025 ## 2.26.0 **`(feat):`** Expose max retries for clients ## 2.25.0 **`(feat):`** Add config to inline file properties --- # March 12, 2025 ## 2.24.4 **`(fix):`** Prevent put requests from generating without a request body ## 2.24.3 **`(fix):`** Fix double unknown in forward-compatible enums **`(fix):`** Prevent enum keyword use in package paths ## 2.24.2 **`(fix):`** Remove 'object' from Java reserved strings list --- # March 11, 2025 ## 2.24.1 **`(fix):`** Add @JsonIgnore to non-serialization getters for nullables ## 2.24.0 **`(fix):`** Fix wrapped request paths in flat mode --- # March 7, 2025 ## 2.23.1 **`(fix):`** Fix async client builder generation --- # March 6, 2025 ## 2.23.0 **`(fix):`** Represent protobuf uint as int rather than long --- # March 5, 2025 ## 2.22.0 **`(feat):`** Add support for explicit nulls in serialization --- # March 4, 2025 ## 2.21.0 **`(feat):`** Add async clients --- # March 2, 2025 ## 2.20.1 **`(fix):`** Fix type reference syntax in readValue calls --- # February 27, 2025 ## 2.20.0 **`(fix):`** Fix collection serialization in multipart form body without form encoding --- # February 26, 2025 ## 2.19.0 **`(feat):`** Enable overriding literal headers --- # February 25, 2025 ## 2.18.1 **`(fix):`** Fix form body serialization --- # February 24, 2025 ## 2.18.0 **`(feat):`** Support form-data with deep object query params ## 2.17.0 **`(feat):`** Support deep object query parameters --- # February 20, 2025 ## 2.16.0 **`(chore):`** Upgrade IR version dependency to v55 --- # February 19, 2025 ## 2.15.0 **`(feat):`** Add support for custom HTTP client in Java SDK ## 2.14.0 **`(feat):`** Support user-agent header --- # February 18, 2025 ## 2.13.0 **`(feat):`** Flat package layout by setting `page-layout: flat` --- # February 14, 2025 ## 2.12.1 **`(fix):`** Fix collision with variant type called "Value" and internal interface name. **`(fix):`** Prevent discriminant from deserializing as additional property in unwrapped variant. --- # February 10, 2025 ## 2.12.0 **`(feat):`** Let users define custom headers in request options --- # February 4, 2025 ## 2.11.3 **`(fix):`** Don't add a semicolon twice when rendering accept header --- # February 3, 2025 ## 2.11.2 **`(fix):`** Add accept header if endpoint has errors ## 2.11.1 **`(fix):`** Send only request body reference for body-only wrapped request --- # January 29, 2025 ## 2.11.0 **`(feat):`** Add deep cursor path pagination support. --- # January 23, 2025 ## 2.10.7 **`(fix):`** Fix wrapped requests without inline path parameters checking not rendering no-request endpoint because of non-optional parameters --- # January 21, 2025 ## 2.10.6 **`(fix):`** Prevent accept header from being removed in wrapped requests ## 2.10.5 **`(fix):`** Add Accept header for json responses --- # January 19, 2025 ## 2.10.4 **`(fix):`** Fix potential NPE initializing client options with default version --- # January 17, 2025 ## 2.10.3 **`(fix):`** Fix inlining unwrapped alias types. --- # January 16, 2025 ## 2.10.2 **`(fix):`** Omit methods with inlined types from interface definitions. ## 2.10.1 **`(fix):`** Fix union inline type name conflict resolution. ## 2.10.0 **`(feat):`** Support inline types in the Java generator. --- # January 7, 2025 ## 2.9.0 **`(feat):`** Support version headers in request and client options. --- # December 23, 2024 ## 2.8.1 **`(feat):`** Implement global timeout configuration for generated clients. ```java var client = Client.builder() .apiKey("...") .timeout(40) .build(); ``` --- # December 20, 2024 ## 2.8.0 **`(feat):`** Generate inline request bodies with their path parameters in the object. --- # December 11, 2024 ## 2.7.0 **`(feat):`** Apply Content-Type header from endpoint definition in SDK generator. --- # December 10, 2024 ## 2.6.0 **`(fix):`** Don't generate pagination with nonempty path. Fixes pagination seed tests breaking. ## 2.5.0 **`(chore):`** Bump IR version to latest (v53) ## 2.4.0 **`(feat):`** We now support overriding sdk package prefixes by adding a "package-prefix" key under the java-sdk generator configuration. --- # December 4, 2024 ## 2.3.1 **`(fix):`** The rootProject.name is now set in settings.gradle and ci.yml uses ./gradlew sonatypeCentralUpload for publishing. ## 2.3.0 **`(feat):`** Fix publishing to Maven Central with proper signing configuration and metadata. --- # September 26, 2024 ## 2.2.0 **`(feat):`** We now provide endpoint methods for streaming byte array requests in addition to the previous methods accepting byte array directly. **`(chore):`** Bump Jackson version to latest (2.17.2) --- # September 11, 2024 ## 2.1.0 **`(feat):`** We no longer enforce non-null constraints for Object type properties in builders. --- # September 5, 2024 ## 2.0.0 **`(break):`** The SDK generator is now on major version 2. To take this upgrade without any breaks, please add the below configuration to your `generators.yml` file: ```yaml generators: - name: fernapi/fern-java-sdk config: disable-required-property-builder-checks: true ``` **`(feat):`** Generated builder methods now enforce non-null checks for required fields, ensuring that all required fields are properly validated during object construction: ```java @java.lang.Override @JsonSetter("name") public NameStage name(@NotNull String name) { this.name = Objects.requireNonNull(name, "name must not be null"); return this; } ``` --- # September 4, 2024 ## 1.0.7 **`(feat):`** Public constructors can now be generated for all model types: ```yaml generators: - name: fernapi/fern-java-sdk config: enable-public-constructors: true # default false ``` ## 1.0.6 **`(fix):`** Fixed a bug where optional collections are not handled properly in paginated responses. --- # July 26, 2024 ## 1.0.5 **`(fix):`** Fixed a bug where local generation custom config doesn't pick up some values, including exception naming. --- # July 24, 2024 ## 1.0.4 **`(fix):`** Fixed a bug where OkHttp responses could be closed prematurely. --- # July 23, 2024 ## 1.0.3 **`(feat):`** Generated builder methods for optional fields can now accept null directly. --- # July 2, 2024 ## 1.0.2-rc0 **`(feat):`** The generator now adds a class-level `@JsonInclude(JsonInclude.Include.NON_ABSENT)` annotation to each generated type in place of the previous `@JsonInclude(JsonInclude.Include.NON_EMPTY)` by default. This is configurable in the `generators.yml` file: ```yaml generators: - name: fernapi/fern-java-sdk config: json-include: non-empty # default non-absent ``` --- # June 26, 2024 ## 1.0.1 **`(break):`** The Java SDK is now on major version 1. To take this upgrade without any breaks, please add the below configuration to your `generators.yml` file: ```yaml generators: - name: fernapi/fern-java-sdk config: base-api-exception-class-name: ApiError base-exception-class-name: CompanyException # Optional: This should only be set if default naming is undesirable ``` **`(feat):`** We now generate Exception types for all errors that are defined in the IR. Generated clients with an error discrimination strategy of "status code" will throw one of these typed Exceptions based on the status code of error responses. Example error type: ```java public final class BadRequest extends MyCompanyApiError { public BadRequest(Object body) { super("BadRequest", 400, body); } } ``` --- # June 13, 2024 ## 0.10.1 **`(feat):`** Add support for cursor and offset pagination. ### What's new * Add support for cursor and offset pagination. For example, consider the following endpoint `/users` endpoint: ```yaml types: User: properties: name: string ListUserResponse: properties: next: optional data: list service: auth: false base-path: /users endpoints: list: path: "" method: GET pagination: cursor: $request.starting_after next_cursor: $response.next results: $response.data request: name: ListUsersRequest query-parameters: starting_after: optional response: ListUsersResponse ``` The generated `SyncPagingIterable` can then be used to traverse through the `User` objects: ```java for (User user : client.users.list(...)) { System.out.println(user); } ``` Or stream them: ```java client.users.list(...).streamItems().map(user -> ...); ``` Or statically calling `nextPage()` to perform the pagination manually: ```java SyncPagingIterable pager = client.users.list(...); // First page System.out.println(pager.getItems()); // Second page pager = pager.nextPage(); System.out.println(pager.getItems()); ``` --- # June 7, 2024 ## 0.10.0 **`(feat):`** The generator now supports BigInteger types. --- # June 6, 2024 ## 0.9.8 **`(feat):`** `RequestOptions` are now generated with the `timeout` field initialized to `Optional.empty()` instead of `null` to avoid NPEs if `timeout` is not set in the builder. ## 0.9.7 **`(feat):`** The SDK generator now generates `@java.lang.Override` over `@Override` in all files to avoid clashes with any `Override.java` class that may have been generated in the same package. The former was used most places, but not all, until this release. --- # June 5, 2024 ## 0.9.6 **`(feat):`** The SDK generator now supports returning response properties from client methods rather than just the responses themselves. --- # May 30, 2024 ## 0.9.5 **`(fix):`** Types without fields are now generated with builders. Previously, they were not, which made them impossible to initialize. ## 0.9.4 **`(fix):`** The SDK now generates undiscriminated unions with de-conflicted method signatures. Previously, certain undiscriminated unions would have failed to compile due to Java's type erasure causing conflicts. --- # May 23, 2024 ## 0.9.3 **`(feat):`** Generated SDK clients with an OAuth security scheme will now automatically refresh access tokens before they expire. --- # May 21, 2024 ## 0.9.2 **`(fix):`** Java 8 Compatibility. --- # May 15, 2024 ## 0.9.1 **`(fix):`** Support OAuth without token refresh. Example of initializing a client with OAuth: ```java ExampleApiClient client = ExampleApiClient .builder() .clientId("4bf2a37d-8512-44a2-af50-28a7701d9f2e") .clientSecret("b3b187b0-ef48-49ba-9d99-80d89fd11c4a") .build(); ``` --- # May 13, 2024 ## 0.9.0-rc0 **`(internal):`** Bump intermediate representation to v42 --- # May 8, 2024 ## 0.8.11 **`(fix):`** Corrects the fix in 0.8.10 to check null value as opposed to a .isPresent check, given the header is not `Optional`, it's always `String` ## 0.8.10 **`(fix):`** Fixes regression from 0.8.8, headers are no longer added to the header map unless they are non-null. --- # May 7, 2024 ## 0.8.9 **`(fix):`** Generated SDK clients now handle null response bodies and avoid NPEs when they receive error responses. ## 0.8.8 **`(fix):`** The generated SDKs no longer require global headers that are not directly related to auth if auth is mandatory within the SDK. Previously, the generator would require all global headers if auth was mandatory. --- # March 21, 2024 ## 0.8.7 **`(feat):`** You can now specify publishing metadata to populate your POM on publish: ```yaml generators: - name: fernapi/fern-java-sdk version: 0.X.Y output: location: maven registryUrl: "" publish-metadata: author: "" email: "" package-description: "" reference-url: "" ``` --- # March 20, 2024 ## 0.8.6 **`(fix):`** The SDK now generates RequestOptions functions for timeouts with IdempotentRequestOptions correctly, previously timeout functions were only taking in regular RequestOptions. This also addresses a JavaPoet issue where fields were being initialized twice across RequestOptions and IdempotentRequestOptions classes, preventing the SDK from generating at all. --- # March 18, 2024 ## 0.8.5 **`(feat):`** Add in publishing config that allows for signing published artifacts, this is required for publishing to Maven Central. To sign your artifacts, you must add the below to your publishing config: ```yaml generators: - name: fernapi/fern-java-sdk version: 0.X.Y output: location: maven registryUrl: "" signature: keyId: "" password: "" secretKey: "" ``` and secrets can be used, similar to how API keys are specified today: ```yaml generators: - name: fernapi/fern-java-sdk version: 0.X.Y output: location: maven registryUrl: "" signature: keyId: ${MY_KID_ENVVAR} password: ${MY_SECRET_ENVVAR} secretKey: ${MY_SECRET_KEY_ENVVAR} ``` --- # February 23, 2024 ## 0.8.5-rc0 **`(internal):`** Update docker image for Java SDK task runner. ## 0.8.4 **`(fix):`** The timeout specified on the RequestOptions object now sets the timeout on the entire call, not just the read timeout of the request. As a refresher, a timeout can be added per request like so: ```java RequestOptions ro = RequestOptions.builder().timeout(90).build(); // Creates a timeout of 90 seconds for the request // You could also specify the timeunit, similar to as if you were using OkHttp directly // RequestOptions ro = RequestOptions.builder().timeout(2, TimeUnit.MINUTES).build(); client.films.list(ro); ``` ## 0.8.3 **`(fix):`** The SDK generator now always creates a valid name for union discriminator wrapper classes. --- # February 21, 2024 ## 0.8.2 **`(fix):`** File upload endpoints no longer fail to compile because the reference to the mime type variable is present. ```java // Code that failed to compile String fileMimeType = Files.probeContentType(file.toPath()); MediaType fileMediaType = fileMimeType != null ? MediaType.parse(mimeType) : null; // mimeType undefined // Code that now compiles MediaType fileMediaType = fileMimeType != null ? MediaType.parse(fileMimeType) : null; ``` --- # February 14, 2024 ## 0.8.1 **`(feat):`** The RequestOptions object now supports configuring an optional timeout to apply per-request. ```java RequestOptions ro = RequestOptions.builder().timeout(90).build(); // Creates a timeout of 90 seconds for the request // You could also specify the timeunit, similar to as if you were using OkHttp directly // RequestOptions ro = RequestOptions.builder().timeout(2, TimeUnit.MINUTES).build(); client.films.list(ro); ``` --- # February 11, 2024 ## 0.8.0 **`(feat):`** The SDK generator now supports whitelabelling. When this is turned on, there will be no mention of Fern in the generated code. **Note**: You must be on the enterprise tier to enable this mode. --- # February 4, 2024 ## 0.7.1 **`(feat):`** The SDK generator now supports idempotency headers. Users will be able to specify the idempotency headers in RequestOptions. ```java Imdb imdb = Imdb.builder() .apiKey("...") .build(); var response = imdb.ticket.purchase("theatre-id", IdempotentRequestOptions.builder() .idempotencyKey("...") .build()); ``` **`(feat):`** The SDK generator now supports scanning API credentials via environment variables. ```java Imdb imdb = Imdb.builder() .apiKey("...") // defaults to System.getenv("IMDB_API_KEY") .build(); ``` **`(feat):`** The generated models now support boolean literals and users do not have to specify them in the builder. For example, for the following object ```yaml Actor: properties: name: string isMale: literal ``` the user will not need to specify the literal properties when building the object. ```java var actor = Actor.builder() .name("Brad Pitt") .build(); ``` --- # February 3, 2024 ## 0.6.1 **`(internal):`** Release version 0.6.1 --- # .NET quickstart > Generate a C#/.NET SDK with Fern's SDK generator. Follow step-by-step instructions to configure, build, and publish your client library. Generate a C#/.NET SDK by following the instructions on this page. This page assumes that you have: * An initialized `fern` folder. See [Set up the `fern` folder](/sdks/overview/quickstart). * A GitHub repository for your SDK. See [Project Structure](/sdks/overview/project-structure). ### Pass `fern check` Run `fern check` to ensure that your API definition is valid. If there are any errors, fix them before proceeding. If you're using an OpenAPI Specification, check out all of our [supported extensions](/learn/api-definition/openapi/extensions). ### Add the SDK generator Run the following command to add the C#/.NET SDK generator to `generators.yml`: ```bash fern add fern-csharp-sdk --group csharp-sdk ``` `csharp-sdk` is the name of the `generators.yml` group that configures your C#/.NET SDK's output location and other metadata. You can customize this group name to differentiate between multiple SDKs across different languages (e.g., `ruby-sdk`, etc) in your organization. This command adds the following `group` to `generators.yml`: ```yaml title="generators.yml" csharp-sdk: # group name generators: - name: fernapi/fern-csharp-sdk version: 2.20.3 output: location: local-file-system path: ../sdks/csharp ``` ### Generate the SDK Run the following command to generate your SDK: ```bash fern generate --group csharp-sdk ``` If you have multiple APIs, use the [`--api` flag](/cli-api-reference/cli-reference/commands#api) to specify the API you want to generate: ```bash fern generate --group csharp-sdk --api your-api-name ``` This creates a `sdks` folder in your current directory. The resulting folder structure looks like this: --- # .NET configuration > Configure your C# .NET SDK generator with Fern. Customize client class names, namespaces, error handling, and pagination settings. You can customize the behavior of the C#/.NET SDK generator in `generators.yml`: ```yml {6-7} title="generators.yml" groups: csharp-sdk: generators: - name: fernapi/fern-csharp-sdk version: 2.20.3 config: client_class_name: YourApiClient ``` When enabled, allows handling of additional properties not explicitly defined in the API specification. This provides flexibility for APIs that may include extra fields in responses. Customizes the name of the base API exception class that all API-specific exceptions will inherit from. This allows you to define a custom base exception class name for better integration with your existing error handling patterns. Specifies the name of the base exception class that all generated exceptions will inherit from. This provides a common parent class for all SDK exceptions, enabling consistent exception handling patterns. Sets the name of the generated API client class. This determines the primary client type name that users will interact with in the generated .NET SDK. Customizes the name of the pagination helper class used for handling paginated API responses. This allows you to specify a custom name that fits your naming conventions. When enabled, generates enum types that can handle unknown values gracefully. This allows the SDK to process new enum values that may be added to the API without breaking existing client code, improving forward compatibility. Specifies the name of the environment configuration class used for managing different API environments (e.g., development, staging, production). When enabled, generates code with explicit namespace declarations throughout the SDK. This can help avoid naming conflicts and improve code clarity in larger projects. Sets the name of the exported client class that will be used in code examples and documentation. This is useful for customizing how the client appears in generated documentation. When enabled, generates specific error type classes for different API errors. This provides strongly-typed error handling instead of using generic exception types. Generates [mock server (wire) tests](/sdks/deep-dives/testing#mock-server-tests) to verify that the SDK sends and receives HTTP requests as expected. When enabled, includes built-in exception handling utilities in the generated SDK. This provides convenience methods for common error handling scenarios. When enabled, path parameters are included as properties in the request object instead of being passed as separate method parameters. This creates a more unified request structure where all parameters are grouped together. Specifies the root namespace for all generated .NET code. This determines the namespace hierarchy that users will import when using the SDK. Sets the NuGet package identifier for the generated SDK. This is used when publishing the SDK to NuGet or other package repositories. Specifies a list of types that should be generated using ReadOnlyMemory\ instead of regular arrays or collections. This can improve performance for large data transfers by reducing memory allocations. Controls the access modifier for the root client class. Use 'public' to make the client accessible from other assemblies, or 'internal' to restrict access within the same assembly. When enabled, places core SDK classes (like base client classes and utilities) in the root namespace instead of nested namespaces. This can simplify imports for commonly used types. When enabled, generates discriminated union types for API responses that can contain multiple different object types. This provides type-safe handling of polymorphic responses. --- # Publishing to NuGet > Learn how to publish your Fern-generated C#/.NET SDK to NuGet registry with step-by-step configuration, API key setup, and automated release workflows. Publish your public-facing Fern C#/.NET SDK to the [NuGet registry](https://www.nuget.org/). After following the steps on this page, you'll have a versioned package published on NuGet. Versioned package published on NuGet This page assumes that you have: * An initialized `fern` folder. See [Set up the `fern` folder](/sdks/overview/quickstart). * A GitHub repository for your C#/.NET SDK. See [Project structure](/sdks/overview/project-structure). * A C#/.NET generator group in `generators.yml`. See [C#/.NET Quickstart](quickstart#add-the-sdk-generator). ## Configure SDK package settings You'll need to update your `generators.yml` file to configure the package name, output location, and client name for NuGet publishing. Your `generators.yml` [should live in your source repository](/sdks/overview/project-structure) (or on your local machine), not the repository that contains your C#/.NET SDK code. In the `group` for your C#/.NET SDK, change the output location from `local-file-system` (the default) to `nuget` to indicate that Fern should publish your package directly to the npm registry: ```yaml {6-7} title="generators.yml" groups: csharp-sdk: generators: - name: fernapi/fern-csharp-sdk version: 2.20.3 output: location: nuget ``` Your package name must be unique in the NuGet repository, otherwise publishing your SDK to NuGet will fail. ```yaml {8} title="generators.yml" groups: csharp-sdk: generators: - name: fernapi/fern-csharp-sdk version: 2.20.3 output: location: nuget package-name: your-package-name ``` The `client-class-name` option controls the name of the generated client. This is the name customers use to import your SDK (`import { your-client-name } from 'your-package-name';`). ```yaml {9-10} title="generators.yml" groups: csharp-sdk: generators: - name: fernapi/fern-csharp-sdk version: 2.20.3 output: location: nuget package-name: your-package-name config: client_class_name: YourClientName # must be PascalCase ``` ## Generate a NuGet API key Log into [NuGet](https://nuget.org/) or create a new account. 1. Click on your profile picture. 2. Select **API Keys**, then **Create**. 3. Name your key. 4. Select **Push > Push new packages and package versions** as the **Select Scopes** type. 5. Enter `*` under **Select Packages > Glob Patten**. If you are overriding an existing package, you can select the relevant package instead of entering `*`. 6. Click **Create**. Creating a New API Key Save your new key – it won’t be displayed after you leave the page. ## Configure NuGet publication Add the path to the GitHub repository containing your C#/.NET SDK: ```yaml title="generators.yml" {11-12} groups: csharp-sdk: generators: - name: fernapi/fern-csharp-sdk version: 2.20.3 output: location: nuget package-name: your-package-name config: client_class_name: YourClientName github: repository: your-org/company-csharp ``` Add `api-key: ${NUGET_API_KEY}` to `generators.yml` to tell Fern to use the `NUGET_API_KEY` environment variable for authentication when publishing to the NuGet registry. ```yaml title="generators.yml" {9} groups: csharp-sdk: generators: - name: fernapi/fern-csharp-sdk version: 2.20.3 output: location: nuget package-name: your-package-name api-key: ${NUGET_API_KEY} config: client_class_name: YourClientName github: repository: your-org/company-csharp ``` Optionally set the mode to control how Fern handles SDK publishing: * `mode: release` (default): Fern generates code, commits to main, and tags a release automatically * `mode: pull-request`: Fern generates code and creates a PR for you to review before release * `mode: push`: Fern generates code and pushes to a branch you specify for you to review before release You can also configure other settings, like the reviewers or license. Refer to the [full `github` (`generators.yml`) reference](/sdks/reference/generators-yml#github) for more information. ```yaml title="generators.yml" {14} groups: csharp-sdk: generators: - name: fernapi/fern-csharp-sdk version: 2.20.3 output: location: nuget package-name: your-package-name api-key: ${NUGET_API_KEY} config: client_class_name: YourClientName github: repository: your-org/company-csharp mode: push branch: your-branch-name # Required for mode: push ``` ## Publish your SDK Decide how you want to publish your SDK to NuGet. You can use GitHub workflows for automated releases or publish directly via the CLI. Set up a release workflow via [GitHub Actions](https://docs.github.com/en/actions/get-started/quickstart) so you can trigger new SDK releases directly from your source repository. Open your source repository in GitHub. Click on the **Settings** tab. Then, under the **Security** section, open **Secrets and variables** > **Actions**. You can also use the url `https://github.com//settings/secrets/actions`. 1. Select **New repository secret**. 2. Name your secret `NUGET_API_KEY`. 3. Add the corresponding API key you generated above. 4. Click **Add secret**. NUGET_API_KEY secret 1. Select **New repository secret**. 2. Name your secret `FERN_TOKEN`. 3. Add your Fern token. If you don't already have one, generate one by running `fern token`. By default, the `fern_token` is generated for the organization listed in `fern.config.json`. 4. Click **Add secret**. Set up a CI workflow that you can manually trigger from the GitHub UI. In your repository, navigate to **Actions**. Select **New workflow**, then **Set up workflow yourself**. Add a workflow that's similar to this: ```yaml title=".github/workflows/publish.yml" maxLines=0 name: Publish C#/.NET SDK on: workflow_dispatch: inputs: version: description: "The version of the C#/.NET SDK that you would like to release" required: true type: string jobs: release: runs-on: ubuntu-latest steps: - name: Checkout repo uses: actions/checkout@v4 - name: Install Fern CLI run: npm install -g fern-api - name: Release C#/.NET SDK env: FERN_TOKEN: ${{ secrets.FERN_TOKEN }} NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} run: | fern generate --group csharp-sdk --version ${{ inputs.version }} --log-level debug ``` You can alternatively configure your workflow to execute `on: [push]`. See Vapi's [npm publishing GitHub Action](https://github.com/VapiAI/server-sdk-typescript/blob/main/.github/workflows/ci.yml) for an example. Navigate to the **Actions** tab, select the workflow you just created, specify a version number, and click **Run workflow**. This regenerates your SDK. Running TS publish workflow The rest of the release process depends on your chosen mode: * **Release mode (default):** If you didn't specify a `mode` or set `mode: release`, no further action is required. Fern automatically tags the new release with your specified version number and initiates the publishing workflow in your SDK repository. * **Pull request or push mode:** If you set `mode: pull-request` or `mode: push`, Fern creates a pull request or pushes to a branch respectively. Review and merge the PR (`pull-request`) or branch (`push`), then [tag a new release](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository) to initiate the publishing workflow in your SDK repository. Once the workflow completes, you can view your new release by logging into NuGet and navigating to **Manage Packages**. Set the `NUGET_API_KEY` environment variable on your local machine: ```bash export NUGET_API_KEY=your-actual-nuget-api-key ``` Regenerate your SDK, specifying the version: ```bash fern generate --group csharp-sdk --version ``` The rest of the release process depends on your chosen mode: * **Release mode (default):** If you didn't specify a `mode` or set `mode: release`, no further action is required. Fern automatically tags the new release with your specified version number and initiates the publishing workflow in your SDK repository. * **Pull request or push mode:** If you set `mode: pull-request` or `mode: push`, Fern creates a pull request or pushes to a branch respectively. Review and merge the PR (`pull-request`) or branch (`push`), then [tag a new release](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository) to initiate the publishing workflow in your SDK repository. Once the workflow completes, you can view your new release by logging into NuGet and navigating to **Manage Packages**. --- # Adding custom code > Add custom logic and methods to your .NET SDK with Fern. Extend BaseClient, create custom helpers, and use .fernignore effectively. This page covers how to add custom logic and methods to your .NET SDK. Before getting started, [read about how Fern SDKs use custom code and learn about the `.fernignore` file](/sdks/overview/custom-code) . ## Adding custom logic To get started adding custom code: ```csharp title="src/YourNamespace/Helper.cs" namespace YourNamespace; public static class Helper { public static void MyHelper() { Console.WriteLine("Hello World!"); } } ``` ```yaml {3} title=".fernignore" # Specify files that shouldn't be modified by Fern src/YourNamespace/Helper.cs ``` Now your users can consume the helper function by importing it from the SDK. ```csharp using YourNamespace; Helper.MyHelper(); ``` ## Adding custom SDK methods Fern also allows you to add custom methods to the SDK itself (e.g. `client.my_method()` ) by inheriting the Fern generated client and then extending it. Name your Fern-generated client something like `BaseClient` to reflect that this client will be extended. ```yaml {4} title="generators.yml" - name: fernapi/fern-csharp-sdk version: 2.20.3 config: client-class-name: BaseClient ``` First, import the Fern generated base client and extend it. Then, add whatever methods you want. ```csharp title="src/YourNamespace/MyClient.cs" namespace YourNamespace; public class MyClient : BaseClient { public MyClient(ClientOptions? clientOptions = null) : base(clientOptions) { } public void MyHelper() { Console.WriteLine("Hello World!"); } } ``` Add the `MyClient.cs` to `.fernignore`. ```diff title=".fernignore" + src/YourNamespace/MyClient.cs ``` Instead of constructing the generated client, your users will want to construct the extended client. ```csharp using YourNamespace; var client = new MyClient(); ``` Now your users can consume the helper function by importing it from the SDK. ```csharp client.MyHelper(); ``` --- # .NET compatibility > Learn about supported .NET Framework versions (net462, net472, net48) and Unity compatibility for Fern-generated SDKs. Fern-generated .NET SDKs support modern .NET versions, .NET Framework versions, and Unity. Because these SDKs are built with modern C# features, you'll need the following even when targeting older .NET Framework targets: * A modern compiler (Visual Studio 2022 or .NET SDK) * The appropriate .NET Framework Developer Pack or reference assemblies ## Supported frameworks Fern .NET SDKs support [all officially supported .NET versions](https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-framework), except for net35. | Framework | Target Framework Moniker (TFM) | | -------------------- | ------------------------------ | | .NET 9 | net9.0 | | .NET 8 | net8.0 | | .NET Framework 4.8.1 | net481 | | .NET Framework 4.8 | net48 | | .NET Framework 4.7.2 | net472 | | .NET Framework 4.7.1 | net471 | | .NET Framework 4.7 | net47 | | .NET Framework 4.6.2 | net462 | The C# language version is determined by your compiler, while the target framework determines which runtime and base class library APIs are available. Fern SDKs use modern C# features but compile to older framework versions. All major IDEs support Fern-generated SDKs when targeting `net462`, `net472`, and `net48` versions: * **Visual Studio 2022** (recommended) - Works out of the box. Set `` in your project and install the appropriate [developer pack](#developer-packs). * **Visual Studio 2019** - Supports C# 9 natively. For newer C# versions, add the `Microsoft.Net.Compilers.Toolset` package. * **Rider** - Uses Roslyn. Set `` and ensure reference assemblies are available. * **VS Code** - Works via OmniSharp and .NET SDK builds. * **Unity** - Uses Unity's own C# compiler. See [Using SDKs with Unity](#using-sdks-with-unity). You can "bring your own compiler" with the `Microsoft.Net.Compilers.Toolset` package on any environment. Use the **Roslyn compiler** (`csc`) that comes with Visual Studio 2022+ or the .NET SDK. Set your C# version via `` to `latest`, `preview`, or a specific version (minimum `9`). Fern's .NET SDK doesn't support the legacy Mono compiler (`mcs`, `gmcs`) or the pre-Roslyn `csc.exe` compiler. Use Roslyn even when building on Mono. Use the .NET SDK (`dotnet`) with the `Microsoft.NETFramework.ReferenceAssemblies` package to supply `net48` references on non-Windows. Use Roslyn via `dotnet build` or Mono's MSBuild. ```bash title="macOS/Linux" dotnet build -c Release ``` * [.NET Framework 4.6.2 Developer Pack](https://dotnet.microsoft.com/en-us/download/dotnet-framework/net462) * [.NET Framework 4.7.2 Developer Pack](https://dotnet.microsoft.com/en-us/download/dotnet-framework/net472) * [.NET Framework 4.8 Developer Pack](https://dotnet.microsoft.com/en-us/download/dotnet-framework/net48) ## Using SDKs with Unity Unity controls its own C# compiler and .NET profile, which affects how you use Fern's .NET SDK. Unity compiles projects using Roslyn, typically supporting C# 9 (varies by Unity version). You can't force Unity to use a newer C# compiler by changing your package because Unity controls the compiler inside the Editor. Configure this in Unity: `Edit → Project Settings → Player → Other Settings → Api Compatibility Level` * **.NET Standard 2.1** (recommended for cross-platform plugins) * **.NET Framework 4.x** (Unity's "4.x equivalent" profile) Unity doesn't support NuGet packages, so you must manually download and add these assemblies to your Unity project: | Assembly | NuGet Package | | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | | Microsoft.Bcl.AsyncInterfaces | [10.0.0-preview.6.25358.103](https://www.nuget.org/packages/Microsoft.Bcl.AsyncInterfaces/10.0.0-preview.6.25358.103) | | OneOf | [3.0.271](https://www.nuget.org/packages/OneOf/3.0.271) | | OneOf.Extended | [3.0.271](https://www.nuget.org/packages/OneOf.Extended/3.0.271) | | System.Buffers | [4.6.1](https://www.nuget.org/packages/System.Buffers/4.6.1) | | System.IO.Pipelines | [10.0.0-preview.6.25358.103](https://www.nuget.org/packages/System.IO.Pipelines/10.0.0-preview.6.25358.103) | | System.Memory | [4.6.3](https://www.nuget.org/packages/System.Memory/4.6.3) | | System.Runtime.CompilerServices.Unsafe | [6.1.2](https://www.nuget.org/packages/System.Runtime.CompilerServices.Unsafe/6.1.2) | | System.Text.Encodings.Web | [10.0.0-preview.6.25358.103](https://www.nuget.org/packages/System.Text.Encodings.Web/10.0.0-preview.6.25358.103) | | System.Text.Json | [10.0.0-preview.6.25358.103](https://www.nuget.org/packages/System.Text.Json/10.0.0-preview.6.25358.103) | | System.Threading.Tasks.Extensions | [4.6.3](https://www.nuget.org/packages/System.Threading.Tasks.Extensions/4.6.3) | | portable.system.datetimeonly | [9.0.0](https://www.nuget.org/packages/portable.system.datetimeonly/9.0.0) | ## Project configuration examples Use SDK-style projects where possible, as they provide modern compilers and simpler multi-targeting. If you have a classic project format, consider converting to SDK-style. The [legacy projects section](#legacy-projects) covers legacy setups that can't be converted. When building for `net48` on macOS/Linux, you won't have the Windows targeting packs. Add the reference assemblies package: ```xml title="YourProject.csproj" ``` This provides the `net48` reference assemblies so Roslyn can compile for `net48` on any platform. You'll still need Mono or Wine to execute the result. Targeting `net48` with modern C# Install the [.NET Framework 4.8 Developer Pack](#developer-packs) so the `net48` reference assemblies are available to the compiler. ```xml title="YourProject.csproj" net48 latest enable ``` ```bash dotnet build -c Release ``` To support multiple frameworks, use ``: {/* */} ```xml title="YourProject.csproj" net48;net8.0 ``` {/* */} For older MSBuild/Visual Studio versions, Visual Studio 2019, or legacy `packages.config` setups, add a modern Roslyn toolset and target the old framework. Install the appropriate [.NET Framework Developer Pack](#developer-packs) so Visual Studio can find the reference assemblies. ```xml title="YourProject.csproj" latest ``` Or use a specific version: `9`, `10`, `11`, `12`, or `preview`. ```xml title="YourProject.csproj" all ``` This ensures your build uses a modern `csc.exe` even if your IDE/MSBuild is older. ## Troubleshooting Add a small shim in your project or reference a helper package. * Windows: install the [.NET Framework 4.8 Developer Pack](#developer-packs). * Cross-platform/CI: add `Microsoft.NETFramework.ReferenceAssemblies` to the project (as `PrivateAssets=all`). Add `Microsoft.Net.Compilers.Toolset` to the project, or move to VS 2022+. This error occurs when using the `required` keyword with older Visual Studio versions. Follow the instructions at [Legacy projects](#legacy-projects) to add a modern compiler. Some versions of Visual Studio may show this error in the IDE but compile the project successfully when using the package-provided compiler. --- # January 30, 2026 ## 2.20.3 **`(fix):`** Fix `useDefaultRequestParameterValues` to only apply defaults to query parameters and headers, not to inlined request body properties. --- # January 29, 2026 ## 2.20.2 **`(fix):`** Wire test assertions now use JSON element comparison instead of object equality, resolving false failures when comparing collections inside undiscriminated union types. **`(fix):`** Fix mock response data generation to omit null values for optional-but-not-nullable properties, matching SDK serialization behavior. **`(fix):`** Fix nullability warning (CS8764) in undiscriminated union JsonConverter by using non-optional return type for ReadAsPropertyName method. ## 2.20.1 **`(fix):`** Fix ambiguous type references (CS0104) for sub-client interfaces when multiple sub-clients share the same name in different namespaces. **`(fix):`** Fix duplicate implicit conversion operators (CS0557) for undiscriminated unions with multiple variants that resolve to the same type. **`(fix):`** Add transitive implicit conversion operators for nested undiscriminated unions. ## 2.20.0 **`(chore):`** Remove .NET 6 (EOL 2024/10/12) and 7 (EOL 2024/05/14) target frameworks from generated SDKs as they are no longer supported by Microsoft. The generated SDKs now only target .NET Framework 4.6.2, .NET Standard 2.0, and .NET 8. ## 2.19.7 **`(fix):`** Top-level clients now use interface types for sub-clients instead of concrete types. ## 2.19.6 **`(fix):`** Fix wire test generation to preserve string field values that contain datetime-like strings. --- # January 28, 2026 ## 2.19.5 **`(fix):`** Fix missing client-level headers for endpoints without endpoint-specific headers. Previously, endpoints that didn't have endpoint-specific headers (like custom request headers) would not include client-level headers (API key, SDK version, additional headers) in their HTTP requests. This caused authentication failures for APIs that rely on headers set at the client level. The fix ensures that all endpoints now properly merge headers from: * Client options headers (API key, SDK version, etc.) * Client additional headers (user-provided at client construction) * Request options additional headers (user-provided per-request) ## 2.19.4 **`(fix):`** Fix missing `[Optional]` and/or `Nullable` attributes on generated properties with defaults. ## 2.19.3 **`(fix):`** Fully unwrap optional-nullable wrappers when generating undiscriminated unions. ## 2.19.2 **`(fix):`** Fixes missing references to Core utilities in interface files for the Optional wrapper. ## 2.19.1 **`(fix):`** Fix nullable element types in collections to correctly preserve nullable markers. Previously, nullable types nested inside collections would incorrectly strip the inner nullable marker: * `nullable>>` incorrectly generated `IEnumerable?` * `nullable>>` incorrectly generated `Dictionary?` Now generates correctly: * `nullable>>` generates `IEnumerable?` * `nullable>>` generates `Dictionary?` * `optional>>` generates `Dictionary?` --- # January 27, 2026 ## 2.19.0 **`(feat):`** Add support for type-safe undiscriminated unions with the new `use-undiscriminated-unions` configuration option. Undiscriminated unions provide a clean, type-safe way to work with values that can be one of several types: ```csharp // Creating union values var response = MyUnion.FromString("hello"); var response = MyUnion.FromInt(42); var response = MyUnion.FromCustomObject(new CustomObject { ... }); // Type-safe value access with Is* properties and As* methods if (response.IsString) { string value = response.AsString(); Console.WriteLine($"Got string: {value}"); } else if (response.IsInt) { int value = response.AsInt(); Console.WriteLine($"Got integer: {value}"); } // Safe extraction with TryAs* pattern (no exceptions) if (response.TryAsCustomObject(out var obj)) { Console.WriteLine($"Got object: {obj.Name}"); } ``` This provides better IntelliSense support and compile-time safety compared to working with generic `object` types. **`(chore):`** Reduce NuGet package dependencies. The OneOf library is no longer required when undiscriminated unions are not used, resulting in smaller package sizes and fewer transitive dependencies. ## 2.18.1 **`(fix):`** While most `<`s and `>`s should be escaped to `<` and `>` to avoid mangling the output, genuine XML/HTML tags should be kept as-is; this commit scans for potential valid tags and prevents their being escaped. (Ambiguous cases are escaped.) Before: ``` /// XMLDoc (C#) (Example of actual XML tags): /// See <a href="https://example.com/docs">the docs</a> for more info. /// Use <code>getValue()</code> to retrieve the value. /// Note: when count < 10 or count > 100, special handling applies. ``` After: ``` /// XMLDoc (C#) (Example of actual XML tags): /// See the docs for more info. /// Use getValue() to retrieve the value. /// Note: when count < 10 or count > 100, special handling applies. ``` --- # January 26, 2026 ## 2.17.5 **`(fix):`** Fix test equality comparison for nested OneOf values in collections. Previously, when comparing objects containing `List>` properties (such as `RelatedResources` in FHIR-style models), the test framework would incorrectly report differences even when the values were identical. This was because the nested OneOf comparer didn't recursively handle OneOf values within collections. The fix adds a custom `EqualityAdapter` that registers itself with the inner `NUnitEqualityComparer`, enabling proper recursive comparison of nested OneOf values. ## 2.17.4 **`(fix):`** Fix extra properties support for inlined request bodies and improve test equality comparisons. This fix addresses three issues with the `extra-properties: true` feature: * Inlined request bodies now properly support `AdditionalProperties` for serialization/deserialization * Test snippets now include extra properties from examples for both object types and wrapped requests * Added `AdditionalPropertiesComparer` to handle type mismatches between JsonElement and native C# types in test assertions ## 2.17.3 **`(fix):`** Fix mock server tests to use FormUrlEncodedMatcher for form-urlencoded requests. Previously, mock server tests used `WithBodyAsJson` for form-urlencoded requests, which caused test failures because the SDK sends the request body as `key=value&key2=value2` format, not JSON. This fix uses WireMock's `FormUrlEncodedMatcher` to properly match form-urlencoded request bodies. --- # January 23, 2026 ## 2.17.2 **`(fix):`** Fix mock server tests to exclude read-only properties from expected request JSON. Previously, mock server tests included read-only properties (marked with `access: read-only`) in the expected request JSON, causing test failures because the SDK correctly excludes these properties during serialization. This fix filters out read-only properties at all nesting levels, including within dictionaries, lists, and nested objects. ## 2.17.1 **`(fix):`** Add global::System to Attribute in OptionalAttribute and NullableAttribute. --- # January 22, 2026 ## 2.18.0 **`(feat):`** Add `QueryStringBuilder` class for building query strings with proper URL encoding. Example usage: ```csharp var queryString = new QueryStringBuilder.Builder() .Add("access_token", "abc123") .Add("config_id", "cfg-456") .AddDeepObject("session_settings", new { SystemPrompt = "Hello" }) .Build(); // Result: ?access_token=abc123&config_id=cfg-456&session_settings%5BSystemPrompt%5D=Hello ``` **`(chore):`** Improve header merging logic for better reliability and maintainability. **`(chore):`** Remove `additional-properties` and `experimental-additional-properties` configuration options. AdditionalProperties support is now always enabled for all generated SDKs, simplifying the generator and ensuring consistent behavior across all generated code. This feature allows handling of extra/unknown properties in JSON responses. --- # January 21, 2026 ## 2.17.0 **`(feat):`** Respect defaults set for request parameter values. When `use-default-request-parameter-values: true` is configured in generators.yml, the SDK will generate initializers of the form `= default` for those properties of a record that have defaults. Any property with a default will also have the 'required' keyword stripped if it's there, since users should be allowed to omit it during initialization and rely on the default. --- # January 20, 2026 ## 2.16.0 **`(feat):`** Add support for accessing raw HTTP response data alongside typed response objects using `.WithRawResponse()`. HTTP endpoint methods now return `WithRawResponseTask`, which provides two usage patterns: * **Default behavior**: Direct `await` returns just the typed data (zero-allocation fast path) * **Raw response access**: Await with `.WithRawResponse()` returns both data and HTTP metadata Example usage: ```csharp // Default behavior - returns just the data var userData = await client.Users.GetAsync("user-123"); // Access raw response metadata var result = await client.Users.GetAsync("user-123").WithRawResponse(); var data = result.Data; var statusCode = result.RawResponse.StatusCode; // HttpStatusCode var headers = result.RawResponse.Headers; // ResponseHeaders var url = result.RawResponse.Url; // Uri // Access specific headers (case-insensitive) if (headers.TryGetValue("X-Request-Id", out var requestId)) { Console.WriteLine($"Request ID: {requestId}"); } // Check content type and length var contentType = headers.ContentType; var contentLength = headers.ContentLength; ``` New types: * `WithRawResponseTask` - Awaitable task wrapper supporting both usage patterns * `WithRawResponse` - Container for data + raw response metadata * `RawResponse` - HTTP response metadata (status code, headers, URL) * `ResponseHeaders` - Case-insensitive header collection with enumeration support Benefits: * Zero overhead when raw response access isn't needed * Backward compatible - implicit conversion to `Task` supported * Type-safe access to HTTP metadata when debugging or logging * Case-insensitive header lookups following HTTP standards --- # January 15, 2026 ## 2.15.0 **`(feat):`** Add support for explicit nullable/optional type handling with the new `Optional` type. When `experimental-explicit-nullable-optional: true` is configured in generators.yml, the SDK will use `Optional` for nullable optional fields, enabling three-state semantics for PATCH requests: * **Undefined**: Field not set - won't be included in the request (leave unchanged on server) * **Defined with null**: Field explicitly set to null - will send `null` (clear the field on server) * **Defined with value**: Field set to a value - will send the value (update the field on server) Example usage: ```csharp public class UpdateUserRequest { public Optional Name { get; set; } = Optional.Undefined; public Optional Email { get; set; } = Optional.Undefined; } // Don't send name field (leave unchanged) var request1 = new UpdateUserRequest(); // Set name to a value var request2 = new UpdateUserRequest { Name = "John" }; // Clear name (send null) var request3 = new UpdateUserRequest { Name = null }; ``` The `Optional` type includes: * `IsDefined` property to check if a value is set * `Value` property to access the value (throws if undefined) * `TryGetValue` method for safe value access * Implicit conversion operators for ergonomic usage * Full JSON serialization support * `IEquatable>` implementation for proper equality checks **`(fix):`** Fix query parameter serialization to properly handle nullable struct types (DateTime?, DateOnly?, etc.) by adding `.Value` accessor when needed. **`(fix):`** Improve nullable and optional type handling throughout the generator, including collection value types and type mapping. ## 2.14.1 **`(fix):`** When `include-exception-handler: true` is configured, the generated exception interceptor class now accepts `ClientOptions` in its constructor. This allows the interceptor to access client configuration when capturing exceptions. ## 2.14.0 **`(feat):`** Refactor WebSocket API code generation to use composition over inheritance. Key changes: * Replace `AsyncApi` base class with `WebSocketClient` internal class using composition * Flatten namespace from `{root}.Core.Async.*` to `{root}.Core.WebSockets` * Generated WebSocket clients now implement `IAsyncDisposable`, `IDisposable`, and `INotifyPropertyChanged` directly * Store `Options` and `WebSocketClient` as private fields instead of using inheritance * Forward `Status`, `Connected`, `Closed`, and `ExceptionOccurred` events from internal client * Simplify `INotifyPropertyChanged` to only notify for `Status` property changes This refactoring improves code clarity and reduces complexity. --- # January 13, 2026 ## 2.13.1 **`(chore):`** Update Dockerfile to use the latest generator-cli with improve reference.md generation. --- # January 6, 2026 ## 2.13.0 **`(feat):`** Generate interfaces for all SDK clients to enable dependency injection and mocking for unit testing. Each client class now implements a corresponding interface: * Root client implements `I{ClientName}` (e.g., `IAcmeClient`) * Sub-package clients implement `I{SubpackageName}Client` (e.g., `IUsersClient`) This allows consumers to: * Use dependency injection frameworks to inject client interfaces * Mock client interfaces in unit tests using libraries like Moq or NSubstitute * Follow SOLID principles with interface-based programming --- # January 5, 2026 ## 2.12.2 **`(chore):`** Update Dockerfile CVE patches to work with newer generator-cli package structures. --- # December 18, 2025 ## 2.12.1 **`(chore):`** Add sdkVersion as a top-level field in the generated metadata.json file. --- # December 13, 2025 ## 2.11.4 **`(fix):`** Don't use `required` keyword on properties that are read-only, since they're not supposed to be set by users. --- # December 11, 2025 ## 2.12.0 **`(feat):`** Add support for inferred authentication scheme. This allows the SDK to automatically obtain authentication tokens from a specified token endpoint and cache them for subsequent requests. When an API uses inferred auth, the SDK will: * Call the token endpoint to obtain authentication headers * Cache the headers and refresh them when expired (with a 2-minute buffer) * Automatically set the authenticated request headers on all API calls ## 2.11.3 **`(fix):`** Remove blocking `.Result` calls on async tasks in generated code. Header values now support async resolution via `Func>` and `Func>`, and the `RawClient` uses async methods (`CreateHttpRequestAsync`, `MergeHeadersAsync`) to resolve headers without blocking. This improves performance and prevents potential deadlocks in async contexts. --- # December 5, 2025 ## 2.11.2 **`(fix):`** Change core files to fully qualify references to `Attribute` and related types in case of name collision. ## 2.11.1 **`(fix):`** When `include-exception-handler: true` is configured: * Remove unneeded `CaptureException` method from `Interceptor` class, since there's already an `Intercept` method. ## 2.11.0 **`(feat):`** Add constructor exception handling infrastructure for SDK authors to capture initialization errors. When `include-exception-handler: true` is configured: * Adds `CaptureException` method to `ExceptionHandler` class for capturing exceptions without re-throwing * Wraps all client constructors (root and sub-clients) with try-catch blocks * Initializes `clientOptions.ExceptionHandler` with a custom interceptor in the root client constructor * Generates a `{PackageName}ExceptionInterceptor` stub class that SDK authors can customize New configuration option: * `exception-interceptor-class-name`: Custom name for the exception interceptor class (optional) Example generators.yml configuration: ```yml groups: dotnet-sdk: generators: - name: fernapi/fern-csharp-sdk version: 2.11.0 config: include-exception-handler: true exception-interceptor-class-name: MyCustomExceptionInterceptor ``` SDK authors can implement their exception capturing logic (e.g., application monitoring platform, logging) in the generated interceptor class. --- # December 3, 2025 ## 2.10.0 **`(feat):`** Add support for flexible `output-path` configuration that allows specifying different paths for the library project, test project, solution file, and other files (README.md, reference.md). Configuration options: * Simple string: `output-path: src` - all projects go to that path * Object with specific paths: * `library`: path for the library project (default: "src") * `test`: path for the test project (default: "src") * `solution`: path for the solution file (default: ".") * `other`: path for README.md, reference.md, and other files (default: ".") Example generators.yml configuration: ```yml groups: dotnet-sdk: generators: - name: fernapi/fern-csharp-sdk version: 2.10.0 config: output-path: library: src/MyApi test: test/MyApi.Test solution: . other: src/MyApi ``` The generated CI workflow and project references are automatically updated to use the configured paths. Note: `.github`, `.fern`, `.editorconfig`, `.gitignore`, and `.fernignore` are always generated in the root output folder. ## 2.9.9 **`(fix):`** Retries now check `Retry-After` and `X-RateLimit-Reset` headers before defaulting to exponential backoff with jitter. ## 2.9.8 **`(fix):`** Restore default behavior for wire tests: tests are now generated by default and controlled via the existing `generate-mock-server-tests` config option (defaults to true). The `enable-wire-tests` option is now treated as an alias for backward compatibility. --- # December 2, 2025 ## 2.9.7 **`(fix):`** Wire tests are now controlled entirely by the `enable-wire-tests` custom config option, no longer using the CLI's `writeUnitTests` flag. ## 2.9.6 **`(fix):`** Fix getGitHubConfig to return RawGithubConfig with undefined values instead of throwing errors when publishing config is missing, aligning with TypeScript/Python generator behavior. --- # November 27, 2025 ## 2.9.5 **`(fix):`** Fix readonly constant assertion message showing '\[object Object]' instead of property name. --- # November 26, 2025 ## 2.9.4 **`(fix):`** Remove error on null config in README generation. --- # November 21, 2025 ## 2.9.3 **`(fix):`** Remove using generator-cli to push to GitHub for self-hosted SDKs; this is now handled in the local workspace runner. --- # November 19, 2025 ## 2.9.2 **`(chore):`** Bump generator CLI version to publish new Docker image. --- # November 13, 2025 ## 2.9.1 **`(fix):`** Add check in test script to verify that .NET 10 is installed. --- # November 12, 2025 ## 2.9.0 **`(feat):`** Upgrade C# SDK generator Docker images to use .NET 10 SDK base image. * Improves package restoration and build performance * .NET 10 uses .slnx solution files instead of .sln files, which are more readable and generate deterministically * This change does not affect the target framework of generated SDKs ## 2.8.0 **`(feat):`** .github/workflows/ci.yml file changes: * Update actions/checkout to v5 * Update actions/setup-dotnet to v5 * Use .NET 10 SDK * Split up restore and build steps * Don't build the test project unless running tests --- # November 11, 2025 ## 2.7.5 **`(fix):`** Support enums in multipart-forms. Corrected date-normalization code in tests generation. ## 2.7.4 **`(chore):`** Upgrade C# formatter csharpier to 1.2.1. --- # November 10, 2025 ## 2.7.3 **`(fix):`** Refactor package dependencies in C# generation so Dynamic Snippets in the browser can work. --- # November 5, 2025 ## 2.7.2 **`(fix):`** Synthesize simple values for dynamic snippets when the example is missing data. ## 2.7.1 **`(fix):`** Improved generation of snippets and example code for file-upload scenarios. --- # November 4, 2025 ## 2.7.0 **`(feat):`** Added Generation Metadata file to output --- # October 31, 2025 ## 2.6.0 **`(feat):`** Significant improvements to class/property/namespace tracking, collisions reduced. Generated snippets and examples are far more accurate. Resolved a case where files with duplicate names were clobbered. Implicit namespaces are consistent across .NET frameworks now. Eliminated unnecessary namespace and scoping in generated code. Significant fixes to generated code for Pagination scenarios. --- # October 24, 2025 ## 2.5.0 **`(feat):`** Generate section about forward-compatible enums in README.md --- # October 20, 2025 ## 2.4.4 **`(fix):`** When sending the HTTP request, allow the response to start processing before the entire body is read. --- # October 16, 2025 ## 2.4.3 **`(fix):`** Fix incomplete handling for boolean type. --- # October 9, 2025 ## 2.4.2 **`(fix):`** Enabled SSE and JSON streaming to deserialize OneOf the same as WebSockets can. Fixed minor nullability warnings. --- # October 7, 2025 ## 2.4.1 **`(fix):`** Fix nullability issues in generated code. --- # September 29, 2025 ## 2.3.1 **`(fix):`** Upgrade generator-cli dependency to fix local generation handling of .fernignore files. --- # September 26, 2025 ## 2.4.0 **`(internal):`** Bump IR to v60 ## 2.3.0 **`(feat):`** Add generator code to create clients for WebSocket APIs. --- # September 17, 2025 ## 2.2.0 **`(feat):`** Add support for custom sections in the README.md via `customSections` config option. --- # September 5, 2025 ## 2.1.16-rc0 **`(fix):`** Enable type disambiguation and renaming during code generation Permits the `examples` test fixtures to compile successfully --- # August 25, 2025 ## 2.1.15 **`(fix):`** Ensure dynamic snippet method calls can use literal values ## 2.1.14 **`(fix):`** Create link in README.MD file to the REFERENCE.MD file --- # August 19, 2025 ## 2.1.13 **`(fix):`** Ensure `experimental-fully-qualified-namespaces` to have 'global::' prefix. --- # August 18, 2025 ## 2.1.12 **`(fix):`** Add support for configuration 'experimental-fully-qualified-namespaces' to generate fully qualified typenames and namespaces. Add support for `experimental-dotnet-format` to have `dotnet format` reduce namespaces and namespace prefixes. (this can take a large amount of memory) This creates code that is much cleaner, and can easily support multiple endpoints with identical names in the generated code without name or namespace collisions. --- # August 11, 2025 ## 2.1.10 **`(fix):`** Generate reference.md file as long as there are some endpoints. ## 2.1.8 **`(fix):`** Idempotent headers are added to the headers in the request --- # August 4, 2025 ## 2.1.7 **`(fix):`** Improve generation so that all expected tests/samples correctly generate and compile. **`(fix):`** In `RawClient.cs` namespace references are prefixed with `global::` to ensure that the class works correctly when an explicit namespace and client class are used that could cause it to collide. **`(fix):`** Set csharpier version to `1.1.*` to avoid inadvertently picking up `1.0.3` which has an inconsistency in formatting. ## 2.1.6 **`(feat):`** Trigger release to use new version of CSharpier formatter --- # July 31, 2025 ## 2.1.5 **`(fix):`** Add test for RawClient.ts to test Query Parameter Escaping ## 2.1.4 **`(fix):`** ensure that query parameters are Uri encoded in RawClient.cs --- # July 29, 2025 ## 2.1.3 **`(fix):`** uses fully qualified class name `System.IO.Stream` for downloads ## 2.1.2 **`(feat):`** Generate methods to support FileDownload (returns a `Task`). Example: ```csharp var request = new FooAudioRequest { Format = Format.Wav, Song = "Happy Birthday" }; var stream = await client.Songs.CreateSongAsync(request); // copy the stream to a file using (var fileStream = new FileStream("song.wav", FileMode.Create, FileAccess.Write)) { await stream.CopyToAsync(fileStream); } ``` **`(feat):`** Generate streaming/SSE JSON responses (returns an `IAsyncEnumerable<...>`). Example: ```csharp var request = new FooRequest { Names = ["Bob", "Alice"] }; // iterate over the list of items returned await foreach( var item in client.People.CreatePeopleStreamingAsync(request)) { Console.WriteLine($"Text for {item.Name} : {item.Text}"); } ``` --- # July 23, 2025 ## 2.1.1 **`(fix):`** Ensures that clients that have no endpoints are not generated. --- # July 9, 2025 ## 2.1.0 **`(feat):`** Pass in custom pager context to the custom pager factory. The context contains the send request method, initial HTTP request, client options, and request options. SDK authors can improve their custom pagination implementation with this context available to them. ## 2.0.3 **`(fix):`** Mockserver tests were generated based on the endpoint name being tested. When multiple endpoints have the same name, they would override each other, resulting in only one of them being tested. Mockserver tests are now namespaced and written to the filesystem following the same structure as the generated endpoints are. **`(fix):`** Update the type referencing logic to take into account the current namespace, other namespaces, and more scenarios where it could conflicts. --- # June 27, 2025 ## 2.0.2 **`(fix):`** Improve auto-pagination logic to consider empty strings in response as null cursors and stop paging. --- # June 24, 2025 ## 2.0.1 **`(fix):`** Fix a bug where strings with special characters would not be properly escaped when converted to C# strings. --- # June 23, 2025 ## 2.0.0 **`(chore):`** The following configuration names have changed, but the old names will continue to work. * `experimental-enable-forward-compatible-enums` is now `enable-forward-compatible-enums` * `experimental-additional-properties` is now `additional-properties` **`(feat):`** This release changes the defaults for the following custom configuration in *generators.yml*. | Option | Before | Now | | --------------------------------- | ------- | ------- | | `additional-properties` | `false` | `true` | | `enable-forward-compatible-enums` | `false` | `true` | | `generate-mock-server-tests` | `false` | `true` | | `inline-path-parameters` | `false` | `true` | | `simplify-object-dictionaries` | `true` | `false` | | `use-discriminated-unions` | `false` | `true` | To avoid breaking changes, explicitly set the options above with the `Before` values in the `config` of your generator in *generators.yml*. --- # June 17, 2025 ## 1.18.1 **`(fix):`** Add `[Serializable]` attribute to generated schema, request, and error classes. This will make it easier for instances of these classes to be stored in places like `Exception.Data`. --- # June 5, 2025 ## 1.18.0 **`(feat):`** Add support for HTTP HEAD method ## 1.17.6 **`(fix):`** Fix generated pagination endpoints that include path parameters. --- # June 3, 2025 ## 1.17.5 **`(internal):`** Update the IR to v58. --- # May 16, 2025 ## 1.17.4 **`(fix):`** Mock the OAuth endpoint for the wire tests. --- # May 13, 2025 ## 1.17.3 **`(fix):`** Add support for the custom introduction setting in the generated README.md. --- # May 4, 2025 ## 1.17.1 **`(chore):`** Self hosted github user defaults to `fern-api[bot]`. ## 1.17.0 **`(feat):`** Added support for pushing to GitHub. --- # May 1, 2025 ## 1.17.2 **`(fix):`** Install the generator-cli at build time as a fallback if runtime installation fails. --- # April 23, 2025 ## 1.16.3 **`(feat):`** Upgrade Csharpier formatter to `1.*` for faster and better formatting. --- # April 22, 2025 ## 1.16.2 **`(feat):`** Add `root-client-class-access` configuration option to control the access modifier of the root client class. `root-client-class-access` defaults to `public`, but can be set to `internal` to make the root client class internal. **`(fix):`** Pin `csharpier` formatter to `0.*` to avoid breaking changes in the formatter. --- # April 11, 2025 ## 1.16.1 **`(feat):`** Make minor improvements to the ReadOnlyAdditionalProperties and AdditionalProperties properties for internal usage. --- # April 10, 2025 ## 1.16.0 **`(feat):`** Add read-only and writeable additional properties for request and response types. Example: ```csharp var request = new FooRequest { Id = "123", AdditionalProperties = { ["extra1"] = new { value = 42 }, ["extra2"] = DateTime.Now, ["extra3"] = 99 } }; var response = await client.Foo.CreateAsync(request); Dictionary jsonElements = response.AdditionalProperties.ToJsonElementDictionary(); Dictionary extra1 = jsonElements["extra1"].Deserialize>(); DateTime extra2 = jsonElements["extra2"].GetDateTime(); int extra3 = jsonElements["extra3"].GetInt32(); ``` To enable this feature, configure `experimental-additional-properties: true` in the `config` section of your C# generator in generators.yml. This will become the default in the future. --- # April 7, 2025 ## 1.15.14 **`(fix):`** Fix issue where read-only list properties wouldn't deserialize correctly. --- # April 1, 2025 ## 1.15.13 **`(chore):`** Mark `AdditionalProperties` property as experiment using XML docs. --- # March 31, 2025 ## 1.15.12 **`(fix):`** Fallback from `init` to `set` on .NET Framework & .NET Standard 2.0 for public and protected properties. This ensures the properties can be set on older TFMs without compilation errors. --- # March 25, 2025 ## 1.15.11 **`(chore):`** Restructure internal HTTP classes to allow for more granular Fern ignoring. --- # March 22, 2025 ## 1.15.10 **`(fix):`** Fix generated tests that fail because of types containing OneOf or ReadOnlyMemory properties. --- # March 21, 2025 ## 1.15.9 **`(fix):`** Significantly improve performance of the generator itself by asynchronously formatting snippets in parallel. For example, Square's SDK generates in less than 20 seconds as opposed to more than 3 minutes previously. ## 1.15.8 **`(fix):`** Fix issue where the `FileParameter` class was not generated in projects with gRPC/proto endpoints. --- # March 19, 2025 ## 1.15.6 **`(fix):`** Make tests pass that compare JSON strings regardless of how it is formatted by ignoring whitespace. ## 1.15.5 **`(fix):`** Fix issue where headers were shared across different client instantiations when they should maintain their own state. --- # March 18, 2025 ## 1.15.4 **`(feat):`** Make `FileParameter` disposable. ## 1.15.3 **`(fix):`** Fix multipart form tests and add charset tests for multipart form tests. ## 1.15.2 **`(fix):`** Fix a compilation error when using typed idempotency headers. --- # March 17, 2025 ## 1.15.1 **`(fix):`** If a Content-Type header does not include charset, make sure the charset is also not included in the HTTP request. ## 1.15.0 **`(feat):`** Add `AdditionalHeaders` to client and request options. This lets users add and override headers for each request. --- # March 14, 2025 ## 1.14.3 **`(fix):`** Escape summary node contents in XML doc comments to prevent XML parsing errors. --- # March 13, 2025 ## 1.14.2 **`(fix):`** Fix issue a NullReferenceException for generated root clients with typed headers in client options. ## 1.14.1 **`(fix):`** Fix issue where a type is written but conflicts with the namespace it is written in. ## 1.14.0 **`(feat):`** The SDK now supports the `AdditionalBodyProperties` and `AdditionalQueryParameters` request options, which can be used to add arbitrary properties to the request. This is useful for interacting with alpha or undocumented functionality. ```csharp var response = await client.Users.Create( ..., new RequestOptions { AdditionalBodyProperties = new Dictionary { { "key", "value" } }, } ); ``` ## 1.13.2 **`(fix):`** Fix issue where MultipartFormTests wouldn't pass because the timezone on the local machine is different than the timezone on the CI machine. ## 1.13.1 **`(fix):`** Forward compatible enums has a static method `Custom(string value)` that allows you to create a new instance of the enum with a custom value. "Custom" is a commonly used enum value, and we want to avoid conflicts with the static method, so we're renaming the static method to `FromCustom(string value)`. This feature is gated behind the `experimental-enable-forward-compatible-enums` configuration option, so we're accepting this as a breaking change without a major version bump. **`(feat):`** Forward compatible enums can be explicitly casted from and to strings. ```csharp string myEnumAsString = (string)MyEnum.Enum1; MyEnum myEnum = (MyEnum)"custom-value"; ``` Note: We're not supporting implicit casts here because it could lead to behavior the user doesn't expect. ## 1.13.0 **`(feat):`** Add support for multipartform requests with file and non-file parameters. This is useful when you want to send a file along with other form data in a single request. For example, you can use the following code to upload a file with a description and some metadata: ```csharp await client.UploadAsync( new UploadRequest { File = new FileParameter { Stream = fileStream, FileName = "file.txt" }, Description = "This is a test file", Meta = new Meta { Key1 = "value1", Key2 = "value2" } } ); ``` --- # March 10, 2025 ## 1.12.0-rc18 **`(fix):`** Make the behavior between a wrapped request with body properties and normal body request consistent. Previously, a wrapped request with body properties would not omit `null` values even if the JSON configuration is configured to omit `null` values. **`(fix):`** Fix a bug where required properties that were `[JsonIgnore]` threw an error during serialization. **`(feat):`** Improve performance of query string value to string conversion by relying less on `JsonSerializer` and more on `ToString()`. --- # March 9, 2025 ## 1.12.0-rc17 **`(fix):`** Generate snippets for unions when `use-discriminated-unions` is `true` in the generator configuration. ## 1.12.0-rc16 **`(fix):`** Remove hardcoded namespace import from JsonElementComparer.cs ## 1.12.0-rc15 **`(feat):`** Generate **discriminated unions** with: * Type safety with compile-time checking * Exhaustive discriminant value matching * JSON serialization support Here's a simple example how to use a shape discriminated union: ```csharp var shape = new Shape(new Circle { Radius = 5 }); // Type checking if (shape.IsCircle) { Console.WriteLine($"Radius: {circle.AsCircle().Radius}"); } // Discriminant value matching var area = shape.Match( circle => Math.PI * circle.Radius * circle.Radius, square => square.Length * square.Length, (type, _) => throw new NotSupportedException($"Unknown: {type}") ); // TryAs pattern if (shape.TryAsCircle(out var circle)) { Console.WriteLine($"Radius: {circle.Radius}"); } ``` This feature is off by default for backward compatibility. To enable it, set `use-discriminated-unions` to `true` in the generator configuration. **`(feat):`** Improved serialization tests for generated classes for normal objects and discriminated unions. **`(feat):`** Generated classes now follow the C# convention for odering consts, fields, constructors, properties, methods, operators, and inner classes. --- # March 7, 2025 ## 1.12.0-rc14 **`(feat):`** Add support for overriding literal global headers via the `ClientOptions` class. ## 1.12.0-rc13 **`(feat):`** Add support for receiving additional properties in object types with the new `AdditionalProperties` field. This is useful when you want to parse an object that has properties that are not available in the SDK (e.g. alpha and/or undocumented properties). ```csharp // Call the endpoint. var response = await client.GetUser(...); // Print the additional properties. Console.WriteLine(response.AdditionalProperties); ``` --- # March 5, 2025 ## 1.12.0-rc12 **`(fix):`** Don't rely on the `FluentAssertions.Json` package to test serialization and deserialization. --- # March 4, 2025 ## 1.12.0-rc11 **`(internal):`** Update the IR to v57. ## 1.12.0-rc10 **`(feat):`** Compare .NET objects instead of JSON strings when comparing objects in mock wire tests. With this change, we can remove the dependency on the FluentAssertions.Json package (and implicitly on the Newtonsoft.Json package). **`(chore):`** Update dependencies in generated test project: * `Microsoft.NET.Test.Sdk`: 17.12.0 => 17.13.0 * `NUnit`: 4.2.2 => 4.3.2 * `NUnit3TestAdapter`: 4.6.0 => 5.0.0 * `NUnit.Analyzers`: 4.4.0 => 4.6.0 * `coverlet.collector`: 6.0.2 => 6.0.4 * `WireMock.Net`: 1.6.8 => 1.7.4 **`(fix):`** Compare .NET objects instead of JSON strings when comparing objects in mock wire tests, which fixes bugs where JSON deserialization and serialization would cause differences in the JSON strings. --- # March 3, 2025 ## 1.12.0-rc9 **`(fix):`** Fix inline path parameters with pagination endpoints. ## 1.12.0-rc8 **`(feat):`** Several class names are computed differently: * Environment class name: * Use `environment-class-name` if configured, * otherwise, fall back to `exported-client-class-name` if configured, with `Environment` suffix, * otherwise, fall back to `client-class-name` if configured, with `Environment` suffix, * otherwise, fall back to the computed client name, with `Environment` suffix. * Base exception class name: * Use `base-exception-class-name` if configured, * otherwise, fall back to `exported-client-class-name` if configured, with `Exception` suffix, * otherwise, fall back to `client-class-name` if configured, with `Exception` suffix, * otherwise, fall back to the computed client name, with `Exception` suffix. * Base API exception class name: * Use `base-api-exception-class-name` if configured, * otherwise, fall back to `exported-client-class-name` if configured, with `ApiException` suffix, * otherwise, fall back to `client-class-name` if configured, with `ApiException` suffix, * otherwise, fall back to the computed client name, with `ApiException` suffix. ## 1.12.0-rc7 **`(internal):`** Move exception handler into client options as an internal property for SDK authors to configure. ## 1.12.0-rc6 **`(fix):`** Fix bug where a lambda for sending HTTP requests would use the HTTP request from the outer scope instead of the local scope. ## 1.12.0-rc5 **`(fix):`** Fix hardcoded namespace for Pager.cs ## 1.12.0-rc4 **`(feat):`** Add .editorconfig file to the generated SDK. --- # March 2, 2025 ## 1.12.0-rc3 **`(feat):`** Add support for schema properties with write-only and read-only access. **`(feat):`** The JSON serializer will write with indentation during debugging, and without in production. ## 1.12.0-rc2 **`(feat):`** Pager and BiPager now have consistent properties and methods. As part of this change, pagers are now generated asynchronously which is a breaking change for the endpoint methods. ```csharp // Before: var pager = client.GetItemsAsync(...); // After: var pager = await client.GetItemsAsync(...); ``` **`(fix):`** Fixed an issue where generated code for setting UUIDs in a query string parameter would generate uncompilable code. **`(feat):`** Extend support for offset pagination to float, double, and decimal types. ## 1.12.0-rc1 **`(feat):`** Add support for the `include-exception-handler` configuration option, which generates an `ExceptionHandler` interface for the SDK. This is useful when you want to act upon all exceptions thrown by the SDK (e.g. report them to a monitoring service). You can configure this feature with the following: ```yaml --- # generators.yml - name: fern-api/fern-csharp-sdk version: 1.12.0-rc1 config: include-exception-handler: true ``` **`(fix):`** Fixes a regression for mapping `ReadOnlyMemory` values in the generated Protobuf mapper. --- # February 28, 2025 ## 1.12.0-rc0 **`(feat):`** Add support for custom pagination. --- # February 27, 2025 ## 1.11.0 **`(feat):`** Add support for the `inline-path-parameters` configuration option, which generates path parameters in the generated request type (if any) instead of as separate positional parameters. ```yaml --- # generators.yml - name: fern-api/fern-csharp-sdk version: 1.11.0 config: inline-path-parameters: true ``` **`(fix):`** Fix an issue where the `JsonIgnore` attribute was not included for query parameter or header properties. ## 1.10.1 **`(internal):`** Update the IR to v55. --- # February 26, 2025 ## 1.10.0 **`(feat):`** Add support for `exported-client-class-name` to allow you to export the client class name. This is useful when you want to use a custom client class name for code snippets. --- # February 24, 2025 ## 1.9.33 **`(fix):`** Upload C# snippets to the registry. ## 1.9.32 **`(fix):`** JSON serialize `DateOnly` to `yyyy-MM-dd` format. **`(internal):`** Add test for serializing and deserializing `DateOnly` abd `DateTime`. --- # February 15, 2025 ## 1.9.31 **`(fix):`** Use `global::System` instead of `System` to avoid conflicts when a type named `System` exists in the current namespace. ## 1.9.30 **`(fix):`** The Protobuf enum mapper now handles every enum variant. ## 1.9.29 **`(fix):`** The Protobuf package aliases now include the package name to avoid conflicts when multiple Protobuf packages are used. For example, `com.acme.users.v1` would be aliased as `ProtoUsersV1` instead of just `Proto`. ## 1.9.28 **`(fix):`** Fix the Protobuf mappers for the google.protobuf.Any type. **`(fix):`** The Protobuf mappers now refer to the original name of the Protobuf type instead of the PascalCase name. --- # February 14, 2025 ## 1.9.27 **`(fix):`** Fix the Protobuf mappers for enum and timestamp types. ## 1.9.26 **`(fix):`** Use `global::System.Type` instead of `System.Type` in `OneOfSerializer` when a type named `System` exists in the current namespace. ## 1.9.25 **`(fix):`** Use `global::System.Type` instead of `System.Type` in generated code to avoid potential naming conflicts when a type named `System` exists in the current namespace. ## 1.9.24 **`(fix):`** Use the original gRPC service name in the generated client reference instead of applying any casing transformations. ## 1.9.23 **`(fix):`** Fix method return types to use unqualified `Task` instead of `System.Threading.Tasks.Task` when the method returns a response. ## 1.9.22 **`(feat):`** Generate a pagination section to the generated README.md file. **`(feat):`** You can now `foreach(var item in page)` on `Page` instances. --- # February 6, 2025 ## 1.9.21 **`(fix):`** Support literals in query parameters and headers. For example, if a field in a wrapped request has a literal value of "foo", we will now set that value as the default value for the field. Note that wrapped requests are just a bag of properties that include body properties. ## 1.9.20 **`(fix):`** Support literals in wrapped requests (). For example, if a field in a wrapped request has a literal value of "foo", we will now set that value as the default value for the field. Note that wrapped requests are just a bag of properties that include body properties. ## 1.9.19 **`(fix):`** Fix serialization of enum path parameters. Previously, enum path parameters were serialized using their C# enum name, but now they are correctly serialized using their wire value. ## 1.9.18 **`(fix):`** Fix serialization of enum path parameters. Previously, enum path parameters were serialized using their C# enum name, but now they are correctly serialized using their wire value. ## 1.9.17 **`(fix):`** Support required literals. For example, if a field has a literal value of "foo", we will now set that value as the default value for the field. ## 1.9.16 **`(fix):`** Required client parameters that are headers are now sent when making API requests. For example if a bearer token is required to instantiate the client, we will ensure that it is sent when making API requests. ## 1.9.15 **`(fix):`** Change unpaged endpoints from internal to private to avoid ambiguous references in test projects who have access to internals. **`(fix):`** Fix an issue where enum values named `Equals` would always have be converted to `"Equals"` instead of their correct wire value. **`(feat):`** Increase test performance by parallelizing tests and setting HTTP request retry delay to 0. --- # February 3, 2025 ## 1.9.14 **`(fix):`** Add support for nullable undiscriminated unions (`OneOf?`), and add tests for undiscriminated unions. --- # February 2, 2025 ## 1.9.13 **`(internal):`** Miscellaneous improvement for the C# generator * Call `.ConfigureAwait(false)` on Tasks * Use `Enumerable.Empty` instead of creating a new empty list * Add PolySharp to test project and use C# 12 * Remove redundant `#nullable enable` directives * Improve C# syntax --- # January 22, 2025 ## 1.9.12 **`(fix):`** Change serialization logic for headers and querystring parameters: * Strings, enums, dates, times, and date times are serialized as before. * Booleans are now serialized as `true` and `false` instead of `True` and `False`. * Objects, lists, maps, dictionaries, undiscriminated, and discriminated unions are serialized to JSON. **`(fix):`** Only use `.Value` on nullable structs when serializing parameters to headers and querystring parameters. --- # November 25, 2024 ## 1.9.11 **`(feat):`** Add two dependencies who previously were transitive dependencies to ensure the generated SDKs use the patched versions without vulnerabilities. * `System.Net.Http` >= `4.3.4` * `System.Text.RegularExpressions` >= `4.3.1` Update other dependencies to the latest version: * `Portable.System.DateTimeOnly` = `8.0.2` (on net462 & netstandard2.0) * `PolySharp` = `1.15.0` * `OneOf` = `3.0.271` * `OneOf.Extended` = `3.0.271` --- # November 20, 2024 ## 1.9.10 **`(feat):`** Add partial `JsonOptions.ConfigureJsonSerializerOptions` method to allow SDK maintainers to configure the `JsonSerializerOptions` used by the SDK. --- # November 19, 2024 ## 1.9.9 **`(feat):`** Add support for [Auto Pagination](https://buildwithfern.com/learn/sdks/features/auto-pagination). When enabled, the endpoint methods will return a `Pager` object that you can use to iterate over all items of an endpoint. Additionally, you can use the `Pager.AsPagesAsync` method to iterate over all pages of an endpoint. The SDK will automatically make the necessary HTTP requests for you as you iterate over the items or the pages. --- # November 14, 2024 ## 1.9.8 **`(feat):`** Add support for [idempotency headers](https://buildwithfern.com/learn/sdks/capabilities/idempotency-headers). --- # November 12, 2024 ## 1.9.7 **`(feat):`** Set Content-Type header for HTTP requests when specified in the API spec/definition. --- # November 9, 2024 ## 1.9.6 **`(feat):`** Copy the csproj Version as the AssemblyVersion and FileVersion. ## 1.9.5 **`(feat):`** Copy the csproj Version as the AssemblyVersion and FileVersion. --- # November 8, 2024 ## 1.9.4 **`(feat):`** Generate a ProjectName.Test.Custom.props file for you to configure any MSBuild properties for your test project. **`(feat):`** Only import ProjectName.Custom.props and ProjectName.Test.Custom.props if the file exists, so you can delete the file if you wish to. **`(fix):`** Do not re-import the .NET SDK inside of ProjectName.Custom.props. --- # November 7, 2024 ## 1.9.3 **`(feat):`** Generate a ProjectName.Custom.props file for you to configure any MSBuild properties for your project. **`(fix):`** Generate the license NuGet properties inside the .csproj file correctly. --- # November 6, 2024 ## 1.9.1 **`(chore):`** Update `System.Text.Json` dependency from `8.0.4` to `8.0.5` because a security patch was released to resolve [this vulnerability](https://github.com/advisories/GHSA-8g4q-xg66-9fp4). --- # November 5, 2024 ## 1.9.0 **`(feat):`** Add support for calling HTTP endpoints and gRPC endpoints within the same service. --- # October 30, 2024 ## 1.8.5 **`(feat):`** Add forward-compatible enums. Set `experimental-enable-forward-compatible-enums` to `true` in the configuration to generate forward-compatible enums. With forward-compatible enums you can create and parse an enum value that is not predefined. * Forward compatible enums are not compatible with the previously generated native enums. This is a breaking change for the users of the generated SDK, but only users using switch-case statements are affected. * Use the `Value` property to get the string value of the enum. - For each value in the enum, * a public static property is generated, which is an instance of the enum class, * a public static property is generated within the nested `Values` class with the string value of the enum. Here's a before and after for creating and parsing a resource with a predefined enum value and a custom enum value: **Before**: ``csharp var resource = client.CreateResource(new Resource { Id = "2", EnumProperty = MyEnum.Value2 } ); // The line below does not compile because the enum does not have a `Value3` value. // resource = client.CreateResource(new Resource { Id = "3", EnumProperty = MyEnum.Value3 } ); resource = client.GetResource("3"); switch(resource.EnumProperty) { case MyEnum.Value1: Console.WriteLine("Value1"); break; case MyEnum.Value2: Console.WriteLine("Value2"); break; default: // this will never be reached until the SDK is updated with the new enum value Console.WriteLine("Unknown"); break; } if(resource.EnumProperty == MyEnum.Value1) { Console.WriteLine("Value1"); } else if (resource.EnumProperty == MyEnum.Value2) { Console.WriteLine("Value2"); } else { // this will never be reached until the SDK is updated with the new enum value Console.WriteLine("Unknown"); } `` No exception is thrown, but the output incorrectly shows `Value1` because .NET falls back to the first value in the enum. **After**: ````csharp var resource = client.CreateResource(new Resource { Id = "2", EnumProperty = MyEnum.Value2 } ); resource = client.CreateResource(new Resource { Id = "3", EnumProperty = MyEnum.Custom("value3") } ); resource = client.GetResource("3"); switch(resource.EnumProperty.Value) { case MyEnum.Values.Value1: Console.WriteLine("Value1"); break; case MyEnum.Values.Value2: Console.WriteLine("Value2"); break; default: Console.WriteLine(resource.EnumProperty.Value); break; } if(resource.EnumProperty == MyEnum.Value1) { Console.WriteLine("Value1"); } else if (resource.EnumProperty == MyEnum.Value2) { Console.WriteLine("Value2"); } else { Console.WriteLine(resource.EnumProperty.Value); } ``` The output correctly shows `Value3`. ```` --- # October 28, 2024 ## 1.8.4 **`(fix):`** Make sure summary and code examples in XML code comments are XML encoded. ## 1.8.3 **`(fix):`** Update generated .gitignore files to not ignore C# files inside of folders named Logs and Releases. ## 1.8.2 **`(fix):`** Fixes a bug where the ClientOptions would not compile due to incorrect Clone method generation. --- # October 8, 2024 ## 1.8.1 **`(fix):`** Fixes a bug where the `OauthTokenProvider.cs` was incorrectly referencing the endpoint method, causing code to fail to compile. --- # August 29, 2024 ## 1.8.0 **`(feat):`** Adds support for Client Credentials OAuth with token refresh. Now you can instantiate your SDK by passing in clientId and clientSecret, and let fern handle retrieving and refreshing the token. ```cs var client = new ImdbClient("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET"); await client.doThing(); ``` ## 1.7.0 **`(feat):`** Add support for generated `reference.md` files. ## 1.6.0 **`(feat):`** Add support for generated `README.md` files. --- # August 28, 2024 ## 1.5.0 **`(feat):`** Add support for service-level headers. **`(feat):`** Generate `snippet.json` file containing usage snippets for each endpoint. **`(feat):`** Apply the timeout configured on the `ClientOptions` and `RequestOptions` type. **`(feat):`** Add exponential backoff retrier, which acts upon `MaxRetries` configuration option specified on the `ClientOptions` and `RequestOptions`. **`(feat):`** Generate the `RawClientTests.cs` file which includes retry logic tests. **`(internal):`** Refactor the `RawClient` with additional helper methods so that it's easier to follow. **`(fix):`** Fix a bug where `OneOf` used directly as request or response types fail serialization. --- # August 26, 2024 ## 1.4.0 **`(internal):`** Generate a `Version` class which is used to reference the current version. --- # August 22, 2024 ## 1.3.0 **`(internal):`** No changes. ## 1.3.0-rc2 **`(internal):`** Fix warnings in generated `RawClient`. **`(internal):`** Use a simpler primitive instantiation for the various number types. ## 1.3.0-rc1 **`(feat):`** Generate the `ToString` method to write the JSON format of an object. **`(feat):`** Generate snippets as example documentation. ## 1.3.0-rc0 **`(feat):`** Add support for sending the `User-Agent` header. **`(internal):`** The `RawClient` now supports HTTP headers within the `ClientOptions` and `RequestOptions` types. **`(feat):`** Add support for the `package-id` configuration, which is used to control the name of the package in NuGet. **`(feat):`** Add support for mock server tests with `generate-mock-server-tests` configuration option. **`(internal):`** Omit `null` property values in requests. **`(fix):`** Fix a bug where request bodies are not sent for wrapped requests that include headers or query params. **`(fix):`** Fix a bug where enums, dates, and datetimes are sometimes not serialized properly as query parameters and headers. **`(feat):`** Add support for `read-only-memory-types` configuration. **`(feat):`** Add the `CancellationToken` parameter as the last parameter to every endpoint method. **`(feat):`** Add support for gRPC/Protobuf endpoints. --- # August 12, 2024 ## 1.2.1 **`(feat):`** Add support for Protobuf file dependencies to generate gRPC client stubs. **`(fix):`** Fix potential namespace and type conflicts. --- # August 11, 2024 ## 1.1.0 **`(fix):`** Error strings are correctly mapped to an appropriate exception. ## 1.0.0 **`(break):`** The C# SDK is now on major version 1.0.0. To preserve compatibility with pre-1.0.0, set all of `{root-namespace-for-core-classes, pascal-case-environments, simplify-object-dictionaries}` to `false`. **`(internal):`** Core classes that are exposed publicly are now in the root namespace. **`(internal):`** Types that were previously generated as `Dictionary` are now just `object`. **`(internal):`** Environment names are pascal-cased. **`(feat):`** Generating specific error types can now be turned off with the `generate-error-types` configuration. --- # August 10, 2024 ## 0.12.0 **`(feat):`** Get better Unit Testing JSON comparison results by using `FluentAssertions`. --- # August 9, 2024 ## 0.11.0 **`(internal):`** Mark internal files `internal`. **`(feat):`** Make all client classes `Partial`. **`(internal):`** Don't override `toString` on Exceptions. --- # August 7, 2024 ## 0.10.0 **`(fix):`** Fix a bug where conflicting class names and namespaces cause compile to fail. --- # August 1, 2024 ## 0.9.0 **`(feat):`** Add the `base-api-exception-class-name` and `base-exception-class-name` generator configuration. These control the class names of the generated `ApiException` and `Exception` class names. --- # July 31, 2024 ## 0.8.0 **`(feat):`** Support text response types. **`(feat):`** Support inheritance for inlined request bodies. ## 0.7.0 **`(feat):`** Generate Exception types for all errors defined in the IR. ## 0.6.0 **`(feat):`** Add support for `RequestOptions` allowing request-specific option overrides. --- # July 30, 2024 ## 0.5.0 **`(feat):`** Add support for `uint`, `ulong`, and `float` types. **`(internal):`** Bump to IRv53. ## 0.4.0 **`(feat):`** Add support for `allow-multiple` query parameters. **`(feat):`** Generate `map` types as `Dictionary` to support explicit `null` values. ## 0.3.4 **`(internal):`** Make datetime deserialization more lenient and include milliseconds in serialization. ## 0.3.3 **`(internal):`** Generate types with `set` accessors instead of `init` to improve object construction flexibility. --- # July 29, 2024 ## 0.3.2 **`(feat):`** The C# generator now supports configuration to match namespaces to file paths. --- # July 25, 2024 ## 0.3.1 **`(internal):`** Add header suppliers to `RawClient` constructor parameters. ## 0.3.0 **`(break):`** Convert all usages of `Guid` to `string` to avoid casing issues. ## 0.2.1 **`(fix):`** Fix Multi URL environment classes compilation issue. ## 0.2.0 **`(break):`** Rename `Environments.cs` to `{OrgName}Environment`. **`(feat):`** Generate classes for environments with different endpoint URLs. --- # July 23, 2024 ## 0.1.4 **`(internal):`** More improvements to datetime serialization. --- # July 22, 2024 ## 0.1.3 **`(fix):`** Fixed a bug with serializing datetimes. **`(internal):`** Stop generating empty serialization unit test files when there are no examples. --- # July 17, 2024 ## 0.1.2 **`(chore):`** Bump IR to 51. **`(feat):`** Generate serialization unit tests for models and add a GH workflow to run them. --- # July 10, 2024 ## 0.1.1 **`(internal):`** Enable generating unions with up to 32 types by adding the OneOf.Extended package. **`(fix):`** Handle double optional fields properly with a single `?`. --- # July 9, 2024 ## 0.1.0 **`(feat):`** Add targets for .NET Standard 2.0 and .NET Framework 4.6.2. **`(fix):`** Avoid duplicate key errors in `StringEnumSerializer`. **`(fix):`** Fix bugs with root client requests causing generation failures. **`(fix):`** Correctly handle environment values and literal header names. **`(internal):`** Improve constructor parameters and other minor fixes. --- # July 2, 2024 ## 0.0.35 **`(fix):`** Ensure base client requests are generated correctly. ## 0.0.34 **`(fix):`** Implement base client methods instead of leaving them empty. --- # June 21, 2024 ## 0.0.33 **`(feat):`** Add support for specifying extra dependencies in the C# generator configuration. ## 0.0.32 **`(fix):`** Ensure enum values are JSON serialized before being sent to the server. ## 0.0.31 **`(fix):`** Ensure the HTTP client joins endpoint path with the base URL safely. --- # June 20, 2024 ## 0.0.30 **`(fix):`** The SDK now supports making requests with a Content-Type of `application/octet-stream` for byte data. **`(fix):`** The SDK now safely handles API-wide path parameters, including their proper joining in `RawClient.cs`. ## 0.0.29 **`(fix):`** The generated SDK now correctly respects service base paths, which were previously omitted. ## 0.0.25 **`(feat):`** Discriminated unions are now generated as object. **`(feat):`** Header parameters are no longer required in the constructor, eliminating the need for users to provide redundant information. --- # June 19, 2024 ## 0.0.28 **`(fix):`** Query and header parameters with optional datetimes are now encoded in ISO 8601 format before making requests. ## 0.0.24 **`(fix):`** Query and header parameters are now ISO 8601 encoded before making requests. --- # June 7, 2024 ## 0.0.23 **`(feat):`** The SDK is now compatible exclusively with .NET 6. This change reflects significant code adjustments needed for .NET 4+ compatibility. ## 0.0.22 **`(feat):`** The SDK now includes support for .NET 4. --- # May 31, 2024 ## 0.0.21 **`(fix):`** Array and list fields are now generated as `IEnumerable`. --- # May 29, 2024 ## 0.0.20 **`(internal):`** Enum serializers are now added directly to enum declarations. **`(internal):`** OneOf serializers are now added as a core class. ## 0.0.19 **`(fix):`** Enum serializers now handle reading and writing enum string values. **`(fix):`** Non-success status code errors are now thrown with the stringified response body. --- # May 28, 2024 ## 0.0.18 **`(internal):`** Generated GitHub workflows now run on dotnet-version 8.x. ## 0.0.17 **`(feat):`** Enabled nullable on all C# files. **`(feat):`** Made project compatible with .NET 6, .NET 7, and .NET 8. --- # May 23, 2024 ## 0.0.16 **`(fix):`** Miscellaneous fixes. ### What's been fixed * .csproj indentation * Setting X-Fern-SDK-Name to the top-level namespace * Passing through serializer options when serializing JSON messages ## 0.0.15 **`(fix):`** Inlined requests that are strictly bodies are JSON serializable. ## 0.0.14 **`(feat):`** The SDK now includes a `JsonEnumMemberStringEnumConverter`. --- # May 22, 2024 ## 0.0.13 **`(feat):`** If a LICENSE is specified, the generator now packages the license in the .csproj file. ## 0.0.12 **`(feat):`** The C# generator now generates an `Environments.cs` file containing URLs for different environments. --- # May 20, 2024 ## 0.0.11 **`(feat):`** The C# generator now generates a proper `.csproj` file with version, GitHub URL, and a reference to the SDK README. --- # May 15, 2024 ## 0.0.10 **`(feat):`** The generated SDK now publishes GitHub Actions to build and publish the generated package to NuGet. --- # May 10, 2024 ## 0.0.9 **`(fix):`** When an inlined request body is entirely made up of request body properties, the entire request can now be serialized as the request body. ## 0.0.8 **`(fix):`** Several bug fixes. ### What's new * Support for arbitrary nested clients * Query parameter serialization ### What's changed * Property naming for async methods * Properly formatted solution files --- # PHP quickstart > Get started quickly with the Fern PHP SDK. Generate a PHP SDK by following the instructions on this page. This page assumes that you have: * An initialized `fern` folder. See [Set up the `fern` folder](/sdks/overview/quickstart). * A GitHub repository for your SDK. See [Project Structure](/sdks/overview/project-structure). ### Pass `fern check` Run `fern check` to ensure that your API definition is valid. If there are any errors, fix them before proceeding. If you're using an OpenAPI Specification, check out all of our [supported extensions](/learn/api-definition/openapi/extensions). ### Add the SDK generator Run the following command to add the PHP SDK generator to `generators.yml`: ```bash fern add fern-php-sdk --group php-sdk ``` `php-sdk` is the name of the `generators.yml` group that configures your PHP SDK's output location and other metadata. You can customize this group name to differentiate between multiple SDKs across different languages (e.g., `ruby-sdk`, etc) in your organization. This command adds the following `group` to `generators.yml`: ```yaml title="generators.yml" php-sdk: # group name generators: - name: fernapi/fern-php-sdk version: 1.25.3 output: location: local-file-system path: ../sdks/php/sdk ``` ### Generate the SDK Run the following command to generate your SDK: ```bash fern generate --group php-sdk ``` If you have multiple APIs, use the [`--api` flag](/cli-api-reference/cli-reference/commands#api) to specify the API you want to generate: ```bash fern generate --group php-sdk --api your-api-name ``` This creates a `sdks` folder in your current directory. The resulting folder structure looks like this: --- # PHP configuration > Configure your PHP SDK generator with Fern. Customize client names, namespaces, package settings, and composer.json for PHP client libraries. You can customize the behavior of the PHP SDK generator in `generators.yml`: ```yaml {7-8} title="generators.yml" groups: php-sdk: generators: - name: fernapi/fern-php version: 1.25.3 config: clientName: YourClientName ``` ## SDK configuration options Sets the name of the generated API client class. This determines the primary client type name that users will interact with in the generated PHP SDK. Allows customization of the generated `composer.json` file contents. You can specify additional metadata, dependencies, or configuration that will be merged into the package's composer configuration file. When enabled, generates [mock server (wire) tests](/sdks/deep-dives/testing#mock-server-tests) to verify that the SDK sends and receives HTTP requests as expected. When enabled, path parameters are included as properties in the request class instead of being passed as separate method parameters. This creates a more unified request structure where all parameters are grouped together in the request object. Specifies the PHP namespace for all generated code. This determines the namespace hierarchy that users will use when importing and using the SDK classes. Sets the name of the PHP package as it will appear in Composer and Packagist. This is the name users will use to install the SDK via Composer (e.g., `composer require your/package-name`). Specifies the directory path where the generated SDK source files should be placed. This determines the file system location of the generated PHP code relative to the output directory. Controls the access level of generated class properties. When set to 'public', properties are public and getter/setter methods are omitted. When set to 'private', properties are private and getter/setter methods are generated for encapsulation. --- # Publishing to Packagist > How to publish the Fern PHP SDK to Packagist. Publish your public-facing Fern PHP SDK to the [Packagist registry](https://packagist.org/). After following the steps on this page, you'll have a versioned package published on Packagist. Versioned package published on Packagist This page assumes that you have: * An initialized `fern` folder. See [Set up the `fern` folder](/sdks/overview/quickstart). * A GitHub repository for your SDK. See [Project Structure](/sdks/overview/project-structure). ## Configure `generators.yml` PHP publishes via Git repositories, so remove the auto-generated `output`, `location`, and `path` fields. Instead, add the path to your GitHub repository: ```yaml {6-7} groups: php-sdk: generators: - name: fernapi/fern-php-sdk version: 4.23.2 github: repository: your-org/company-php ``` ## Set up Packagist publishing authentication Log into [Packagist](https://packagist.org/login/) or [create an account with Packagist](https://packagist.org/register/). 1. Click **Submit**. 2. Input the full URL of the repository where you generated your PHP SDK, then click **Check**. 3. Fix any errors Packagist finds in your repository, then click **Submit**. Submit Package Screen in Packagist Once you've submitted your URL, you'll be prompted to set up the GitHub Hook. 1. In to your repository, go to **Settings > Webhooks**. 2. Select **"Add webhook"** 3. Set the Payload URL as `https://packagist.org/api/github?username=` 4. Set the content type as `application/json` 5. Packagist autogenerates API Tokens. To find yours, go to your **Profile**. Then, add your token to the **Secret** field. 6. Set the trigger events as **Just the `push` event** 7. Click **"Add Webhook"** GitHub Webhook for Packagist ## Release your SDK to Packagist At this point, you're ready to regenerate your SDK and publish it on Packagist: ```bash fern generate --group php-sdk --version ``` Local machine output will verify that the release is pushed to your repository and tagged with the version you specified. Log back into Packagist, click on your username, and select **My packages** to see your new release. --- # Adding custom code > Learn how to add custom logic, methods, and dependencies to your PHP SDK. Step-by-step guide to extending Fern-generated PHP clients. This page covers how to add custom logic, methods, and dependencies to your PHP SDK. Before getting started, [read about how Fern SDKs use custom code and learn about the `.fernignore` file](/sdks/overview/custom-code) . ## Adding custom logic To get started adding custom code: ```php title="src/Helper.php" ```yaml {3} title=".fernignore" # Specify files that shouldn't be modified by Fern src/Helper.php ``` Now your users can consume the helper function by importing it from the SDK. ```php ## Adding custom SDK methods Fern also allows you to add custom methods to the SDK itself (e.g. `client.my_method()` ) by inheriting the Fern generated client and then extending it. Name your Fern-generated client something like `BaseClient` to reflect that this client will be extended. ```yaml {4} title="generators.yml" - name: fernapi/fern-php-sdk version: 1.25.3 config: clientName: BaseClient ``` First, import the Fern generated base client and extend it. Then, add whatever methods you want. ```php title="src/MyClient.php" Add the `MyClient.php` to `.fernignore`. ```diff title=".fernignore" + src/MyClient.php ``` Instead of constructing the generated client, your users will want to construct the extended client. ```php myHelper(); ``` ## Adding custom dependencies To add packages that your custom code requires, update your `generators.yml` using the `composerJson` configuration option. ```yaml {4-8} title="generators.yml" - name: fernapi/fern-php-sdk version: 1.25.3 config: composerJson: require: guzzlehttp/guzzle: "^7.0" require-dev: phpunit/phpunit: "^10.0" ``` --- # January 26, 2026 ## 1.25.4 **`(fix):`** Fix wire tests to start and stop the mock server once for all tests instead of per test class. Previously, each test class would start and stop the WireMock container in setUpBeforeClass/tearDownAfterClass, causing the container to restart multiple times. Now uses a PHPUnit bootstrap file to manage the container lifecycle once for the entire test suite. --- # January 23, 2026 ## 1.25.3 **`(fix):`** Fix wire test generation for file upload endpoints. When file parameters are required but no example value is provided, the generator now creates a default file using `File::createFromString()` instead of omitting the field, which caused TypeError when assigning null to non-nullable File properties. --- # December 18, 2025 ## 1.25.2 **`(chore):`** Add sdkVersion as a top-level field in the generated metadata.json file. --- # December 9, 2025 ## 1.25.1 **`(fix):`** Fix OAuth and InferredAuth token refresh to work on every request. Previously, tokens were fetched once during client initialization and stored statically in headers, causing authentication failures when tokens expired for long-lived client instances. Now the auth provider's getToken()/getAuthHeaders() method is called on every request via a callback, properly refreshing tokens when needed. --- # December 3, 2025 ## 1.25.0 **`(feat):`** Add support for custom pagination in PHP SDK. The generator now handles custom pagination endpoints by generating a CustomPager class that users can extend to implement their own pagination logic. The CustomPager provides access to the initial response and client instance for making subsequent requests. The class name can be customized via the `custom-pager-classname` configuration option. ## 1.24.2 **`(fix):`** Fix php-cs-fixer creating .php-cs-fixer.dist.php config files in subdirectories during generation. The interactive prompt was causing config files with @auto ruleset to be created, which then failed when running from subdirectories without composer.json. Added --no-interaction flag to prevent this behavior. --- # December 2, 2025 ## 1.24.1 **`(fix):`** Fix getGitHubConfig to return RawGithubConfig with undefined values instead of throwing errors when publishing config is missing, aligning with TypeScript/Python generator behavior. --- # December 1, 2025 ## 1.24.0 **`(feat):`** Retries now check `Retry-After` and `X-RateLimit-Reset` response headers before defaulting to exponential backoff. Added jitter to retry delays and capped maximum retry delay at 60 seconds. ## 1.23.11 **`(chore):`** Remove verbose debug logs for endpoint snippet processing and generation counts. ## 1.23.10 **`(fix):`** Fix union deserialization to catch Throwable instead of Exception. Previously, when deserializing union types, TypeError exceptions thrown during property assignment (e.g., assigning null to a non-nullable int property) were not caught, preventing the union from trying alternative types. This fix ensures that all errors during union type deserialization are caught, allowing proper fallthrough to the next union variant. ## 1.23.9 **`(fix):`** Fix JsonException "No constructor found" for empty object types. Previously, object types with no properties would not generate a constructor, causing JSON deserialization to fail. Now all JsonSerializableType subclasses generate a constructor with the expected `array $values` parameter signature. ## 1.23.8 **`(fix):`** Normalize UTC datetime serialization to use Z suffix instead of +00:00. The JsonSerializer now converts `2023-01-01T12:34:56+00:00` to `2023-01-01T12:34:56Z` for UTC times while preserving RFC3339 format for non-UTC timezones. Query parameters and headers now use JsonSerializer::serializeDateTime() for consistent datetime formatting. Test templates updated to match the new behavior. --- # November 27, 2025 ## 1.23.7 **`(fix):`** Fix DateTime formatting for optional and nullable query parameters. Previously, optional and nullable DateTime query parameters were passed as raw DateTime objects to Guzzle HTTP client, causing request failures. The fix ensures that `Optional` and `Nullable` types are correctly identified and formatted using `.format()` method with proper date/datetime constants. ## 1.23.6 **`(fix):`** Fix wire tests to pass X-Test-Id header via method call options. Dynamic snippets now pass arbitrary headers from the snippet request as per-request options when generating calls on existing clients (skipClientInstantiation mode). This enables wire tests to properly correlate requests with WireMock verification. ## 1.23.5 **`(fix):`** Fix wire test environment parameter generation and inferred auth parameter handling. Wire tests now properly indent environment parameters and use Environments::custom() instead of raw arrays for type safety. Additionally, required inferred auth parameters no longer use unnecessary null coalescing operators (??), resolving PHPStan static analysis warnings. ## 1.23.4 **`(fix):`** Fix wire test generation for inferred auth by using getInferredAuth() explicitly. The previous fix relied on the visitor pattern which may not correctly identify inferred auth schemes in all cases. ## 1.23.3 **`(fix):`** Fix wire test generation for inferred auth. Wire tests now correctly pass the required auth parameters (e.g., apiKey) extracted from the token endpoint's request body and headers, matching the root client constructor signature. ## 1.23.2 **`(fix):`** Fix constructor signature mismatches in multi-URL environments. Subpackage clients now consistently use `isMultiUrl` to determine whether to accept `Environments` or `options` as the second constructor parameter, matching the root client's behavior. Also fixes OAuth and inferred auth client instantiation to pass the environment parameter when in multi-URL mode, and updates wire tests to extend `WireMockTestCase` and include auth parameters. --- # November 26, 2025 ## 1.23.1 **`(fix):`** Remove error on null config in README generation. ## 1.23.0 **`(feat):`** Add inferred auth support for PHP SDKs. The SDK now generates an InferredAuthProvider class that handles automatic token retrieval and caching with expiration handling. Root clients accept the token endpoint request parameters for inferred authentication. --- # November 25, 2025 ## 1.22.3 **`(fix):`** Fix dynamic snippets to properly handle custom URLs in multi-URL environments. Custom URLs now correctly generate `Environments::custom(...)` calls instead of failing with "Invalid multi url environment" error. ## 1.22.2 **`(fix):`** Add missing `` and `array`) would generate duplicate array annotations in PHP union types (array|array|null). The fix implements recursive union flattening with proper deduplication during type generation. --- # July 2, 2025 ## 1.16.4 **`(feat):`** Add documentation for using a custom client in the README. This makes it easier for our customers to visualize how they can override the default client. --- # July 1, 2025 ## 1.16.3 **`(feat):`** Add documentation for pagination in the README, this uses the AST to build some human readable example of how to use the pagination on the client results. --- # June 3, 2025 ## 1.16.2 **`(feat):`** Add documentation for retries and timeout parameters in the README, including examples of how to configure maxRetries and timeout options at the request level ## 1.16.1 **`(feat):`** Add exception handling documentation to README with examples of catching and handling API exceptions ## 1.16.0 **`(feat):`** Introduce initial version of README generation for the PHP SDK with Installation, Usage, and Contributing sections. ## 1.15.1 **`(internal):`** Update the IR to v58. --- # April 29, 2025 ## 0.15.0 **`(feat):`** Support custom package path --- # April 8, 2025 ## 0.14.2 **`(fix):`** This updates the PHP generator to better support undiscriminated unions that define one or more `optional` types. With this, the generator unwraps each of the optional types, and includes a `|null` variant (e.g. `array|Metadata|null`). --- # March 4, 2025 ## 0.14.1 **`(internal):`** Upgrade to IRv57. --- # February 13, 2025 ## 0.14.0 **`(feat):`** Support literal types ## 0.13.7 **`(fix):`** Make constructor private for union types and remove static unknown constructor ## 0.13.6 **`(fix):`** Fix an issue where the value field of the deserialized discriminated union was null. ## 0.13.5 **`(fix):`** Change discriminated union method name from `->getvalue()` to `->getValue()`. ## 0.13.4 **`(fix):`** Flatten test directory structure from `tests/package-name/**` to `tests/**` so it matches the psr-4 structure defined in composer.json. Without this change, you cannot reference classes within the `tests` directory from your tests, for example, a `Helpers` class for common test utilities. ## 0.13.3 **`(fix):`** Fix issue where an empty request would be JSON serialized as an empty array instead of an empty object. ## 0.13.2 **`(fix):`** Fix a bug where literal global headers could not be overridden in the root client constructor. ## 0.13.1 **`(fix):`** Render union references as their type references rather than mixed. ## 0.13.0 **`(feat):`** Add support for configuring a request timeout. **`(fix):`** Fix a bug where the private pagination method helpers collided with magic methods (e.g. `__get`). ## 0.12.0 **`(feat):`** Add support for discriminated unions. --- # February 12, 2025 ## 0.11.0 **`(feat):`** The SDK now supports a `bodyProperties` and `queryParameters` request option, which can be used to add arbitrary properties to the request. This is useful for interacting with alpha or undocumented functionality. ````php $response = $client->users->list( new ListUsersRequest([ ... ]), [ 'queryParameters' => [ 'limit' => 100, ], ] ); ``` ```` --- # February 11, 2025 ## 0.10.0 **`(feat):`** You can now modify the generated `composer.json` file by adding a `composerJson` property to your generator configuration. Here's an example of the `generators.yml` file with the `composerJson` property: ```yaml generators.yml ... groups: php-sdk: generators: - name: fernapi/fern-php-sdk ... config: composerJson: description: This is my PHP library keywords: - myCustomTag license: - "LGPL-2.1-only" - "GPL-3.0-or-later" scripts: hello: echo hello ``` Which will result in the following composer.json file: ````jsonc composer.json { // ..., "description": "This is my PHP library", "keywords": [ "myCustomTag", // ..., ], "license": [ "LGPL-2.1-only", "GPL-3.0-or-later" ], // ..., "scripts": { // ..., "hello": "echo hello" } } ``` ## 0.9.0 **`(feat):`** Add the ability to access alpha or undocumented response properties from every class. Users can access the additional properties like so: ```php $response = $client->users->get(...); $additionalProperties = $response->getAdditionalProperties(); ``` ## 0.8.0 **`(feat):`** Add automatic pagination support for endpoints that return a paginated response. Here's an example of how users can use paginated endpoints: ```php $items = $client->list($request); foreach($items as $item){ echo $item; } $pages = $items->getPages(); foreach($pages as $page){ foreach($page as $item){ echo $item; } } ``` ```` --- # February 9, 2025 ## 0.7.0 **`(feat):`** The SDK now supports inline path parameters in the generated request class like so: ````php class GetUserRequest extends JsonSerializableType { /** * @var string $userId */ public string $userId; } ``` You can configure this in your `generators.yml` like so: ```yaml - name: fernapi/fern-php-sdk version: 0.7.0 config: inlinePathParameters: true ```` ## 0.6.0 **`(feat):`** You can now configure the generated class property access to be `public` or `private`. * When the access is public, both the getter and setter methods are omitted (default). * When the access is private, both the getter and setter methods are generated. You can configure this in your `generators.yml` like so: ```yaml - name: fernapi/fern-php-sdk version: 0.6.0 config: propertyAccess: private ``` ## 0.5.2 **`(fix):`** Update the endpoint generator to not require the in-lined request wrapper if it's only composed of optional properties. **`(fix):`** Update optional query parameters lists to be generated as an optional array instead of an array of optional values. --- # February 7, 2025 ## 0.5.1 **`(fix):`** Catch HTTP request exceptions and rethrow it as a FooApiException. ## 0.5.0 **`(feat):`** Add the `__toString()` magic method to all generated class types. --- # February 5, 2025 ## 0.4.0 **`(feat):`** Retry HTTP requests on status codes 408, 429, 5XX. You can configure the maximum number of retries like this: `php $client = new FooClient("token", ['maxRetries' => 3]) $client->bar($request, ['maxRetries' => 5]); ` The default for `maxRetries` is 2, meaning up to 3 HTTP requests may be sent. Set `maxRetries` to 0 to disable retries. If you create your own HTTP client and pass it to the root client, you must add the desired middlewares yourself. Here's how you would add the `RetryMiddleware` to a custom HTTP client: `php $handlerStack = HandlerStack::create(); $handlerStack->push(RetryMiddleware::create()); $httpClient = new Client(['handler' => $handlerStack]); $client = new FooClient(['client' => $client]); ` ## 0.3.2 **`(internal):`** Upgrade to IRv55 to recognize nullable types. ## 0.3.1 **`(fix):`** Improve multiline parameter docs by writing them above the tag, e.g. ````php class UpdateUserRequest extends JsonSerializableType { /** * The user to update. * * See [User](https://acme.co/user) for more information. * * @var ?User $user */ public ?User $user; } ``` **`(fix):`** Add .idea to the generated .gitignore file. ```` --- # February 3, 2025 ## 0.3.0 **`(feat):`** Add support for customizing the package name, which is used in the `User-Agent` header. Users can configure this like so: ```yaml - name: fernapi/fern-php-sdk version: 0.3.0 config: packageName: acme/acme-php ``` ## 0.2.3 **`(fix):`** Updates a variety of properties in the generated composer.json file, including: * Pin guzzlehttp/guzzle to version ^7.4. * Custom license support. * Set `memory-limit` to 1G in the `analyze` script. --- # December 12, 2024 ## 0.2.2 **`(fix):`** Handle cross package type name deconfliction --- # November 20, 2024 ## 0.2.1 **`(fix):`** Override escaped method names in the generated client. --- # October 30, 2024 ## 0.2.0 **`(feat):`** Add support for multipart file uploads. --- # October 3, 2024 ## 0.1.4 **`(fix):`** Add `null` to annotations for optional undiscriminated unions. ## 0.1.3 **`(feat):`** Support inheritance for types and inlined requests. **`(feat):`** Support undiscriminated unions. **`(fix):`** Fix ci.yml `php-version` field name. **`(feat):`** We now allow an empty constructor on types with no required properties. --- # September 25, 2024 ## 0.1.2 **`(feat):`** Represent enums in objects as strings. **`(fix):`** Generated wrapped requests now implement `JsonSerializableType`. **`(fix):`** Fix a bug where we don't set the request options baseurl properly. **`(fix):`** Fix bugs in our numeric type serde and add tests. --- # September 24, 2024 ## 0.1.1 **`(fix):`** The generated `.github/workflows/ci.yml` file now uses 'shivammathur/setup-php\@v2' to install `php` and `composer`. ## 0.1.0 **`(feat):`** Initial release. --- # Ruby quickstart > Learn how to generate a Ruby SDK with Fern. Step-by-step guide to configure generators.yml, run fern generate, and create Ruby client libraries. Generate a Ruby SDK by following the instructions on this page. This page assumes that you have: * An initialized `fern` folder. See [Set up the `fern` folder](/sdks/overview/quickstart). * A GitHub repository for your SDK. See [Project Structure](/sdks/overview/project-structure). ### Pass `fern check` Run `fern check` to ensure that your API definition is valid. If there are any errors, fix them before proceeding. If you're using an OpenAPI Specification, check out all of our [supported extensions](/learn/api-definition/openapi/extensions). ### Add the SDK generator Run the following command to add the Ruby SDK generator to `generators.yml`: ```bash fern add fern-ruby-sdk --group ruby-sdk ``` `ruby-sdk` is the name of the `generators.yml` group that configures your Ruby SDK's output location and other metadata. You can customize this group name to differentiate between multiple SDKs across different languages (e.g., `python-sdk`, etc) in your organization. This command adds the following `group` to `generators.yml`: ```yaml title="generators.yml" ruby-sdk: # group name generators: - name: fernapi/fern-ruby-sdk version: 1.0.0-rc85 output: location: local-file-system path: ../sdks/ruby ``` ### Generate the SDK Run the following command to generate your SDK: ```bash fern generate --group ruby-sdk ``` If you have multiple APIs, use the [`--api` flag](/cli-api-reference/cli-reference/commands#api) to specify the API you want to generate: ```bash fern generate --group ruby-sdk --api your-api-name ``` This creates a `sdks` folder in your current directory. The resulting folder structure looks like this: --- # Ruby configuration > Configuration options for the Fern Ruby SDK. You can customize the behavior of the Ruby SDK generator in `generators.yml`: ```yaml {6-14} title="generators.yml" groups: ruby-sdk: generators: - name: fernapi/fern-ruby-sdk version: 1.0.0-rc85 config: module: YourModuleName enableWireTests: true extraDependencies: faraday: "~> 2.0" oj: "~> 3.0" extraDevDependencies: rspec: "~> 3.0" webmock: "~> 3.0" ``` Custom name for the client module. This allows you to customize the module name that wraps the generated client class. Custom name for the pager class used in paginated endpoints. By default, the generator creates a standard pager class, but you can customize its name to match your SDK's naming conventions. Add custom sections to the generated README file. Each section requires a title and content. ```yaml config: customReadmeSections: - title: "Custom integration" content: "Instructions for custom integration..." - title: "Advanced usage" content: "Advanced usage examples for {{ packageName }}" ``` The content supports template variables like `{{ packageName }}` that are replaced with actual values during generation. When enabled, generates [mock server (wire) tests](/sdks/deep-dives/testing#mock-server-tests) to verify that the SDK sends and receives HTTP requests as expected. This feature is available only for the [Pro and Enterprise plans](https://buildwithfern.com/pricing). To get started, reach out to [support@buildwithfern.com](mailto:support@buildwithfern.com). Specify additional dependencies to include in the generated SDK's gemspec. This is useful when you need to add custom gems that your SDK depends on. This feature is available only for the [Pro and Enterprise plans](https://buildwithfern.com/pricing). To get started, reach out to [support@buildwithfern.com](mailto:support@buildwithfern.com). Specify additional development dependencies to include in the generated SDK's Gemfile. These are dependencies used for development and testing but not required by end users. Custom module name for the generated SDK. This sets the top-level Ruby module that wraps all generated code. By default, the module name is derived from the package name in your publish configuration or your organization name. ```yaml config: module: MyCustomModule ``` This generates code like: ```ruby module MyCustomModule class Client # ... end end ``` This feature is available only for the [Pro and Enterprise plans](https://buildwithfern.com/pricing). To get started, reach out to [support@buildwithfern.com](mailto:support@buildwithfern.com). Paths to files that will be auto-loaded when the gem is required. This is useful for including custom integrations or extensions that should be loaded automatically. ```yaml config: requirePaths: - custom_integration - sentry_integration ``` This will load `lib//custom_integration.rb` and `lib//sentry_integration.rb` when the gem is required. --- # Publishing to RubyGems > Publish Ruby SDKs to RubyGems with Fern. Complete setup guide for package configuration, API key authentication, and versioned releases. Publish your public-facing Fern Ruby SDK to the [RubyGems registry](https://rubygems.org/). After following the steps on this page, you'll have a versioned package published on RubyGems. This page assumes that you have: * An initialized `fern` folder. See [Set up the `fern` folder](/sdks/overview/quickstart). * A GitHub repository for your SDK. See [Project Structure](/sdks/overview/project-structure). ## Configure `generators.yml` Next, change the output location in `generators.yml` from `local-file-system` (the default) to `pypi` to indicate that Fern should publish your package directly to the PyPI registry: ```yaml {6-7} groups: ruby-sdk: generators: - name: fernapi/fern-ruby-sdk version: 1.0.0-rc85 output: location: rubygems ``` Your package name must be unique in the RubyGems repository, otherwise publishing your SDK to RubyGems will fail. Update your package name if you haven't done so already: ```yaml {8} groups: ruby-sdk: generators: - name: fernapi/fern-ruby-sdk version: 1.0.0-rc85 output: location: rubygems package-name: your-package-name ``` The `clientModuleName` option controls the name of the generated client. This is the name customers use to import your SDK (`import { your-client-name } from 'your-package-name';`). ```yaml {9-10} groups: ruby-sdk: generators: - name: fernapi/fern-ruby-sdk version: 1.0.0-rc85 output: location: rubygems package-name: your-package-name config: clientModuleName: YourClientName # must be PascalCase ``` Add the path to your GitHub repository to `generators.yml`: ```yaml {11-12} groups: ruby-sdk: generators: - name: fernapi/fern-ruby-sdk version: 1.0.0-rc85 output: location: rubygems package-name: your-package-name config: clientModuleName: YourClientName github: repository: your-org/company-ruby ``` ## Set up RubyGems publishing authentication Log into [RubyGems](https://rubygems.org/) or create a new account. 1. Click on your profile picture 2. Select **Settings**. 3. Scroll down and click on **API Keys**. When prompted to [create a new API key](https://rubygems.org/profile/api_keys/new): 1. Name your key. 2. Under **Scopes**, select **Push rubygem** 3. Select `All Gems` under **Gem Scope**. If you are overriding an existing gem, you can select the relevant package instead of entering `All Gems`. 1. Set an expiration date. 2. Click **Create API Key**. Save your new key – it won’t be displayed after you leave the page. Creating a New API Key Add `api-key: ${RUBYGEMS_API_KEY}` to `generators.yml` to tell Fern to use the `RUBYGEMS_API_KEY` environment variable for authentication when publishing to the PyPI registry. ```yaml title="ruby" {9} groups: ruby-sdk: generators: - name: fernapi/fern-ruby-sdk version: 1.0.0-rc85 output: location: rubygems package-name: your-package-name api-key: ${RUBYGEMS_API_KEY} config: clientModuleName: YourClientName github: repository: your-org/company-ruby ``` ## Release your SDK to RubyGems At this point, you're ready to generate a release for your SDK. On your local machine, set the `RUBYGEMS_API_KEY` environment variable to the new API key you generated earlier: ```bash export RUBYGEMS_API_KEY=your-actual-rubygems-token ``` Regenerate your SDK and publish it on RubyGems: ```bash fern generate --group ruby-sdk --version ``` Local machine output will verify that the release is pushed to your repository and tagged with the version you specified. Log back into RubyGems and navigate to **Releases** to see your new release. --- # Adding custom code > Augment your Ruby SDK with custom utilities This page covers how to add custom logic, methods, and dependencies to your Ruby SDK. Before getting started, [read about how Fern SDKs use custom code and learn about the `.fernignore` file](/sdks/overview/custom-code) . ## Adding custom logic To get started adding custom code: ```ruby title="lib//helper.rb" module YourGem class Helper def self.my_helper puts "Hello World!" end end end ``` ```yaml {3} title=".fernignore" # Specify files that shouldn't be modified by Fern lib//helper.rb ``` Now your users can consume the helper function by importing it from the SDK. ```ruby require "your_gem" YourGem::Helper.my_helper ``` ## Adding custom SDK methods Fern also allows you to add custom methods to the SDK itself (e.g. `client.my_method()` ) by inheriting the Fern generated client and then extending it. Name your Fern-generated client something like `BaseClient` to reflect that this client will be extended. ```yaml {4} title="generators.yml" - name: fernapi/fern-ruby-sdk version: 1.0.0-rc85 config: clientClassName: BaseClient ``` First, import the Fern generated base client and extend it. Then, add whatever methods you want. ```ruby title="lib//my_client.rb" require_relative "client" module YourGem class MyClient < BaseClient def my_helper puts "Hello World!" end end end ``` Add the `my_client.rb` to `.fernignore`. ```diff title=".fernignore" + lib//my_client.rb ``` Instead of constructing the generated client, your users will want to construct the extended client. ```ruby require "your_gem" client = YourGem::MyClient.new ``` Now your users can consume the helper function by importing it from the SDK. ```ruby client.my_helper ``` ## Adding custom dependencies This feature is available only for the [Pro and Enterprise plans](https://buildwithfern.com/pricing). To get started, reach out to [support@buildwithfern.com](mailto:support@buildwithfern.com). To add gems that your custom code requires, update your `generators.yml`. ```yaml {4-7} title="generators.yml" - name: fernapi/fern-ruby-sdk version: 1.0.0-rc85 config: extraDependencies: faraday: ">= 1.0" extraDevDependencies: rspec: "~> 3.0" ``` --- # January 28, 2026 ## 1.0.0-rc85 **`(fix):`** Fix detached HEAD error in publish workflow. When triggered by a tag push, the workflow enters detached HEAD state, causing `rubygems/release-gem@v1` (which runs `rake release`) to fail when pushing to a non-existent branch. Replaced with manual build/push steps using `rubygems/configure-rubygems-credentials@v1.0.0` for OIDC auth, `bundle exec rake build`, and `gem push pkg/*.gem`. Also replaced `bundler-cache: true` with explicit `bundle install` for more reliable dependency installation. ## 1.0.0-rc84 **`(fix):`** Fix packageName being incorrectly used for folder/module naming. The packageName from publish config (e.g., output.publish.rubygems.packageName) is now only used for the gemspec spec.name field, not for folder structure or Ruby module names. This fixes issues where gems with special characters in their package name (e.g., "square.rb") would have incorrect folder structures (lib/square\_rb/ instead of lib/square/) and normalized gemspec names. The folder and module naming now correctly uses only the custom config moduleName option or the organization name as fallback. **`(fix):`** Fix organization names with digits (e.g., "auth0") being incorrectly transformed to "auth\_0" in folder names. The snake\_case transformation now preserves letter-digit sequences, so "auth0" stays "auth0" and "OAuth2" becomes "oauth2" instead of "o\_auth\_2". ## 1.0.0-rc83 **`(fix):`** Fix request body serialization bug where path/query/header parameters were incorrectly serialized as nil values in the request body. For endpoints with inlined request bodies that also have path, query, or header parameters, the wrapper type (which includes all endpoint parameters) was being created with only body properties, causing non-body fields to be nil and serialized as null in the JSON body. The fix uses a serialize-then-split pattern: serialize ALL params through the wrapper type first, then remove non-body params from the serialized result. This ensures proper type conversion while keeping non-body params out of the request body. --- # January 27, 2026 ## 1.0.0-rc82 **`(feat):`** Implement HTTP status code-based retry logic with exponential backoff. The SDK now automatically retries requests that fail with retryable HTTP status codes (408, 429, 500, 502, 503, 504, 521, 522, 524) using exponential backoff with jitter. The retry logic respects Retry-After headers when present. This addresses the feature gap where the SDK previously only used Net::HTTP's network-level retries, which don't handle HTTP status codes like 429 (Too Many Requests). The max\_retries parameter now controls application-level retries with proper backoff, enabling compliance with rate-limiting requirements like Square App Marketplace. --- # January 16, 2026 ## 1.0.0-rc81 **`(feat):`** Add support for self-hosted mode. When enabled, the generator can clone the user's GitHub repository, generate SDK code, and commit/push changes or create a PR directly to the user's repo. This feature respects .fernignore files to preserve user customizations. The generator now passes ir.selfHosted to the base generator agent instead of hardcoding false. --- # January 15, 2026 ## 1.0.0-rc80 **`(fix):`** Add support for clientModuleName config option to customize the root client class name. When clientModuleName is set (e.g., "PinnacleBaseClient"), the generated root client class will use that name instead of the default "Client". This restores functionality that existed in the original Ruby SDK generator. **`(fix):`** Add support for packageName from publish config to set the gem name and module name. The gem name (folder name) and module name now use the packageName from the RubyGems publish config (e.g., output.publish.rubygems.packageName) as a fallback when the custom config module option is not set. This restores functionality from the original Ruby SDK generator where the gem name could be configured via the publish target. --- # January 14, 2026 ## 1.0.0-rc79 **`(feat):`** Add support for additional\_query\_parameters in request options. Users can now pass additional query parameters via request\_options\[:additional\_query\_parameters] which will be merged with the endpoint's query parameters when making HTTP requests. --- # January 13, 2026 ## 1.0.0-rc78 **`(chore):`** Update Dockerfile to use the latest generator-cli with improve reference.md generation. ## 1.0.0-rc77 **`(feat):`** Add RETRIES, ADDITIONAL\_HEADERS, and ADDITIONAL\_QUERY\_PARAMETERS sections to generated README.md. These sections document how to configure automatic retries, add custom headers, and add custom query parameters to API requests. The features were previously removed because they had Go-specific descriptions; they are now restored with Ruby-specific documentation and code snippets. --- # January 6, 2026 ## 1.0.0-rc76 **`(fix):`** Fix wire tests for paginated endpoints not triggering HTTP requests. Cursor and offset pagination endpoints return lazy iterators that don't make HTTP requests until iterated. Wire tests now call `.pages.next_page` on the returned iterator to trigger the first HTTP request, ensuring WireMock receives the expected request for verification. **`(fix):`** Fix pagination field names to use Ruby-safe method names instead of wire values. Fields like `cursor_field`, `item_field`, and `has_next_field` are used to call Ruby methods on response objects via `send()`. Previously these used `wireValue` which doesn't account for Ruby reserved word escaping (e.g., "next" -> "next\_"). Now uses `snakeCase.safeName` which matches the actual Ruby accessor names. ## 1.0.0-rc75 **`(fix):`** Fix inconsistent module naming for organization names containing digits (e.g., "auth0"). Previously, internal types used `module Auth0` while public types used `module Auth_0` due to lodash's snakeCase inserting underscores before digits. Now all code paths use upperFirst directly on the organization name, producing consistent module names like `Auth0`. Also fixes test\_helper.rb require path to use the correct folder name (e.g., `auth_0`) instead of the module name (e.g., `auth0`), preventing LoadError when running tests. --- # January 5, 2026 ## 1.0.0-rc75 **`(chore):`** Update Dockerfile to use the latest generator-cli with improve reference.md generation. --- # December 19, 2025 ## 1.0.0-rc74 **`(feat):`** Add opt-in `requirePaths` config option for auto-loading user-defined files when the gem is required. When configured (e.g., `requirePaths: ["custom_integration", "sentry_integration"]`), the gem entrypoint will auto-load each file from `lib//.rb` if it exists. This allows users to add custom code (e.g., Sentry integration) without needing to fernignore generated files. Uses file existence check to avoid silently swallowing real errors. --- # December 18, 2025 ## 1.0.0-rc73 **`(fix):`** Fix endpoint header parameters being included in request body instead of HTTP headers. Header parameters (like Idempotency-Key) are now properly extracted from params and passed via the headers parameter in Request.new() calls. **`(feat):`** Add normalize\_keys utility to accept both snake\_case and camelCase parameter keys. SDK endpoint methods now automatically convert camelCase keys (e.g., refundMethod) to snake\_case (e.g., refund\_method) at the start of each method. This allows users to pass JSON data with camelCase keys directly to SDK methods without manual conversion. ## 1.0.0-rc72 **`(chore):`** Add sdkVersion as a top-level field in the generated metadata.json file. --- # December 17, 2025 ## 1.0.0-rc71 **`(feat):`** Make the base\_url parameter optional in the main client.rb. The parameter now has a default value of nil, allowing users to instantiate the client without explicitly providing a base\_url when using environment-based configuration. ## 1.0.0-rc70 **`(fix):`** Fix inferred auth base URL resolution and add absolute URL support: * Auth raw client now properly falls back to default environment when base\_url is not provided * RawClient.build\_url now handles absolute URLs (e.g., HATEOAS pagination links) directly * Added attr\_reader :base\_url to RawClient for external access * Removed unnecessary base\_url override in InferredAuthProvider.refresh since auth\_client is already configured with the correct base URL --- # December 16, 2025 ## 1.0.0-rc69 **`(chore):`** Improve wire test generation with client reuse and AST-level snippet handling. The client is now instantiated once in the setup method and reused across all tests, following the PHP/Python pattern for better performance. Replaced fragile regex-based snippet patching with AST-level code generation using skipClientInstantiation option. Helper methods are now centralized in a WireMockTestCase base class. --- # December 15, 2025 ## 1.0.0-rc68 **`(feat):`** Add RubyGems.org OIDC publishing workflow to generated CI: * Generates a `publish` job in CI that uses `rubygems/release-gem@v1` for OIDC trusted publishing * Publish job runs on tag pushes after lint and test jobs pass * Simplify wire tests execution by running them inline with regular tests using `RUN_WIRE_TESTS=true` env var instead of a separate CI job ## 1.0.0-rc67 **`(feat):`** Add support for x-fern-server-name (multiple base URLs per environment). APIs with different endpoints routed to different base URLs (e.g., separate api and identity URLs) now generate proper Environment classes with hash-based URL mappings. Each endpoint uses its designated base URL based on the endpoint.baseUrl property from the IR. --- # December 11, 2025 ## 1.0.0-rc66 **`(fix):`** Fix union type matching for Hash and Array type wrappers. The `type_matches?` method now correctly handles `Internal::Types::Hash` and `Internal::Types::Array` instances by checking if the value is a `::Hash` or `::Array` respectively, instead of using `is_a?` directly on the type wrapper classes. ## 1.0.0-rc65 **`(feat):`** Add CI workflow generation, .gitignore file, and wire test infrastructure: * Generate `.github/workflows/ci.yml` with lint and test jobs (triggers on push and pull\_request) * Generate `.gitignore` file with `*.gem` * Config-driven wire-tests job: when `enableWireTests: true`, generates wire-tests CI job * Add `wire_helper.rb` for WireMock container lifecycle management using Minitest's `after_run` hook, allowing users to run `bundle exec rake test` locally without manually managing docker compose --- # December 10, 2025 ## 1.0.0-rc64 **`(chore):`** Improve reference.md generation for parity with TypeScript SDK generator: * Add request\_options parameter documentation to all endpoints * Add source file links (hyperlinks) to method names in the reference * Prefer examples with request body data for detailed code snippets, ensuring endpoints show full request bodies with nested objects and arrays instead of minimal one-line examples * Synthesize requestBody from structured properties when jsonExample is null/empty ## 1.0.0-rc63 **`(fix):`** Fix README.md generation for GitHub, direct publish, and seed test modes. * Updated shouldGenerateReadme to return true by default instead of requiring snippetFilepath * Fixed getGitHubConfig to return undefined for uri/token instead of placeholder values that caused invalid git clone attempts --- # December 8, 2025 ## 1.0.0-rc62 **`(feat):`** Add support for discriminated unions, enums, and undiscriminated unions in dynamic snippets. This fixes issues where snippet examples were showing empty arrays or missing values for complex types like union recipients in email/message send operations. --- # December 5, 2025 ## 1.0.0-rc61 **`(fix):`** Move default environment resolution from request functions to root client instantiation. Without this change, a non-default base URL set on the client initialization is never used. The default environment fallback was happening at the request layer, which meant any base\_url passed to individual requests would fall back to the default environment if not explicitly provided in request\_options—even when the root client was initialized with a custom base\_url. ## 1.0.0-rc60 **`(feat):`** Add extraDependencies and extraDevDependencies config flags to Ruby v2 SDK generator. These options allow users to specify additional gem dependencies to include in the generated gemspec (extraDependencies) and Gemfile (extraDevDependencies). Values are written directly as version constraints (e.g., `{ "my-gem": "~> 6.0" }` produces `spec.add_dependency "my-gem", "~> 6.0"`). --- # December 4, 2025 ## 1.0.0-rc59 **`(feat):`** Add wire test generation support for Ruby SDK. When enableWireTests is set to true in custom config, the generator produces Minitest-based integration tests that validate SDK serialization/deserialization against WireMock. Includes docker-compose.test.yml and wiremock-mappings.json for running tests locally. --- # December 3, 2025 ## 1.0.0-rc58 **`(fix):`** Fix additional RuboCop warnings in generated SDK code: * Disabled Layout/LineLength cop (long type names and require paths are unavoidable) * Set Naming/VariableNumber to snake\_case style (allows `last_4`, `address_1`, etc.) * Renamed `get_token` and `get_auth_headers` methods to `token` and `auth_headers` * Replaced OpenStruct with Struct in iterator tests --- # December 2, 2025 ## 1.0.0-rc57 **`(fix):`** Fix additional RuboCop warnings in generated SDK code: * Renamed iterator methods to follow Ruby conventions (get\_next -> next\_element/next\_page, has\_next? -> next?) * Renamed custom pager methods (get\_next\_page -> next\_page, has\_next\_page? -> next\_page?) * Added super() calls in iterator initializers to fix Lint/MissingSuper * Combined duplicate pattern match branches in utils.rb to fix Lint/DuplicateBranch * Updated .rubocop.yml to target Ruby 3.3 and disable additional cops ## 1.0.0-rc56 **`(fix):`** Disable Metrics/CyclomaticComplexity in generated .rubocop.yml to silence warnings for endpoint methods with many query parameters. ## 1.0.0-rc55 **`(fix):`** Fix RuboCop Lint/UnderscorePrefixedVariableName warnings in generated code. Renamed underscore-prefixed local variables (\_query, \_request, \_response, etc.) to non-underscore names (query\_params, request, response, etc.) to follow Ruby conventions for used variables. ## 1.0.0-rc54 **`(fix):`** Auto-wrap long comment lines to fit within RuboCop's 120 character line length limit. This prevents Layout/LineLength warnings for comments generated from long OpenAPI descriptions. --- # November 29, 2025 ## 1.0.0-rc53 **`(feat):`** Pass raw\_client to custom pager for pagination. This allows custom pager implementations to fetch additional pages using the HTTP client. ## 1.0.0-rc52 **`(fix):`** Fix root client generation for inferred auth. The client now correctly creates an unauthenticated client for the auth endpoint, passes auth\_client and options to InferredAuthProvider, and uses the correct Internal namespace. ## 1.0.0-rc51 **`(fix):`** Fix inferred auth token refresh to properly refresh when within buffer period. The token is now refreshed when the current time is within 2 minutes of expiration, rather than only after the token has fully expired. ## 1.0.0-rc50 **`(feat):`** Add inferred auth support for Ruby SDKs. The SDK now generates an InferredAuthProvider class that handles automatic token retrieval and caching with expiration handling. Root clients accept the token endpoint request parameters for inferred authentication. --- # November 28, 2025 ## 1.0.0-rc49 **`(fix):`** Added automatic redaction of sensitive fields in inspect output to prevent accidental exposure of credentials and tokens in logs and debug output. ## 1.0.0-rc48 **`(feat):`** Add custom pagination support with customPagerName configuration option. When customPagerName is configured, the generator includes a CustomPager utility class that provides navigation methods (has\_next\_page?, has\_prev\_page?, get\_next\_page, get\_prev\_page) for custom pagination endpoints. --- # November 26, 2025 ## 1.0.0-rc47 **`(fix):`** Fix request\_options\[:base\_url] being ignored. The RawClient.build\_url method now correctly uses the per-request base\_url override when provided. ## 1.0.0-rc46 **`(fix):`** Improve README snippet generation: use SCREAMING\_SNAKE\_CASE for Environment references, snake\_case for nested object property names, and filter out empty/undefined values to avoid syntax errors like "param: ,". ## 1.0.0-rc45 **`(feat):`** Add support for multi-URL environments. APIs with multiple base URLs per environment (e.g., separate api and identity URLs) now generate a proper Environment class using the first base URL for each environment. ## 1.0.0-rc44 **`(fix):`** Remove error on null config in README generation. --- # November 24, 2025 ## 1.0.0-rc43 **`(fix):`** Fix missing path parameters in reference.md code snippets for endpoints with BodyRequest types. Path parameters are now included as positional arguments in generated snippets (e.g., `client.test_get('id')` instead of `client.test_get()`). --- # November 20, 2025 ## 1.0.0-rc42 **`(fix):`** Improve YARD documentation syntax in generated Ruby SDK code. ## 1.0.0-rc41 **`(fix):`** Remove dead code in RawClient and honor max\_retries parameter. The max\_retries parameter is now properly used instead of being hardcoded to 0. ## 1.0.0-rc40 **`(fix):`** Reorder YARD tags to follow standard convention (@param before @option). --- # November 19, 2025 ## 1.0.0-rc39 **`(feat):`** Add YARD documentation comments for method parameters in generated SDK code. ## 1.0.0-rc38 **`(fix):`** Fix route parameters and multipart file upload properties to use snake\_case names in Ruby code instead of camelCase wire values. Ruby parameter keys now follow Ruby naming conventions (e.g., `params[:payment_id]` instead of `params[:paymentId]`) while preserving the original wire values for HTTP requests. ## 1.0.0-rc37 **`(chore):`** Bump generator CLI version to publish new Docker image. --- # November 17, 2025 ## 1.0.0-rc36 **`(fix):`** Validate that all required (non-optional) fields are present for undiscriminated union members. ## 1.0.0-rc35 **`(fix):`** Properly (de)serialize union members with non-snake\_case field names. --- # November 7, 2025 ## 1.0.0-rc34 **`(fix):`** Bump IR version which we are dependent on. --- # November 6, 2025 ## 1.0.0-rc33 **`(fix):`** Fix the to\_h method to correctly serialize nested objects while respecting the api\_name parameter. --- # November 4, 2025 ## 1.0.0-rc32 **`(feat):`** Add support for undiscriminated unions in Ruby v2 SDK generator. The generator now creates proper union type classes for undiscriminated unions that were previously being skipped. ## 1.0.0-rc31 **`(fix):`** Fix deserialization of API responses with non-snake\_case field names (e.g., camelCase, PascalCase, SCREAMING\_SNAKE\_CASE). The generator now preserves wire format field names via the api\_name parameter when generating field definitions. --- # October 21, 2025 ## 1.0.0-rc30 **`(feat):`** Add support for custom Gemfiles. ## 1.0.0-rc29 **`(feat):`** Add support for API key (header-based) authentication in Ruby SDK generator. Supports multiple authentication schemes in the same API. --- # October 1, 2025 ## 1.0.0-rc28 **`(fix):`** Fix gem versioning when building an SDK locally. --- # September 29, 2025 ## 1.0.0-rc27 **`(fix):`** Upgrade generator-cli dependency to fix local generation handling of .fernignore files. --- # September 21, 2025 ## 1.0.0-rc26 **`(feat):`** Add support for custom sections in the README.md via `customSections` config option. --- # September 17, 2025 ## 1.0.0-rc25 **`(fix):`** Fixes an issue where the generated usage snippets in the README.md was not prioritizing user defined example values over autogenerated example values. --- # September 16, 2025 ## 1.0.0-rc24 **`(fix):`** Fix reference to the default environment to use SCREAMING\_SNAKE\_CASE. ## 1.0.0-rc23 **`(fix):`** Properly fall back to default environment if specified. --- # September 15, 2025 ## 1.0.0-rc22 **`(fix):`** Fix project file to not import non ruby files. ## 1.0.0-rc21 **`(fix):`** Fix missing path parameter references. --- # September 11, 2025 ## 1.0.0-rc20 **`(fix):`** Fix query parameter handling to support symbol keys in addition to string keys. --- # August 29, 2025 ## 1.0.0-rc19 **`(chore):`** Removed circular dependency logs. --- # August 26, 2025 ## 1.0.0-rc18 **`(feat):`** Updating Ruby build and configuration files, and adding custom test files. --- # August 20, 2025 ## 1.0.0-rc17 **`(fix):`** Fix reference request methods. ## 1.0.0-rc16 **`(fix):`** Fix subpackage client generation. ## 1.0.0-rc15 **`(fix):`** Generate nested subpackage clients. ## 1.0.0-rc14 **`(fix):`** Fix parameterless endpoint methods. ## 1.0.0-rc13 **`(feat):`** Implement Wrapped Request Endpoints. ## 1.0.0-rc12 **`(fix):`** Support multipart form uploads. ## 1.0.0-rc11 **`(fix):`** Install dependencies after generating the SDK to produce a Gemfile.lock. ## 1.0.0-rc10 **`(fix):`** Generate a Rubocop file and autocorrect the generated code. --- # August 18, 2025 ## 1.0.0-rc9 **`(fix):`** Union types extend the Model class. ## 1.0.0-rc8 **`(fix):`** The client argument on the nested resource is now a keyword argument. ## 1.0.0-rc7 **`(fix):`** Update the Union type to not remove the discriminant from the value. ## 1.0.0-rc6 **`(fix):`** Fix reference to internal JSON request. ## 1.0.0-rc5 **`(fix):`** Fix module name for internal JSON request. ## 1.0.0-rc4 **`(fix):`** Fix syntax for Union types extending the Union module. --- # August 13, 2025 ## 1.0.0-rc3 **`(feat):`** Always lazy load type references to handle circular dependencies and import order. ## 1.0.0-rc2 **`(feat):`** Support for sending request bodies when the request is a reference to a type or a primitive. ## 1.0.0-rc1 **`(feat):`** Fix circular type references within the Ruby SDK generator. ## 1.0.0-rc0 **`(feat):`** Introduce a revamped Ruby SDK generator with several improvements to be detailed in a larger post. --- # August 5, 2024 ## 0.8.2 **`(fix):`** The generated endpoint functions no long include object utilities such as `_field_set` or `additional_properties`. --- # July 22, 2024 ## 0.8.1 **`(fix):`** Address serialization issues within iterable types ### What's been fixed * Nested `hash` types are recursively resolved in `from_json` such that they come back as true hashes, as opposed to structs * Pass through additional params from request options even if the original request did not have those types of params (ex: query parameters) --- # July 3, 2024 ## 0.8.0 **`(fix):`** Date snippets now wrap their examples in quotation marks to correctly use `.parse` --- # July 1, 2024 ## 0.8.0-rc0 **`(feat):`** allow users to specify additional dependencies and dev dependencies for Ruby SDKs. --- # June 13, 2024 ## 0.7.0-rc0 **`(feat):`** Introduce automatic token refresh for OAuth credentials ### What's new * The Ruby SDK now generates an OAuth client to automate token refresh. ### What's been fixed * The Ruby SDK now no longer requires users specify literals in method signatures --- # May 27, 2024 ## 0.6.3 **`(feat):`** Generated SDK snippets now leverage the full function module path. --- # May 17, 2024 ## 0.6.2 **`(internal):`** The generator now uses the latest FDR SDK --- # April 9, 2024 ## 0.5.0-rc0 **`(feat):`** The generated SDK now includes a rakefile to run any tests prefixed with `test_` in the `test` directory ### What's new * Consumers of the SDK can now pass in a base URL override into the root client, as well as the request's RequestOptions ### What's been fixed * This PR includes a number of typing annotation and cleanliness/QOL fixes. --- # April 8, 2024 ## 0.7.0-rc5 **`(feat):`** additional fix for the same issue within 0.7.0-rc4 (regression introduced within the 0.7.0 RCs where the token prefix was dropped from requests). ## 0.7.0-rc4 **`(feat):`** fixes regression introduced within the 0.7.0 RCs where the token prefix was dropped from requests. ## 0.7.0-rc3 **`(fix):`** Module references are now consistent throughout the generated SDK, this was a regression in the previous release. ## 0.7.0-rc2 **`(feat):`** the ruby generator now nests types under a type module to avoid naming conflicts, this is behind a configuration flag ## 0.7.0-rc1 **`(feat):`** Address serialization issues within iterable types ### What's been fixed * nested loops leverage different variable names to deconflict * nested loops do not call to\_json prior to the subsequent loop ## 0.6.1 **`(internal):`** Release Generator ## 0.6.1-rc0 **`(internal):`** Improve logging within the Ruby generator ## 0.6.0-rc1 **`(fix):`** fix regression where sometimes the parsed\_json variable would not be instantiated, and so there'd be a nil ref in the generated code ## 0.6.0-rc0 **`(feat):`** Introduce code snippets and examples for Ruby SDKs ## 0.5.0-rc2 **`(fix):`** Call JSON.parse prior to iterating through an iterable response ## 0.4.0 **`(feat):`** The generated SDK now includes a rakefile to run any tests prefixed with `test_` in the `test` directory ### What's new * The generators now create a rakefile to run any tests prefixed with `test_` in the `test` directory. A step is also added to CI to run these test. The dummy test now running also provides a sanity check on the health of the build of the gem, even if no tests are added given the gem is imported. --- # March 22, 2024 ## 0.3.3 **`(internal):`** Leverage shared generator notification and config parsing logic. ## 0.1.0-rc0 **`(chore):`** Loosen the Faraday dependencies within the generated SDKs ### What's changed * loosen the Faraday dependencies within the generated SDKs, now we are supporting Faraday 1.x, while continuing to support the same upperbound (specifically supporting the latest major version as well). * release a minor version as the Ruby generator is now being used in beta! ## 0.0.6 **`(feat):`** license files are now specified within the gem config if they are provided ## 0.0.5 **`(fix):`** Address parsing issues within the SDK ### What's been fixed * Syntactic error in block parameter usage: we now ensure block parameters are the final parameter for functions * Add properties to subpackages: previously properties on subpackages were not being exposed * Ensure optional properties in from\_json are only parsed if present ## 0.0.4 **`(fix):`** ensures files are written at the gem name path over client name, and addresses string escaping on one of the Fern headers ## 0.0.3 **`(fix):`** addresses a number of typos and other issues previously contained within the generation code ## 0.0.2 **`(feat):`** Support rubygems output type within `generators.yml` --- # March 18, 2024 ## 0.3.2 **`(feat):`** type bytes requests to also take in IO types, indicating to users that they may pass in a stream of bytes --- # March 12, 2024 ## 0.3.1 **`(fix):`** use strings instead of UUIDs, which are helper classes in Ruby --- # February 27, 2024 ## 0.3.0 **`(fix):`** Generated yardoc now appropriately reflects the typehint of the value type in maps ### What's been fixed * Ensure the name passed into the 'X-Fern-SDK-Name' header is the name of the gem, not the client class * If an envvar is specified as a fallback for an auth header, the SDK will now mark that parameter as optional to allow fallback to actually happen * Generated yardoc now appropriately reflects the typehint of the value type in maps --- # February 20, 2024 ## 0.2.0 **`(feat):`** Add support for idempotency headers ### What's changed * Ruby enum construct now leverages class constants instead of hashes to support better autocomplete * Discriminated unions are no longer wrapped within a parent object, rather, any field or parameter that depends on a discriminated union now explicitly references the member types in support of better autocomplete. * Undiscriminated unions are no longer allowed as hashes as input to SDK functions, this is in support of better autocomplete as well. * The generated Ruby SDKs now support idempotency headers, users may specify idempotency headers within the RequestOptions object --- # February 15, 2024 ## 0.1.1 **`(internal):`** Ensure the Ruby generators do not have strict dependencies on the IR --- # February 1, 2024 ## 0.0.1 **`(feat):`** Support client generation (async and sync) as well as most endpoint types (except streaming) --- # January 30, 2024 ## 0.0.0 **`(internal):`** Initialize the changelog --- # Swift quickstart > Learn how to generate a Swift SDK with Fern. Step-by-step guide to configure generators.yml and create client libraries for your API. Generate a Swift SDK by following the instructions on this page. This page assumes that you have: * An initialized `fern` folder. See [Set up the `fern` folder](/sdks/overview/quickstart). * A GitHub repository for your SDK. See [Project Structure](/sdks/overview/project-structure). ### Pass `fern check` Run `fern check` to ensure that your API definition is valid. If there are any errors, fix them before proceeding. If you're using an OpenAPI Specification, check out all of our [supported extensions](/learn/api-definition/openapi/extensions). ### Add the SDK generator Run the following command to add the Swift SDK generator to `generators.yml`: ```bash fern add fern-swift-sdk --group swift-sdk ``` `swift-sdk` is the name of the `generators.yml` group that configures your Swift SDK's output location and other metadata. You can customize this group name to differentiate between multiple SDKs across different languages (e.g., `ruby-sdk`, etc) in your organization. This command adds the following `group` to `generators.yml`: ```yaml title="generators.yml" swift-sdk: # group name generators: - name: fernapi/fern-swift-sdk version: 0.25.4 output: location: local-file-system path: ../sdks/swift ``` ### Generate the SDK Run the following command to generate your SDK: ```bash fern generate --group swift-sdk ``` This creates a `sdks` folder in your current directory. The resulting folder structure looks like this: --- # Swift configuration > Configure Swift SDK generator settings including clientClassName, moduleName, environmentEnumName, and nullableAsOptional options. You can customize the behavior of the Swift SDK generator in `generators.yml`: ```yaml {6-11} title="generators.yml" groups: swift-sdk: generators: - name: fernapi/fern-swift-sdk version: 0.25.4 config: clientClassName: YourClientName environmentEnumName: YourCustomEnvironment moduleName: MyCustomModule enableWireTests: false nullableAsOptional: true ``` The name of the generated client class. This allows you to customize the class name that users will instantiate when using your SDK. The name of the generated environment enum. This allows you to customize the enum name that defines your API environments (such as production, staging, development) and ensures consistent naming across SDK generations. The module name used in client code (e.g., `import MyCustomModule`). When provided, this name is used consistently across the library, product, and target. Generates [mock server (wire) tests](/sdks/deep-dives/testing#mock-server-tests) to verify that the SDK sends the correct HTTP requests and correctly handles responses per the API spec. When enabled, nullable fields are decoded as Swift optionals (`T?`) instead of the `Nullable` wrapper type. This simplifies type handling but loses the ability to distinguish between explicit `null` values and absent fields. When disabled (default), nullable fields use the `Nullable` wrapper type which preserves the distinction between fields explicitly set to `null` and fields that are missing from the response. --- # Publishing as a Swift package > How to publish the Fern Swift SDK as a Swift package Publish your public-facing Fern Swift SDK as a Swift package distributed via Git. After following the steps on this page, you'll have a versioned package that developers can install using Swift Package Manager. This page assumes that you have: * An initialized `fern` folder. See [Set up the `fern` folder](/sdks/overview/quickstart). * A GitHub repository for your SDK. See [Project Structure](/sdks/overview/project-structure). ## Configure `generators.yml` Swift packages are distributed via Git repositories, so remove the auto-generated `output` and `config` properties. Instead, add the path to your GitHub repository: ```yaml {6-7} title="generators.yml" groups: swift-sdk: generators: - name: fernapi/fern-swift-sdk version: 0.25.4 github: repository: your-org/company-swift ``` ## Publish as a Swift package At this point, you're ready to generate a release for your SDK. Regenerate your SDK and publish it to your repository: ```bash fern generate --group swift-sdk --version ``` Local machine output will verify that the release is pushed to your repository and tagged with the version you specified. Your Swift package is now available! Developers can add it to their projects by: * **In Xcode**: File → Add Package Dependencies → Enter your repository URL * **In Package.swift**: Add to dependencies array: ```swift dependencies: [ .package(url: "https://github.com//", from: "") ] ``` Unlike other languages that rely on centralized registries, Swift packages are available as soon as they’re tagged and pushed to a Git repository. You can optionally submit your package to the community-maintained [Swift Package Index](https://swiftpackageindex.com/) for better discoverability. --- # December 18, 2025 ## 0.25.4 **`(chore):`** Add sdkVersion as a top-level field in the generated metadata.json file. --- # December 2, 2025 ## 0.25.3 **`(fix):`** Fix getGitHubConfig to return RawGithubConfig with undefined values instead of throwing errors when publishing config is missing, aligning with TypeScript/Python generator behavior. --- # November 26, 2025 ## 0.25.2 **`(fix):`** Remove error on null config in README generation. --- # November 21, 2025 ## 0.25.1 **`(fix):`** Remove using generator-cli to push to GitHub for self-hosted SDKs; this is now handled in the local workspace runner. --- # November 20, 2025 ## 0.25.0 **`(feat):`** Introduced a unified client error enum and structured `HTTPError` with a nested `ResponseBody`, and updated the HTTP client and tests to classify and surface HTTP failures consistently. --- # November 19, 2025 ## 0.24.1 **`(chore):`** Bump generator CLI version to publish new Docker image. --- # November 18, 2025 ## 0.24.0 **`(feat):`** Added support for cyclical type detection, rejecting infinite cycles and boxing legal recursive properties with `Indirect<...>`. --- # November 16, 2025 ## 0.23.4 **`(fix):`** Fixed a bug where discriminated union variant properties that collided with the discriminant property were incorrectly included in the generated struct. --- # November 7, 2025 ## 0.23.3 **`(fix):`** All static files within the SDK now use fully qualified type references. ## 0.23.2 **`(fix):`** Fixed a bug where query parameters with string enum types were incorrectly omitted from the request URL. ## 0.23.1 **`(fix):`** Fixed a bug where query parameters with empty values were not omitted from the request URL. ## 0.23.0 **`(feat):`** Added support for automatic retries with exponential backoff respecting the `Retry-After` and `X-RateLimit-Reset` response headers. --- # November 4, 2025 ## 0.22.0 **`(feat):`** Added Generation Metadata file to output. --- # October 31, 2025 ## 0.21.0 **`(feat):`** Added generator config option `nullableAsOptional` (defaults to `false`) to decode nullable fields as `Optional` instead of `Nullable`. --- # October 29, 2025 ## 0.20.1 **`(fix):`** Integrates dynamic snippets with the graph-based symbol registry for scope-aware type resolution. --- # October 26, 2025 ## 0.20.0 **`(feat):`** Migrated the generator to use the programmatic `generator-cli` API instead of invoking the CLI in a child process. --- # October 23, 2025 ## 0.19.0 **`(feat):`** Replaced the flat symbol registry with a graph-backed, scope-aware naming system, delivering deterministic, collision-safe naming and reference resolution. --- # October 19, 2025 ## 0.18.2 **`(fix):`** Fixed a bug where nullable query parameters were not accessed correctly in endpoint methods. --- # October 18, 2025 ## 0.18.1 **`(fix):`** Discriminated union variants with numeric or special character discriminant values now generate valid Swift identifiers using number-to-word conversion. --- # October 4, 2025 ## 0.18.0 **`(feat):`** Swift SDKs now include automatically generated wire tests via the `enableWireTests` option (defaults to true). ## 0.17.5 **`(fix):`** Fixed a bug where some discriminated union variants were missing the container declaration statement in their `encode(to:)` method body. ## 0.17.4 **`(fix):`** Fixed missing `gitUrl` and `minVersion` values in SPM installation instructions in README. ## 0.17.3 **`(fix):`** Reduced subclient class initializer access level to `internal`. --- # September 30, 2025 ## 0.17.2 **`(fix):`** Upgraded generator-cli dependency to fix local generation handling of .fernignore files. --- # September 25, 2025 ## 0.17.1 **`(fix):`** Fixed incorrect handling of `self` keyword in struct property names. --- # September 22, 2025 ## 0.17.0 **`(feat):`** Added `multipart/form-data` request support with autogenerated `fileUpload` request structs and automatic `Content-Type` boundary handling. --- # September 18, 2025 ## 0.16.0 **`(feat):`** Added support for custom sections in the README.md via `customSections` config option. --- # September 17, 2025 ## 0.15.0 **`(feat):`** Added `reference.md` generation with endpoint method details and usage examples. --- # September 14, 2025 ## 0.14.0 **`(feat):`** Autogenerated README now includes request types, additional headers, additional query string parameters, timeouts, and custom networking client sections. --- # September 12, 2025 ## 0.13.0 **`(feat):`** Introduced `Nullable` container type and related extensions to support explicit nulls. --- # September 9, 2025 ## 0.12.4 **`(fix):`** Fixed incorrect handling of schema `date` fields — now decoded into a new `CalendarDate` type. ## 0.12.3 **`(fix):`** Added missing system dependencies (bash, curl, git, zip) to Swift generator Docker image to fix README generation. --- # September 5, 2025 ## 0.12.2 **`(fix):`** Request headers in endpoint methods are now restricted to String types only. ## 0.12.1 **`(fix):`** Required bearer token param in root client convenience initializer is now correctly marked as `@escaping` and the relevant argument is now initialized properly. --- # September 4, 2025 ## 0.12.0 **`(feat):`** Added autogenerated README for Swift SDKs with dynamic usage snippets. --- # September 3, 2025 ## 0.11.1 **`(fix):`** Fixed release-mode compilation error in `Core/Networking/HTTPClient.swift` where a guard used precondition (returns `Void`) and could be flagged as falling through. Switched to `preconditionFailure` (returns `Never`) to satisfy the compiler at all optimization levels. --- # August 26, 2025 ## 0.11.0 **`(feat):`** Added `moduleName` generator config option to allow customizing the module name. --- # August 24, 2025 ## 0.10.0 **`(feat):`** Namespaced inline request structs under a non-instantiable container enum to reduce the probability of top-level symbol name collisions. --- # August 19, 2025 ## 0.9.0 **`(feat):`** Added `clientClassName` and `environmentEnumName` generator config options for custom naming. --- # August 18, 2025 ## 0.8.0 **`(feat):`** Added GitHub publishing support. --- # August 16, 2025 ## 0.7.0 **`(feat):`** Added sanitization for literal enum values to generate valid and readable names. ## 0.6.0 **`(chore):`** Upgraded to IR v59. --- # August 15, 2025 ## 0.5.0 **`(feat):`** Added 'fileDownload' response support. --- # August 14, 2025 ## 0.4.1 **`(fix):`** Fixed an infinite recursion bug in Swift SDKs where convenience initializers without auth schemes could ambiguously call the designated initializer. The generator now always passes arguments explicitly to avoid ambiguity. --- # August 13, 2025 ## 0.4.0 **`(feat):`** Added support for string literal types. --- # August 11, 2025 ## 0.3.0 **`(feat):`** Removed implicit Foundation import by deleting Prelude.swift and adding explicit imports to all source files. --- # August 10, 2025 ## 0.2.0 **`(feat):`** Root client can now use an async token provider for bearer authentication. --- # August 8, 2025 ## 0.1.0 **`(feat):`** Implements support for header, bearer and basic authentication schemes in the Swift SDK. **`(fix):`** The root client initializer is now generated based on the auth schemes defined in the API, replacing the previous static signature. --- # August 6, 2025 ## 0.0.0 **`(feat):`** Initial beta release. --- # Rust quickstart > Get started with the Fern Rust SDK. Generate a Rust SDK by following the instructions on this page. This page assumes that you have: * An initialized `fern` folder. See [Set up the `fern` folder](/sdks/overview/quickstart). * A GitHub repository for your SDK. See [Project Structure](/sdks/overview/project-structure). ### Pass `fern check` Run `fern check` to ensure that your API definition is valid. If there are any errors, fix them before proceeding. If you're using an OpenAPI Specification, check out all of our [supported extensions](/learn/api-definition/openapi/extensions). Run the following command to add the Rust SDK generator to `generators.yml`: ```bash fern add fern-rust-sdk --group rust-sdk ``` `rust-sdk` is the name of the `generators.yml` group that configures your Rust SDK's output location and other metadata. You can customize this group name to differentiate between multiple SDKs across different languages (e.g., `python-sdk`, etc) in your organization. This command adds the following `group` to `generators.yml`: ```yaml title="generators.yml" rust-sdk: # group name generators: - name: fernapi/fern-rust-sdk version: 0.17.2 output: location: local-file-system path: ../sdks/rust ``` Run the following command to generate your SDK: ```bash fern generate --group rust-sdk ``` This creates a `sdks` folder in your current directory. The resulting folder structure looks like this: --- # Rust configuration > Configuration options for the Fern Rust SDK. You can customize the behavior of the Rust SDK generator in `generators.yml`: ```yaml {6-15} title="generators.yml" groups: rust-sdk: generators: - name: fernapi/fern-rust-sdk version: 0.17.2 config: clientClassName: YourClientName crateName: your-crate-name crateVersion: "1.0.0" dateTimeType: "offset" environmentEnumName: YourEnvironment enableWireTests: true ``` The name of the generated client struct. This allows you to customize the struct name that users will instantiate when using your SDK. The name of the generated Rust crate. This is used in `Cargo.toml` and determines how users will add your SDK as a dependency. The version of the generated crate. This is used in `Cargo.toml` for publishing to crates.io. Determines how timezone information is handled: * `offset`: Uses `DateTime` to preserve the original timezone from API responses * `utc`: Uses `DateTime` to normalize all datetimes to UTC regardless of their original timezone Both options accept any datetime format and assume UTC if no timezone is provided in the datetime string. The name of the generated environment enum. This allows you to customize the enum name that defines your API environments (such as production, staging, development). When enabled, generates [mock server (wire) tests](/learn/sdks/deep-dives/testing#mock-server-tests) to verify that the SDK sends the correct HTTP requests and correctly handles responses per the API spec. When enabled, generates code examples in the README and reference documentation. ### Package metadata Configure metadata for publishing to crates.io: ```yaml title="generators.yml" config: packageDescription: "SDK for the Plant Store API" packageLicense: "MIT" packageRepository: "https://github.com/your-org/your-sdk" packageDocumentation: "https://docs.example.com" ``` A description of the crate for crates.io. This appears in the crate's metadata and search results. The license identifier for the crate (e.g., "MIT", "Apache-2.0"). The URL of the crate's source repository. The URL of the crate's documentation. ### Dependencies Add custom dependencies to your generated SDK: ```yaml title="generators.yml" config: extraDependencies: tokio: "1.0" serde_json: "1.0" extraDevDependencies: mockall: "0.11" ``` Additional dependencies to include in the generated `Cargo.toml`. Specify as a map of crate names to version requirements. You can also specify full dependency specifications with features and default features: ```yaml title="generators.yml" config: extraDependencies: reqwest: version: "0.12" defaultFeatures: true ``` ```yaml title="generators.yml" config: extraDependencies: reqwest: version: "0.12" features: ["rustls-tls"] ``` Additional dev dependencies to include in the generated `Cargo.toml`. These are only used during development and testing. --- # Publishing to crates.io > How to publish the Fern Rust SDK to crates.io. Publish your public-facing Fern Rust SDK to the [crates.io registry](https://crates.io/). After following the steps on this page, you'll have a versioned crate published on crates.io. Versioned package published on crates.io This page assumes that you have: * An initialized `fern` folder. See [Set up the `fern` folder](/sdks/overview/quickstart). * A GitHub repository for your SDK. See [Project Structure](/sdks/overview/project-structure). ## Configure `generators.yml` Change the output location in `generators.yml` from `local-file-system` (the default) to `crates` to indicate that Fern should publish your crate directly to the crates.io registry: ```yaml title="generators.yml" {6-7} groups: rust-sdk: generators: - name: fernapi/fern-rust-sdk version: 0.17.2 output: location: crates ``` Your crate name must be unique in the crates.io registry, otherwise publishing your SDK will fail. Update your crate name if you haven't done so already: ```yaml title="generators.yml" {8} groups: rust-sdk: generators: - name: fernapi/fern-rust-sdk version: 0.17.2 output: location: crates package-name: your-crate-name ``` The `clientClassName` option controls the name of the generated client struct. This is the name users will use when instantiating your SDK client. ```yaml title="generators.yml" {9-10} groups: rust-sdk: generators: - name: fernapi/fern-rust-sdk version: 0.17.2 output: location: crates package-name: your-crate-name config: clientClassName: YourClientName # must be PascalCase ``` Add the path to your GitHub repository to `generators.yml`: ```yaml title="generators.yml" {11-12} groups: rust-sdk: generators: - name: fernapi/fern-rust-sdk version: 0.17.2 output: location: crates package-name: your-crate-name config: clientClassName: YourClientName github: repository: your-org/your-rust-sdk ``` ## Set up crates.io publishing authentication Log into [crates.io](https://crates.io/) using your GitHub account. 1. Click on your profile picture in the top right corner. 2. Select **Account Settings**. 3. Go to the **API Tokens** section. 1. Click **New Token**. 2. Name your token (e.g., "Fern SDK Publishing"). 3. Under **Scopes**, select **publish-new** to publish new crates and **publish-update** to update existing crates. 4. Click **Generate Token**. Create a new API token on crates.io Save your new token immediately. It won't be displayed again after you leave the page. Add `token: ${CRATES_IO_API_KEY}` to `generators.yml` to tell Fern to use the `CRATES_IO_API_KEY` environment variable for authentication when publishing to crates.io. ```yaml title="generators.yml" {9} groups: rust-sdk: generators: - name: fernapi/fern-rust-sdk version: 0.17.2 output: location: crates package-name: your-crate-name token: ${CRATES_IO_API_KEY} config: clientClassName: YourClientName github: repository: your-org/your-rust-sdk ``` ## Publish your SDK Decide how you want to publish your SDK to crates.io. You can use GitHub workflows for automated releases or publish directly via the CLI. Set up a release workflow via [GitHub Actions](https://docs.github.com/en/actions/get-started/quickstart) so you can trigger new SDK releases directly from your source repository. Open your source repository in GitHub. Click on the **Settings** tab in your repository. Then, under the **Security** section, open **Secrets and variables** > **Actions**. You can also use the url `https://github.com//settings/secrets/actions`. 1. Select **New repository secret**. 2. Name your secret `CRATES_IO_API_KEY`. 3. Add the corresponding token you generated above. 4. Click **Add secret**. 1. Select **New repository secret**. 2. Name your secret `FERN_TOKEN`. 3. Add your Fern token. If you don't already have one, generate one by running `fern token`. By default, the `fern_token` is generated for the organization listed in `fern.config.json`. 4. Click **Add secret**. Set up a CI workflow that you can manually trigger from the GitHub UI. In your repository, navigate to **Actions**. Select **New workflow**, then **Set up workflow yourself**. Add a workflow that's similar to this: ```yaml title=".github/workflows/publish.yml" maxLines=0 name: Publish Rust SDK on: workflow_dispatch: inputs: version: description: "The version of the Rust SDK that you would like to release" required: true type: string jobs: release: runs-on: ubuntu-latest steps: - name: Checkout repo uses: actions/checkout@v4 - name: Install Fern CLI run: npm install -g fern-api - name: Release Rust SDK env: FERN_TOKEN: ${{ secrets.FERN_TOKEN }} CRATES_IO_API_KEY: ${{ secrets.CRATES_IO_API_KEY }} run: | fern generate --group rust-sdk --version ${{ inputs.version }} --log-level debug ``` Navigate to the **Actions** tab, select the workflow you just created, specify a version number, and click **Run workflow**. This regenerates your SDK. The rest of the release process depends on your chosen mode: * **Release mode (default):** If you didn't specify a `mode` or set `mode: release`, no further action is required. Fern automatically tags the new release with your specified version number and initiates the publishing workflow in your SDK repository. * **Pull request or push mode:** If you set `mode: pull-request` or `mode: push`, Fern creates a pull request or pushes to a branch respectively. Review and merge the PR (`pull-request`) or branch (`push`), then [tag a new release](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository) to initiate the publishing workflow in your SDK repository. Once the workflow completes, you can view your new release by logging into crates.io, navigating to **Dashboard**, and looking under **My Crates**. Set the `CRATES_IO_API_KEY` environment variable on your local machine: ```bash export CRATES_IO_API_KEY=your-actual-rust-token ``` Regenerate your SDK, specifying the version: ```bash fern generate --group rust-sdk --version ``` The rest of the release process depends on your chosen mode: * **Release mode (default):** If you didn't specify a `mode` or set `mode: release`, no further action is required. Fern automatically tags the new release with your specified version number and initiates the publishing workflow in your SDK repository. * **Pull request or push mode:** If you set `mode: pull-request` or `mode: push`, Fern creates a pull request or pushes to a branch respectively. Review and merge the PR (`pull-request`) or branch (`push`), then [tag a new release](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository) to initiate the publishing workflow in your SDK repository. Once the workflow completes, you can view your new release by logging into crates.io, navigating to **Dashboard**, and looking under **My Crates**. --- # January 26, 2026 ## 0.17.2 **`(fix):`** Add serde helpers for base64 and BigInt types to properly serialize/deserialize these types in JSON. Add execute\_request\_base64 method for handling base64 primitive endpoint responses. Fix union variant serde rename to be case-sensitive for proper JSON deserialization. ## 0.17.1 **`(fix):`** Fix compilation errors when generating SDKs without streaming endpoints by conditionally including sse\_stream.rs only when streaming endpoints exist. Also fix missing FixedOffset import for DateTime types when dateTimeType is set to "offset" (the default). --- # January 22, 2026 ## 0.17.0 **`(feat):`** Add OAuthTokenProvider for automatic OAuth token management with caching and refresh support. The provider implements thread-safe token caching with a 2-minute expiration buffer, double-checked locking pattern for concurrent access, and automatic token refresh. --- # January 21, 2026 ## 0.16.0 **`(feat):`** Add `packageLicenseFile` config option to support custom license files. When set, uses `license-file` instead of `license` in Cargo.toml, allowing users to reference custom LICENSE.md files that are not standard SPDX identifiers. ## 0.15.0 **`(feat):`** Add platform headers (X-Fern-Language, X-Fern-SDK-Name, X-Fern-SDK-Version) to all HTTP requests. These headers help identify SDK usage and version for API analytics and debugging. --- # January 13, 2026 ## 0.14.3 **`(chore):`** Update Dockerfile to use the latest generator-cli with improve reference.md generation. ## 0.14.2 **`(fix):`** Remove redundant type imports from README code snippets. The prelude import already re-exports all types via `pub use crate::api::*;`, so the additional explicit type imports were unnecessary. --- # January 8, 2026 ## 0.14.1 **`(chore):`** Support complex dependency specs in extraDependencies and extraDevDependencies config. Dependencies can now be specified as either version strings or full RustDependencySpec objects with features, optional, git, path, and other Cargo.toml options. Also made API key header name configurable via IR auth schemes. --- # January 7, 2026 ## 0.14.0 **`(feat):`** Change default datetime type to `DateTime` with flexible parsing. This preserves original timezone offsets from server responses while accepting any datetime format (with or without timezone). When no timezone is provided, UTC is assumed. Use `dateTimeType: "utc"` to convert all datetimes to UTC instead. --- # January 5, 2026 ## 0.13.10 **`(chore):`** Update Dockerfile CVE patches to work with newer generator-cli package structures. --- # December 24, 2025 ## 0.13.9 **`(fix):`** Preserve parameter order in dynamic snippets to match API schema definition order. Struct fields in generated Rust code now appear in the same order as defined in the API specification. --- # December 22, 2025 ## 0.13.8 **`(fix):`** Fix wire test request type naming to use IR declaration names instead of synthetic endpoint-based names. This ensures generated tests use correct type names like ResponseChargeBack instead of AddResponseRequest. ## 0.13.7 **`(fix):`** Fix wire test compilation by avoiding Default::default() on non-Default types. Always explicitly provide all fields in generated wire tests instead of relying on Default trait derivation. --- # December 21, 2025 ## 0.13.6 **`(fix):`** dynamic snippets to match struct naming and default handling --- # December 18, 2025 ## 0.13.5 **`(chore):`** Add sdkVersion as a top-level field in the generated metadata.json file. --- # December 2, 2025 ## 0.13.4 **`(fix):`** Fix getGitHubConfig to return RawGithubConfig with undefined values instead of throwing errors when publishing config is missing, aligning with TypeScript/Python generator behavior. --- # November 26, 2025 ## 0.13.3 **`(fix):`** Remove error on null config in README generation. --- # November 25, 2025 ## 0.13.2 **`(chore):`** add circular reference detection and Box wrapping for recursive types --- # November 24, 2025 ## 0.13.1 **`(chore):`** improved docs.rs with module documentation and dynamic getting started snippets --- # November 19, 2025 ## 0.13.0 **`(feat):`** enable custom Cargo features and conditional dependency management ## 0.12.1 **`(chore):`** Bump generator CLI version to publish new Docker image. ## 0.12.0 **`(feat):`** add wire test generation with WireMock integration --- # November 7, 2025 ## 0.11.0 **`(feat):`** add file upload multipart/form-data support --- # November 4, 2025 ## 0.10.0 **`(feat):`** Added Generation Metadata file to output --- # October 25, 2025 ## 0.8.4 **`(chore):`** add FileUploadRequestBody type generation support and sanitize queryparams fields name --- # October 24, 2025 ## 0.9.0 **`(feat):`** Add Server-Sent Events (SSE) streaming support with SseStream type ## 0.8.3 **`(fix):`** build failures for content-types, enum, literals, empty-clients requestbody, multi-url-environment-no-default seed fixtures --- # October 21, 2025 ## 0.8.2 **`(chore):`** resolve client name collisions in recursive subpackages and clean up unused imports --- # October 20, 2025 ## 0.8.1 **`(chore):`** auto-generate publish workflow based on publishConfig --- # October 17, 2025 ## 0.8.0 **`(feat):`** Add file download support with ByteStream ## 0.7.3 **`(chore):`** enable show log only on --log-level debug --- # October 15, 2025 ## 0.7.2 **`(chore):`** Upgraded to IR v61 and --version params support ## 0.7.1 **`(chore):`** add readme generation headers, query params and request type --- # October 11, 2025 ## 0.7.0 **`(feat):`** add native crates.io publishing support for Rust SDKs --- # October 7, 2025 ## 0.6.0 **`(feat):`** Add recursive type detection and Box wrapping for structs ## 0.5.6 **`(chore):`** refactor struct type name collision disable cursor pagination ## 0.5.5 **`(chore):`** Add new readme config fields to ReadmeConfigBuilder --- # October 3, 2025 ## 0.5.4 **`(chore):`** Disable doctests and export root client in generator ## 0.5.3 **`(chore):`** Fix type name collisions and improve trait derivation for extended types --- # October 2, 2025 ## 0.5.2 **`(fix):`** use crate prelude::\* for single source of truth for imports, remove wildcard exports --- # September 29, 2025 ## 0.5.1 **`(fix):`** Upgrade generator-cli dependency to fix local generation handling of .fernignore files. ## 0.5.0 **`(feat):`** add reference.md support and some fixes for dynamic-snippets ## 0.4.0 **`(feat):`** Add customizable SDK configuration and dynamic snippets test generator --- # September 24, 2025 ## 0.3.0 **`(feat):`** Add documentation comments and remove warning for unused imports/exports --- # September 23, 2025 ## 0.2.1 **`(chore):`** Add request parameter type generation support --- # September 20, 2025 ## 0.2.0 **`(feat):`** Restructure Rust SDK to have correct support for sub-client folders and query builder pattern ## 0.1.1 **`(chore):`** Upgraded to IR v59. --- # September 18, 2025 ## 0.1.0 **`(feat):`** base CI workflow --- # September 17, 2025 ## 0.0.9 **`(fix):`** Fixes an issue where the generated usage snippets in the README.md was not prioritizing user defined example values over autogenerated example values. --- # September 10, 2025 ## 0.0.8 **`(chore):`** enhanced error handling and rustfmt --- # August 27, 2025 ## 0.0.7 **`(fix):`** Fixed semver for changelog validation. --- # August 16, 2025 ## 0.0.6 **`(feat):`** Added pagination support --- # August 13, 2025 ## 0.0.5 **`(chore):`** enable git and git config ## 0.0.4 **`(fix):`** Updated generator CLI SDK version to 0.0.33 for consistency. ## 0.0.3 **`(feat):`** Added README generation support. --- # August 11, 2025 ## 0.0.2 **`(feat):`** Updated package name. ## 0.0.1 **`(feat):`** First stable release with core SDK functionality --- # July 25, 2025 ## 0.0.0 **`(feat):`** Initial beta release. --- # Postman quickstart > Generate a postman collection full of example requests and responses A Postman collection contains ready-to-use HTTP requests with example payloads and responses that developers can immediately test and explore in Postman. Each API definition generates one complete collection with all endpoints organized into folders. Generate a Postman collection by following the instructions on this page. This page assumes that you have an initialized `fern` folder on your local machine. See [Set up the `fern` folder](/sdks/overview/quickstart). ### Pass `fern check` Run `fern check` to ensure that your API definition is valid. If there are any errors, fix them before proceeding. If you're using an OpenAPI Specification, check out all of our [supported extensions](/learn/api-definition/openapi/extensions). ### Add the Postman generator Run the following command to add the Postman generator to `generators.yml`: ```sh fern add fern-postman --group postman ``` `postman` is the name of the `generators.yml` group that configures your Postman collection's output location and other metadata. You can customize this group name to differentiate between multiple collections if you have multiple APIs in your organization. This command adds the following `group` to `generators.yml`: ```yaml title="generators.yml" {2-8} groups: postman: generators: - name: fernapi/fern-postman version: 0.0.45 output: location: local-file-system path: ../postman ``` ### Generate the collection Run the following command: ```sh fern generate --group postman ``` If you have multiple APIs, use the [`--api` flag](/cli-api-reference/cli-reference/commands#api) to specify the API you want to generate: ```bash fern generate --group postman --api your-api-name ``` This creates a Postman collection on Fern's cloud. Once complete, you'll see a `collection.json`: --- # Publishing to Postman > Publish a Postman collection full of example requests and responses Publish your Postman collection directly to Postman workspaces, making it easy for your team and API consumers to discover and test your endpoints. Collection published on Postman This page assumes that you have: * An initialized `fern` folder. See [Set up the `fern` folder](/sdks/overview/quickstart). * A GitHub repository for your Postman collection. See [Project structure](/sdks/overview/project-structure). * A Postman generator group in `generators.yml`. See [Postman Quickstart](quickstart#add-the-sdk-generator). ## Generate an API key Log into [Postman](https://www.postman.com/) or create a new account. 1. Click on your profile picture. 2. Select **Settings**. 3. Select **API Keys**. Collection published on Postman Click on **Generate API Key**. Name your key, then click **Generate**. Save your new token – it won't be displayed after you leave the page. ## Configure Postman publication You'll need to update your `generators.yml` file to configure the output location, repository, publishing mode, and authentication credentials for Postman publishing. Your `generators.yml` [should live in your source repository](/sdks/overview/project-structure) (or on your local machine), not the repository that contains your Postman collection file. In the `group` for your Postman collection, change the output location from `local-file-system` (the default) to `postman` to indicate that Fern should publish your collection directly to Postman: ```yaml {6-7} title="generators.yml" groups: postman: # Group name for your Postman collection generators: - name: fernapi/fern-postman version: 0.5.0 output: location: postman ``` Add the path to the GitHub repository containing your Postman collection: ```yaml {8-9} title="generators.yml" groups: postman: generators: - name: fernapi/fern-postman version: 0.5.0 output: location: postman github: repository: your-org/company-postman ``` Optionally set the mode to control how Fern handles Postman publishing: * `mode: release` (default): Fern generates code, commits to main, and tags a release automatically * `mode: pull-request`: Fern generates code and creates a PR for you to review before release * `mode: push`: Fern generates code and pushes to a branch you specify for you to review before release You can also configure other settings, like the reviewers or license. Refer to the [full `github` (`generators.yml`) reference](/sdks/reference/generators-yml#github) for more information. ```yaml {10} title="generators.yml" groups: postman: generators: - name: fernapi/fern-postman version: 0.5.0 output: location: postman github: repository: your-org/company-postman mode: push branch: your-branch-name ``` Add `api-key: ${POSTMAN_API_KEY}` to `generators.yml` to tell Fern to use your API key for authentication when publishing to a Postman collection. ```yaml {8} title="generators.yml" groups: postman: generators: - name: fernapi/fern-postman version: 0.5.0 output: location: postman api-key: ${POSTMAN_API_KEY} github: repository: your-org/company-postman ``` ## Choose your versioning approach Fern's Postman publishing uses a simple versioning approach based on whether you specify a `collection-id`: * **Update existing collection:** Specify `collection-id`. Fern updates the same collection each time. Use this option to keep your workspace clean with one collection that is always current. * **Create new collections:** Omit `collection-id`. Fern creates a new collection with each publish. Use this option to maintain historical versions or separate environment collections. You can get your workspace ID by navigating to your workspace and either: * Copying the ID from the URL: `https://user-name.postman.co/workspace/workspace-name~WORKSPACE-ID/request/create` * Making a GET request to `https://api.getpostman.com/workspaces`. You must also enter your API key in the **Auth** tab. This request returns configuration, including IDs, for all of your workspaces. Collection published on Postman ```yaml title="generators.yml" {9} groups: postman: generators: - name: fernapi/fern-postman version: 0.4.0 output: location: postman api-key: ${POSTMAN_API_KEY} workspace-id: your-workspace-id github: repository: your-org/company-postman ``` Set the name for your new collection. Each time you publish, Fern creates a new collection with this name in the specified workspace. ```yaml title="generators.yml" {10-11} groups: postman: generators: - name: fernapi/fern-postman version: 0.5.0 output: location: postman api-key: ${POSTMAN_API_KEY} workspace-id: your-workspace-id config: collection-name: My collection name # Creates new collection called "My collection name" github: repository: your-org/company-postman ``` To publish to a existing collection, specify the workspace ID, existing collection ID, and name of the existing collection. You can get your workspace ID by navigating to your workspace and either: * Copying the ID from the URL: `https://user-name.postman.co/workspace/workspace-name~WORKSPACE-ID/request/create` * Making a GET request to `https://api.getpostman.com/workspaces`. You must also enter your API key in the **Auth** tab. This request returns configuration, including IDs, for all of your workspaces. Collection published on Postman ```yaml title="generators.yml" {9} groups: postman: generators: - name: fernapi/fern-postman version: 0.4.0 output: location: postman api-key: ${POSTMAN_API_KEY} workspace-id: your-workspace-id github: repository: your-org/company-postman ``` You can get your collection name and ID by navigating to your workspace and either: * Copying the ID from the URL: `https://user-name.postman.co/workspace/workspace-name~workspace-id/collection/COLLECTION-ID` * Making a GET request to `https://api.getpostman.com/collections`. You must also enter your API key in the **Auth** tab. Send the request. This request returns configuration, including IDs and names, for all of your collections. ```yaml title="generators.yml" {10-12} groups: postman: generators: - name: fernapi/fern-postman version: 0.5.0 output: location: postman api-key: ${POSTMAN_API_KEY} workspace-id: your-workspace-id collection-id: your-collection-id config: collection-name: Your collection name # Name of the existing collection github: repository: your-org/company-postman ``` ## Publish your collection Decide how you want to publish your collection to Postman. You can use GitHub workflows for automated releases or publish directly via the CLI. Set up a release workflow via [GitHub Actions](https://docs.github.com/en/actions/get-started/quickstart) so you can trigger new Postman collection releases directly from your source repository. Open your source repository in GitHub. Click on the **Settings** tab. Then, under the **Security** section, open **Secrets and variables** > **Actions**. You can also use the url `https://github.com//settings/secrets/actions`. 1. Select **New repository secret**. 2. Name your secret `POSTMAN_API_KEY`. 3. Add the corresponding API key you generated above. 4. Click **Add secret**. 1. Select **New repository secret**. 2. Name your secret `FERN_TOKEN`. 3. Add your Fern token. If you don't already have one, generate one by running `fern token`. By default, the `fern_token` is generated for the organization listed in `fern.config.json`. 4. Click **Add secret**. Set up a CI workflow that you can manually trigger from the GitHub UI. In your repository, navigate to **Actions**. Select **New workflow**, then **Set up workflow yourself**. Add a workflow that's similar to this: ```yaml title=".github/workflows/publish.yml" maxLines=0 name: Publish Postman collection on: workflow_dispatch: inputs: version: description: "The version of the Postman collection that you would like to release" required: true type: string jobs: release: runs-on: ubuntu-latest steps: - name: Checkout repo uses: actions/checkout@v4 - name: Install Fern CLI run: npm install -g fern-api - name: Release Postman collection env: FERN_TOKEN: ${{ secrets.FERN_TOKEN }} POSTMAN_API_KEY: ${{ secrets.POSTMAN_API_KEY }} run: | fern generate --group postman --version ${{ inputs.version }} --log-level debug ``` You can alternatively configure your workflow to execute `on: [push]`. See Vapi's [npm publishing GitHub Action](https://github.com/VapiAI/server-sdk-typescript/blob/main/.github/workflows/ci.yml) for an example. Navigate to the **Actions** tab, select the workflow you just created, specify a version number, and click **Run workflow**. This regenerates your collection. Specifying the version number will update the release number in your GitHub repository, but won't version your collection. The rest of the release process depends on your chosen mode: * **Release mode (default):** If you didn't specify a `mode` or set `mode: release`, no further action is required. Fern initiates the publishing workflow in your collection repository. * **Pull request or push mode:** If you set `mode: pull-request` or `mode: push`, Fern creates a pull request or pushes to a branch respectively. Review and merge the PR (`pull-request`) or branch (`push`), then [tag a new release](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository) to initiate the publishing Once the workflow completes, you can view your new or updated collection by logging into Postman and navigating to your workspace. Collection published on Postman Set the `POSTMAN_API_KEY` environment variable on your local machine: ```bash export POSTMAN_API_KEY=your-actual-postman-api-key ``` Regenerate your collection. The `--version` parameter in `fern generate --version X.X.X` creates a GitHub release tag but doesn't affect Postman collection naming or versioning. Collection versioning is controlled by the `collection-id` configuration. ```bash fern generate --group postman --version ``` The rest of the release process depends on your chosen mode: * **Release mode (default):** If you didn't specify a `mode` or set `mode: release`, no further action is required. Fern initiates the publishing workflow in your collection repository. * **Pull request or push mode:** If you set `mode: pull-request` or `mode: push`, Fern creates a pull request or pushes to a branch respectively. Review and merge the PR (`pull-request`) or branch (`push`), then [tag a new release](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository) to initiate the publishing Once the workflow completes, you can view your new or updated collection by logging into Postman and navigating to your workspace. Collection published on Postman --- # SDK user features > Learn about SDK user features in Fern-generated client libraries including installation, error handling, webhook verification, and customization options. Fern-generated SDKs provide a consistent set of features across all languages to help developers interact with your API. Usage information is auto-generated in your SDK's `README.md`, [which you can customize](./readme). For a complete example of a generated SDK README, see [Intercom's Python SDK](https://github.com/intercom/python-intercom/blob/3aac991a92cefe34cf437f8f5ca46c97c04c1a6c/README.md). ## Installation and basic usage Users install SDKs using standard package managers (npm for TypeScript, pip for Python, Maven/Gradle for Java, etc.) from language-specific registries. Users initialize the client with your API's base URL and any required authentication, then call methods on the client to interact with your API. Generated SDKs support modern runtimes across languages. ## Reference The `README.md` file links to an auto-generated `reference.md` file ([example](https://github.com/intercom/python-intercom/blob/HEAD/reference.md)) that lists all available API methods organized by resource, including method signatures with parameter types, usage examples, and request/response structures for each endpoint. ## IDE support and IntelliSense Fern-generated SDKs include full type definitions that enable rich IDE support. When developers use your SDK in editors like VS Code, they get autocomplete, inline documentation, and type information. The inline documentation comes from your API definition. During the SDK generation process, Fern embeds your parameter descriptions, return types, and code examples directly in the code as docstrings (Python), JSDoc (TypeScript), Javadoc (Java), etc.