diff --git a/fern/products/sdks/overview/typescript/configuration.mdx b/fern/products/sdks/overview/typescript/configuration.mdx index 0651a7f29..a1d06b912 100644 --- a/fern/products/sdks/overview/typescript/configuration.mdx +++ b/fern/products/sdks/overview/typescript/configuration.mdx @@ -3,6 +3,544 @@ title: Typescript Configuration description: Configuration options for the Fern Typescript SDK. --- -# Typescript Configuration +You can customize the behavior of the TypeScript SDK generator in `generators.yml`: + +```yml {7-8} +default-group: local +groups: + local: + generators: + - name: fernapi/fern-typescript-node-sdk + version: 0.7.1 + config: + namespaceExport: Acme +``` + +## SDK configuration options + + + 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. + + + + When enabled, [`withCredentials`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials) is set to `true` when making network requests. + + + + + + + Generate WebSocket clients from your AsyncAPI specs. + + + +The default timeout for network requests. In the generated client, this can be overridden at the request level. + + + + 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`). + + + + + Specify extra dependencies in the generated `package.json`. This is useful +when you utilize [`.fernignore`](https://buildwithfern.com/learn/sdks/capabilities/custom-code) to +supplement the generated client with custom code. + +```yaml +# generators.yml +config: + extraDependencies: + lodash: "3.0.2" +``` + + + + + 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" +``` + + + + 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). + + + + 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; + } + ``` + + + +When you specify an object in `packageJson`, it will be merged into the `package.json` file. + +```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 +``` + + + +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. + + + +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`. + + + +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` + + +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. + + + +Specify the path where the source files for the generated SDK should be placed. + + + +Allow fields that are not defined in object schemas. This only applies to serde. + + + +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 = {}; +``` + + + +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" }); +``` + + + + +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: + + ```yaml + # generators.yml + config: + namespaceExport: Acme + ``` + + ```typescript + import { Acme, AcmeClient } from "@acme/node"; + ``` + + + + + +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 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 `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); + ``` + + + + + 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) + } + ``` + + +### Beta options + + + +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. + + + + + + + + + +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. + -Discover how to configure the Fern Typescript SDK for your project. \ No newline at end of file