diff --git a/fern/products/openapi-def/pages/extensions/parameter-names.mdx b/fern/products/openapi-def/pages/extensions/parameter-names.mdx index ff60bf61..ec562938 100644 --- a/fern/products/openapi-def/pages/extensions/parameter-names.mdx +++ b/fern/products/openapi-def/pages/extensions/parameter-names.mdx @@ -1,41 +1,55 @@ --- title: Customize parameter names -description: Use `x-fern-parameter-name` to customize query parameter, header and path parameter naming. +description: Use extensions to customize parameter naming in your generated SDKs. --- - The `x-fern-parameter-name` extension allows you to customize the variable names of parameters in your generated SDKs. + Extensions allow you to customize how parameters are named and handled in your generated SDKs to improve readability and usability. -## Headers +## Header 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 +Renames a header parameter in the generated SDK for better readability. -```yaml {8} +```yaml paths: "/user": get: - operationId: list_user parameters: - in: header - name: X-API-Version + name: X-API-Version x-fern-parameter-name: version schema: type: string required: true ``` -## 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. +### x-fern-sdk-header +Marks a header to be provided in the SDK client constructor rather than per-request. ```yaml {8} +paths: + "/user": + get: + parameters: + - in: header + name: X-API-Key + schema: + x-fern-sdk-header: api_key + type: string + required: true +``` + +## Query Parameter Extensions + +### x-fern-parameter-name +Renames a query parameter in the generated SDK to be more descriptive. + +```yaml paths: "/user/search": get: - operationId: search_user parameters: - in: query name: q @@ -45,21 +59,61 @@ paths: required: false ``` -## 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. +### x-fern-sdk-variable +Marks a query parameter to be provided in the SDK client constructor. ```yaml {8} +paths: + "/user/search": + get: + parameters: + - in: query + name: org_id + schema: + x-fern-sdk-variable: organization_id + type: string + required: true +``` + +## Path Parameter Extensions + +### x-fern-parameter-name +Renames a path parameter in the generated SDK for conciseness. + +```yaml paths: "/user/{userId}": get: - operationId: get_user parameters: - in: path name: userId x-fern-parameter-name: id schema: type: string - required: false + required: true ``` + +### x-fern-sdk-variable +Marks a path parameter to be provided in the SDK client constructor. This is useful for values that are common across many endpoints. + +```yaml +paths: + "/projects/{project_id}/users": + get: + parameters: + - in: path + name: project_id + schema: + x-fern-sdk-variable: project_id + type: string + pattern: "^proj_[a-zA-Z0-9]+$" + required: true +``` + + + When using `x-fern-sdk-variable` or `x-fern-sdk-header`, the specified value will be provided once in the client constructor rather than needing to be passed to each individual API call. + + + + Use these extensions strategically to create a more ergonomic SDK. Consider renaming cryptic parameter names to be more descriptive, and moving commonly used values like API keys or project IDs to the client constructor. + \ No newline at end of file diff --git a/fern/products/sdks/overview/python/configuration.mdx b/fern/products/sdks/overview/python/configuration.mdx index 1c0eb6af..6b5a39a9 100644 --- a/fern/products/sdks/overview/python/configuration.mdx +++ b/fern/products/sdks/overview/python/configuration.mdx @@ -21,6 +21,36 @@ groups: ## SDK Configuration Options + Additional exports to include in the package's __init__.py file. + + + + Configuration for the generated client class and file structure. + + ```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. + + + + 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. @@ -28,6 +58,18 @@ groups: + Whether to exclude type definitions from the package's __init__.py exports. + + + + Headers to inject into all requests made by the client. Useful for custom authentication or tracking. + + ```yaml + config: + extension_headers: + x-custom-header: "custom-value" + x-api-key: "default-key" + ``` @@ -40,12 +82,15 @@ groups: + Additional development dependencies to include in the generated package. + Optional feature groups that can be installed with the package. + Whether to generate a flat file structure instead of nested directories. @@ -53,14 +98,15 @@ 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. + Whether to include utility functions for working with union types. @@ -72,26 +118,18 @@ 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: + For example, setting `package_name: "my_custom_package"` enables users to use `from 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" -``` + ```yaml + config: + package_name: "my_custom_package" + ``` - + + Configuration options for Pydantic model generation. @@ -140,6 +178,7 @@ groups: + Custom pyproject.toml content to include in the generated package. @@ -147,6 +186,7 @@ groups: + Whether to skip code formatting of the generated files. @@ -154,6 +194,7 @@ groups: + Whether to include the API name in the generated package name. @@ -166,32 +207,4 @@ groups: 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 - Configuration for the generated client class and file structure. - - ```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. - - - - 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. \ No newline at end of file diff --git a/fern/products/sdks/overview/typescript/configuration.mdx b/fern/products/sdks/overview/typescript/configuration.mdx index 6fc21620..0a62de6e 100644 --- a/fern/products/sdks/overview/typescript/configuration.mdx +++ b/fern/products/sdks/overview/typescript/configuration.mdx @@ -2,7 +2,6 @@ title: TypeScript Configuration description: Configuration options for the Fern TypeScript SDK. --- - You can customize the behavior of the TypeScript SDK generator in `generators.yml`: ```yml {7-8} @@ -23,6 +22,7 @@ Allow fields that are not defined in object schemas. This only applies to serde. +Bundle the SDK into a single file. This is useful when you want to distribute the SDK as a single file. @@ -96,7 +96,6 @@ config: extraDependencies: lodash: "3.0.2" ``` - @@ -112,6 +111,18 @@ config: Only applies when publishing to Github. + +Add custom headers to be included with every request: + +```yaml +# generators.yml +config: + extraHeaders: + x-custom-header: "custom-value" + x-api-version: "2023-01-01" +``` + + Specify extra peer dependencies in the generated `package.json`: @@ -130,9 +141,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 +178,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 +192,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 from the API. +Include utility functions on union members for type checking and value extraction. @@ -238,7 +252,6 @@ public async post( ... } ``` - @@ -254,28 +267,26 @@ 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"; +``` @@ -286,7 +297,7 @@ By default, names are based on the organization and API names in the Fern Defini if (response.ok) { console.log(response.body) } else { - console.error(respons.error) + console.error(response.error) } ``` @@ -323,18 +334,13 @@ 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: - - 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`. +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). +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`. @@ -366,8 +372,7 @@ 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. @@ -387,10 +392,10 @@ generate a `jsr.json` as well as a GitHub workflow to publish to JSR. User: type: object properties: - user_id: - type: string - display_name: - type: string + user_id: + type: string + display_name: + type: string ``` Generated TypeScript with `retainOriginalCasing: true`: @@ -408,7 +413,29 @@ generate a `jsr.json` as well as a GitHub workflow to publish to JSR. displayName: string; } ``` + + + + Configure SDK variable headers to be used across endpoints. Headers provided in individual endpoint calls will override these values. + ```yaml + # generators.yml + config: + sdkVariableHeaders: + projectId: "project_id" + environment: "x-pd-environment" + ``` + + This allows configuring headers once at the client level: + + ```typescript + const client = new Client({ + projectId: "proj_123", + environment: "production" + }); + ``` + + Any requests made through this client will automatically include the configured headers. @@ -416,21 +443,18 @@ generate a `jsr.json` as well as a GitHub workflow to publish to JSR. - 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`). - 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`. +* `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`. @@ -448,7 +472,6 @@ However, when disabling the serialization layer (`no-serde: true`), they will be 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: @@ -458,7 +481,6 @@ types: ``` *TypeScript output*: - ```typescript // useBigInt: true // noSerde: false @@ -491,54 +513,102 @@ interface ObjectWithLongAndBigInt { +When `useBrandedStringAliases` is disabled (the default), string aliases are generated as normal TypeScript aliases: - 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 +```typescript +// generated code +export type MyString = string; +export type OtherString = string; +``` - export type MyString = string & { __MyString: void }; - export const MyString = (value: string): MyString => value as MyString; +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. - export type OtherString = string & { __OtherString: void }; - export const OtherString = (value: string): OtherString => value as OtherString; - ``` - - ```typescript - // consuming the generated type +```yaml +# fern definition +types: + MyString: string + OtherString: string +``` - function printMyString(s: MyString): void { - console.log("MyString: " + s); - } +```typescript +// generated code +export type MyString = string & { __MyString: void }; +export const MyString = (value: string): MyString => value as MyString; +``` + - // doesn't compile, "foo" is not assignable to MyString - printMyString("foo"); + + Defines custom extension behavior for SDK generation. Extension headers can be used to modify the generated code behavior: - const otherString = OtherString("other-string"); - // doesn't compile, otherString is not assignable to MyString - printMyString(otherString); + ```typescript + // Available extension headers + interface Extensions { + // Specify custom headers to include in all requests + headers?: { + [key: string]: string | undefined; + }; + // Configure authorization token management + auth?: { + // Token provider function + getToken?: () => Promise; + // Custom auth header name (default: Authorization) + headerName?: string; + // Custom auth header prefix (default: Bearer) + prefix?: string; + }; + // Configure request timeouts + timeout?: { + // Timeout in milliseconds + ms?: number; + }; + // Configure base URL overrides + baseUrl?: { + // Override base URL per environment + [environment: string]: string; + }; + // Enable fetch-style request/response interception + interceptors?: { + request?: Array<(input: RequestInfo, init?: RequestInit) => Promise<[RequestInfo, RequestInit?]>>; + response?: Array<(response: Response) => Promise>; + }; + } + ``` - // compiles - const myString = MyString("my-string"); - printMyString(myString); - ``` + Example configuring extensions: + ```typescript + const client = new MyApiClient({ + extensions: { + headers: { + 'x-custom-header': 'value' + }, + auth: { + getToken: async () => 'my-token', + headerName: 'X-Auth', + prefix: 'Token' + }, + timeout: { + ms: 5000 + }, + baseUrl: { + production: 'https://api.example.com', + staging: 'https://staging-api.example.com' + }, + interceptors: { + request: [ + async (input, init) => { + // Modify request + return [input, init]; + } + ], + response: [ + async (response) => { + // Handle response + return response; + } + ] + } + } + }); + ``` \ No newline at end of file