← Back to blog/Guides

How to Generate a TypeScript SDK From an OpenAPI Spec

Generate a typed Fetch client, then test the request, bearer auth, and errors before treating it as a supported SDK.

F
Faizan Khan
2026-11-09 • 6 min read

You can generate the client from an OpenAPI spec. The part you still own is deciding what callers can rely on: method names, authentication, error handling, and compatibility from one release to the next.

This walkthrough generates a TypeScript Fetch client from a small sample OpenAPI spec and runs a smoke test without hitting a live API. The same spec can feed your API reference generator.

1. Give the generator a stable contract

Download the sample as openapi.yaml. It defines GET /webhooks/{id}, a stable getWebhook operation ID, bearer auth, and a typed success response. Before generating from your real spec, check that operations have meaningful IDs and that required fields, auth, and errors match what the API actually returns.

2. Generate the TypeScript client

Install the OpenAPI Generator CLI and use version 7.13.0 to reproduce this example. In a scratch project with Node.js 22 and TypeScript installed:

Bash
1openapi-generator-cli validate -i openapi.yaml
2openapi-generator-cli generate -i openapi.yaml -g typescript-fetch -o generated

The typescript-fetch generator creates typed operations and a Fetch runtime. Keep generated files separate from hand-written code so you can regenerate them cleanly.

3. Smoke-test the generated client

Save this as smoke.ts next to the generated directory. The fake Fetch response keeps the test offline, but the generated client still builds the real URL and authorization header.

TypeScript
1import assert from "node:assert/strict";
2import { Configuration, ResponseError, WebhooksApi } from "./generated";
3
4async function main() {
5 const api = new WebhooksApi(new Configuration({
6 basePath: "https://api.example.com",
7 accessToken: "test-token",
8 fetchApi: async (url, init) => {
9 assert.equal(init?.method, "GET");
10 assert.equal(new Headers(init?.headers).get("authorization"), "Bearer test-token");
11 if (url === "https://api.example.com/webhooks/missing") {
12 return new Response(null, { status: 404 });
13 }
14 assert.equal(url, "https://api.example.com/webhooks/hook_123");
15 return Response.json({ id: "hook_123", status: "active" });
16 },
17 }));
18
19 assert.deepEqual(await api.getWebhook({ id: "hook_123" }), {
20 id: "hook_123",
21 status: "active",
22 });
23 await assert.rejects(
24 () => api.getWebhook({ id: "missing" }),
25 (error) => error instanceof ResponseError && error.response.status === 404,
26 );
27}
28
29main().catch((error) => {
30 console.error(error);
31 process.exitCode = 1;
32});

From the scratch project, install TypeScript and Node types if needed, then compile and run the test:

Bash
1npm install --save-dev typescript@5.9.3 @types/node@22
2npx tsc smoke.ts --module node16 --target es2022 --strict --outDir dist
3node dist/smoke.js

This verifies the client against a fixture, not the live contract. Before releasing, also run a smoke test against staging with a real credential from the environment, including a documented error. Do not ship a server-side API token in a browser bundle.

4. Make regeneration part of release review

Pin the generator and commit its configuration. When the spec changes, regenerate into a clean directory and review the diff before publishing. A renamed operation ID can break callers even when the HTTP route is unchanged. Test the package as a consumer would install it, document breaking changes, and release it with a version and changelog.

Use the API docs sync guide to keep the reference and quickstart aligned with the SDK. For a quick check of what the same contract looks like to a reader, try the OpenAPI to Markdown tool.

Continue This Guide