feat(typescript): add passthrough fetch method to generated SDK clients#12920
feat(typescript): add passthrough fetch method to generated SDK clients#12920Swimburger merged 11 commits intomainfrom
Conversation
Co-Authored-By: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
🌱 Seed Test SelectorSelect languages to run seed tests for:
How to use: Click the ⋯ menu above → "Edit" → check the boxes you want → click "Update comment". Tests will run automatically and snapshots will be committed to this PR. |
…etch Co-Authored-By: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com>
Co-Authored-By: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com>
Co-Authored-By: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com>
Co-Authored-By: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com>
Co-Authored-By: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com>
Co-Authored-By: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com>
Co-Authored-By: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com>
Co-Authored-By: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com>
| url: string, | ||
| init?: RequestInit, |
There was a problem hiding this comment.
I think native fetch also allows you not to provide the URL in the first arg, instead pass in a request object that itself contains the URL, is that right?
There was a problem hiding this comment.
Yes, native fetch accepts RequestInfo | URL as the first arg, where RequestInfo = Request | string. So you can do fetch(new Request("/path", { method: "POST", body: "..." })).
Currently our implementation only accepts string. Supporting Request objects would add complexity since we'd need to extract and merge the URL, headers, method, body, etc. from the Request object with our SDK-level overrides.
Want me to add Request object support to match the full native fetch signature, or is string-only sufficient for the initial release?
There was a problem hiding this comment.
Done! The fetch method now accepts Request | string | URL as the first argument, matching the native fetch signature. When a Request object is passed without an explicit init, its properties (method, headers, body, signal, credentials, etc.) are extracted automatically. If both a Request and init are provided, init takes precedence (same as native fetch behavior).
Updated: runtime implementation, generated client code, unit tests (3 new test cases for Request/URL), and all seed snapshots.
… for passthrough fetch Co-Authored-By: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com>
Co-Authored-By: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com>
Description
Refs #5333
Adds a passthrough
fetchmethod to the root client class of every generated TypeScript SDK. This lets users make arbitrary HTTP requests through the SDK client—leveraging configured auth, base URL, retry, timeout, logging, and headers—for endpoints not yet exposed in the SDK definition (e.g., new public endpoints, closed beta endpoints).The method signature matches the native
fetchAPI, acceptingRequest | string | URLas the first argument.Link to Devin run: https://app.devin.ai/sessions/766ccf76c0b44f168c976ca82bc06efe
Requested by: @Swimburger
Usage
Changes Made
generators/typescript/utils/core-utilities/src/core/fetcher/makePassthroughRequest.ts): Core implementation that acceptsRequest | string | URL, resolves base URLs, merges headers (SDK defaults → auth → init → requestOptions), delegates to existingmakeRequest/requestWithRetries/getFetchFninfrastructure, and returns a standardResponse. When aRequestobject is passed without explicitinit, its properties (method, headers, body, signal, credentials, etc.) are extracted automatically; if both are provided,inittakes precedence (matching nativefetchbehavior).GeneratedSdkClientClassImpl.ts): AddsaddPassthroughFetchMethodthat generates apublic async fetch(input: Request | string | URL, init?, requestOptions?)method on root client classes only. Conditionally wires auth headers when the client has an auth provider. Detects multi-URL environments and omits theenvironmentproperty to avoid passing an object where a string is expected.ReadmeSnippetBuilder.ts,features.yml): AddedCUSTOM_FETCHfeature with documentation snippet showing passthrough fetch usage. All generated READMEs now include a "Custom Fetch" section under Advanced.core-utilities/tests/unit/fetcher/makePassthroughRequest.test.ts): 23 test cases covering URL resolution (8 cases including URL object), header merge priority, auth header injection, method/body forwarding, timeout/retry override precedence, abort signal precedence, credentials passthrough, response handling, Request object input handling (3 cases), and SDK default header supplier resolution.makePassthroughRequest.tsfile, test file, and README documentation.Updates since last revision
Request | string | URLinput support: The first argument now matches the nativefetchsignature. When aRequestobject is passed withoutinit, its properties are extracted. If both are provided,inittakes precedence.URLobjects are converted to strings. (3 new unit tests added for this behavior.)CUSTOM_FETCHfeature tofeatures.ymland built snippet inReadmeSnippetBuilder.ts. All generated READMEs now include a "Custom Fetch" section with usage example.ReadmeSnippetBuilder.test.ts.snapto include the newCUSTOM_FETCHfeature in the comprehensive feature set snapshot.Human review checklist
Requestobject is passed,input.body(aReadableStream | null) is extracted and passed tomakeRequest. If the Request body has already been consumed, this will fail. Nativefetchhas the same limitation. Consider whether we should document this or add a check.cache: input.cache as RequestCachecast: The cast on line 78 ofmakePassthroughRequest.tsis suspicious—Request.cacheshould already beRequestCachetype. Verify this is necessary or remove it.Requestobject andinitare provided, only the URL from the Request is used; all other properties come frominit. This matches nativefetchbehavior but may be surprising. The unit tests verify this.environmentoption is omitted for multi-URL SDKs. Passthroughfetchwith relative paths will only work ifbaseUrlis configured. Is this the right UX, or should a warning/error be surfaced?init.headers→requestOptions.headers. All keys are lowercased. Verify this priority is correct (unit tests validate this)..headersfromauthProvider.getAuthRequest()is used.getAuthRequest()is called withoutendpointMetadatasince passthrough requests have no endpoint metadata. Verify this is acceptable for all auth schemes (bearer, basic, header, OAuth, inferred).requestOptions.abortSignalwins overinit.signal; they are not combined. If a user passes both, the init signal is silently ignored.EndpointSupplier.get(value, { endpointMetadata: {} })passes an empty metadata object when resolving default headers—confirm this is safe for all supplier types.Testing
pnpm seed test --generator ts-sdk)multi-url-environment,multi-url-environment-no-default,server-url-templating) re-verified after fixmakePassthroughRequestruntime utility (including 3 for Request/URL object support)ReadmeSnippetBuilder.test.ts.snapupdated to include CUSTOM_FETCH feature