From dd2663d1446ab2a59607dbd8a78eb9280b331a9d Mon Sep 17 00:00:00 2001 From: Kapil Gowru Date: Thu, 31 Jul 2025 15:24:28 -0600 Subject: [PATCH 1/3] Update parameter-names.mdx based on issue #266 --- .../pages/extensions/parameter-names.mdx | 93 ++++++++++++++++--- 1 file changed, 82 insertions(+), 11 deletions(-) diff --git a/fern/products/openapi-def/pages/extensions/parameter-names.mdx b/fern/products/openapi-def/pages/extensions/parameter-names.mdx index ff60bf613..b83a4592b 100644 --- a/fern/products/openapi-def/pages/extensions/parameter-names.mdx +++ b/fern/products/openapi-def/pages/extensions/parameter-names.mdx @@ -1,16 +1,48 @@ --- title: Customize parameter names -description: Use `x-fern-parameter-name` to customize query parameter, header and path parameter naming. +description: Learn how to customize parameter naming in generated SDKs using OpenAPI extensions. --- - The `x-fern-parameter-name` extension allows you to customize the variable names of parameters in your generated SDKs. + Fern provides several extensions to customize how API parameters are handled in your generated SDKs. -## Headers +## Parameter Naming Extensions -In the example below, the header `X-API-Version` is renamed to `version` in the -generated SDK. The rename makes the SDK more human readable. +### x-fern-parameter-name + +Use `x-fern-parameter-name` to customize how individual parameters are named in your SDK, making them more readable and intuitive. + +```yaml +paths: + "/users": + get: + parameters: + - in: header + name: X-API-Version + x-fern-parameter-name: version + schema: + type: string +``` + +### x-fern-sdk-variables + +Use `x-fern-sdk-variables` to define parameters that should be passed through the SDK client constructor rather than individual method calls. + +```yaml +components: + x-fern-sdk-variables: + project_id: + type: string + description: "The project ID to use for all API calls" + pattern: "^proj_[a-zA-Z0-9]+$" +``` + +## Usage Examples + +### Headers + +Rename HTTP headers to be more readable in your SDK: ```yaml {8} paths: @@ -26,10 +58,9 @@ paths: required: true ``` -## Query parameters +### Query Parameters -In the example below, the query parameter `q` is renamed to `search_terms` in the -generated SDK. The rename makes the parameter more approachable for end users. +Make query parameter names more descriptive: ```yaml {8} paths: @@ -45,10 +76,9 @@ paths: required: false ``` -## Path parameters +### Path Parameters -In the example below, the path parameter `userId` is renamed to `id` in the -generated SDK. The rename makes the SDK less verbose. +Simplify path parameter names: ```yaml {8} paths: @@ -63,3 +93,44 @@ paths: type: string required: false ``` + +### Constructor Variables + +Define parameters that should be set once in the client constructor: + +```yaml +components: + x-fern-sdk-variables: + project_id: + type: string + description: "Project identifier used across all API calls" + pattern: "^proj_[a-zA-Z0-9]+$" + +paths: + "/v1/connect/{project_id}/accounts": + parameters: + - name: project_id + in: path + required: true + schema: + type: string + pattern: "^proj_[a-zA-Z0-9]+$" + x-fern-sdk-variable: project_id +``` + +This allows you to initialize the client with the project ID once: + +```python +client = YourAPIClient(project_id="proj_123") +``` + +Rather than passing it to every method: + +```python +# Not needed when using x-fern-sdk-variables +client.get_accounts(project_id="proj_123") +``` + + + The `x-fern-sdk-variables` extension is supported in Python SDKs version 4.24.0 and later. + \ No newline at end of file From 81e9ad76fabc000db8e97ced4cf4e1efe0a6efc3 Mon Sep 17 00:00:00 2001 From: Kapil Gowru Date: Thu, 31 Jul 2025 15:24:28 -0600 Subject: [PATCH 2/3] Update configuration.mdx based on issue #266 --- .../sdks/overview/python/configuration.mdx | 52 ++++++++++++------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/fern/products/sdks/overview/python/configuration.mdx b/fern/products/sdks/overview/python/configuration.mdx index 1c0eb6af7..15b71a836 100644 --- a/fern/products/sdks/overview/python/configuration.mdx +++ b/fern/products/sdks/overview/python/configuration.mdx @@ -21,6 +21,7 @@ groups: ## SDK Configuration Options + Additional exports to include in the package's __init__.py file. @@ -28,6 +29,7 @@ groups: + When enabled, type definitions will not be exported in the package's __init__.py file. @@ -40,12 +42,15 @@ groups: + Additional development dependencies to include in the generated package. + Define optional feature sets and their dependencies. + When enabled, generates a flatter directory structure without nested resource folders. @@ -53,18 +58,28 @@ groups: - Feature flag that improves imports in the Python SDK by removing nested `resources` directory + 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 + Whether or not to include legacy wire tests in the generated SDK. + When enabled, generates utility methods for working with union types. - If true, treats path parameters as named parameters in endpoint functions. + If true, treats path parameters as named parameters in endpoint functions. This allows using common variables like project_id across multiple endpoints: + + ```yaml + config: + inline_path_params: true + x-fern-sdk-variables: + project_id: + type: string + description: The project ID to use for all requests + ``` @@ -72,26 +87,24 @@ groups: - -Specifies the Python package name that users will import your generated client -from. + 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: - -```yaml {7-10} -default-group: local -groups: - local: - generators: - - name: fernapi/fern-python + For example, setting `package_name: "my_custom_package"` enables users to use `my_custom_package import Client` to import your client: + + ```yaml {7-10} + default-group: local + groups: + local: + generators: + - name: fernapi/fern-python version: 0.7.1 config: package_name: "my_custom_package" -``` + ``` + Customize how Pydantic models are generated. @@ -112,8 +125,8 @@ groups: # 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), + circle=lambda circle: do_something_with_circle(circle), + triangle=lambda triangle: do_something_with_triangle(triangle), ) ``` @@ -140,6 +153,7 @@ groups: + Custom pyproject.toml content to include in the generated package. @@ -147,6 +161,7 @@ groups: + When true, skips code formatting of generated files. @@ -154,6 +169,7 @@ groups: + When enabled, includes the API name in the generated package name. From de443429770ec8a08cf19f98a05ef6d1e4b95bbb Mon Sep 17 00:00:00 2001 From: Kapil Gowru Date: Thu, 31 Jul 2025 15:24:29 -0600 Subject: [PATCH 3/3] Update configuration.mdx based on issue #266 --- .../overview/typescript/configuration.mdx | 320 ++++++------------ 1 file changed, 105 insertions(+), 215 deletions(-) diff --git a/fern/products/sdks/overview/typescript/configuration.mdx b/fern/products/sdks/overview/typescript/configuration.mdx index 6fc216209..6385165bb 100644 --- a/fern/products/sdks/overview/typescript/configuration.mdx +++ b/fern/products/sdks/overview/typescript/configuration.mdx @@ -11,7 +11,7 @@ groups: local: generators: - name: fernapi/fern-typescript-sdk - version: + version: config: namespaceExport: Acme ``` @@ -23,6 +23,7 @@ Allow fields that are not defined in object schemas. This only applies to serde. +Bundle the SDK into a single file. @@ -96,7 +97,6 @@ config: extraDependencies: lodash: "3.0.2" ``` - @@ -130,9 +130,11 @@ 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" + extraPeerDependenciesMeta: + react: + optional: true + "react-dom": + optional: true ``` @@ -165,7 +167,6 @@ Choose whether you want to support Node.js 16 and above (`Node16`), or Node.js 1 - Includes the content type and content length from binary responses. The user will receive an object of the following type: ```typescript @@ -180,13 +181,15 @@ Includes the content type and content length from binary responses. The user wil - When enabled, [`withCredentials`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials) is set to `true` when making network requests. +When enabled, [`withCredentials`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials) is set to `true` when making network requests. +Include an "other" variant in union types to handle unknown values. +Include utility methods on union type members. @@ -238,7 +241,6 @@ public async post( ... } ``` - @@ -254,68 +256,66 @@ await service.getFoo("pathParamValue", { id: "SOME_ID" }); ```typescript await service.getFoo({ pathParamName: "pathParamValue", id: "SOME_ID" }); ``` - By default, names are based on the organization and API names in the Fern Definition: - ```typescript - import { AcmeApi, AcmeApiClient } from "@acme/node"; - ``` - - `namespaceExport` customizes the exported namespace and client names: +```typescript +import { AcmeApi, AcmeApiClient } from "@acme/node"; +``` - ```yaml - # generators.yml - config: - namespaceExport: Acme - ``` +`namespaceExport` customizes the exported namespace and client names: - ```typescript - import { Acme, AcmeClient } from "@acme/node"; - ``` +```yaml +# generators.yml +config: + namespaceExport: Acme +``` +```typescript +import { Acme, AcmeClient } 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`](packages/core-utilities/fetcher/src/APIResponse.ts). - - ```typescript - const response = await client.callEndpoint(...); - if (response.ok) { - console.log(response.body) - } else { - console.error(respons.error) - } - ``` +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`](packages/core-utilities/fetcher/src/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; - } - ``` +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; +} +``` @@ -323,24 +323,21 @@ Prevent the generator from running any scripts such as `yarn format` or `yarn in - No serialization/deserialization code is generated by default. The client uses `JSON.parse()` and `JSON.stringify()` instead of the default Serde layer. - When `noSerdeLayer: false`, the generated client includes a layer for serializing requests and deserializing responses. This has three benefits: +When `noSerdeLayer: false`, the generated client includes a layer for serializing requests and deserializing responses. This has three benefits: - 1. The client validates requests and response at runtime (client-side). +1. The client validates requests and response at runtime (client-side). - 1. The client can support complex types like `Date` and `Set`. - - 1. The generated types can stray from the wire/JSON representation to be more - idiomatic. For example, when the Serde layer is enabled (`noSerdeLayer: false`), all properties are `camelCase`, even if the server is expecting `snake_case`. +2. The client can support complex types like `Date` and `Set`. +3. The generated types can stray from the wire/JSON representation to be more idiomatic. For example, when the Serde layer is enabled (`noSerdeLayer: false`), all properties are `camelCase`, even if the server is expecting `snake_case`. - When enabled, the generator outputs raw TypeScript files. When disabled (the default), outputs `.js` and `d.ts` files. +When enabled, the generator outputs raw TypeScript files. When disabled (the default), outputs `.js` and `d.ts` files. - This only applies when dumping code locally. This configuration is ignored when publishing to Github or npm. +This only applies when dumping code locally. This configuration is ignored when publishing to Github or npm. @@ -366,64 +363,63 @@ 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. +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; - } - ``` +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. +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). +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`). + + +The path to which the SDK variables should be passed in API requests. If not specified, defaults to `x-fern-sdk-variables` extension field from OpenAPI/Fern spec. @@ -435,110 +431,4 @@ Change the type of stream that is used in the generated SDK. 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 (`no-serde: 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 (`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*: - -```yaml -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; -} -``` - - - - - 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); - ``` - - \ No newline at end of file +