Typed Fetch Client for OpenAPI Schemas
openapi-typescript-fetch provides a robust and type-safe `fetch` client tailored for use with TypeScript definitions generated by `openapi-typescript`. It simplifies API interactions by offering strong typing for request parameters, response bodies, and error structures, directly derived from OpenAPI 3.x and Swagger 2.0 schemas. The current stable version is 2.2.1, with releases occurring incrementally as bug fixes and minor features are introduced. The project differentiates itself by deeply integrating with `openapi-typescript`'s generated types, allowing developers to configure a global fetcher instance, define per-path operations, and handle complex API error responses using discriminated unions, enhancing developer experience and reducing runtime errors. It supports middleware for request/response interception and offers utility types for introspection of operation arguments and return values. This library focuses on providing a secure and reliable way to interact with RESTful APIs in TypeScript environments, primarily for Node.js (>=12) and modern browsers.
Common errors
-
Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'openapi-typescript-fetch' imported from ...
cause This usually indicates an attempt to import an ESM-only package using CommonJS `require()` or in an environment not configured for ESM, particularly after the v2.0.0 release.fixEnsure your project is configured for ES Modules. Use `type: "module"` in `package.json`, ensure your `tsconfig.json` has `"module": "esnext"` or similar, and use `import` statements. If running Node.js, ensure `node --loader ts-node/esm` or similar for TypeScript projects. -
Property 'someProperty' does not exist on type 'never'.
cause This error often appears when the `paths` type from `openapi-typescript` is incorrectly imported or not up-to-date, causing the `Fetcher.for<paths>()` to infer `never` or an empty type.fixVerify that `openapi-typescript` has successfully generated your `petstore.ts` (or similar) file. Check the import path `import type { paths } from './petstore';` to ensure it correctly points to the generated types file. Regenerate the types if the OpenAPI schema has changed. -
Argument of type '{ status: string[]; invalidProp: string; }' is not assignable to parameter of type 'OpArgType<...>'cause You are passing an argument to an operation that does not match the expected type defined by your OpenAPI schema and `openapi-typescript` generated types.fixReview your OpenAPI schema for the specific endpoint and method. Cross-reference with the `OpArgType` for that operation to ensure all required parameters are present and correctly typed. This is the core benefit of the library: type safety.
Warnings
- breaking Version 2.0.0 introduced significant changes targeting ES Modules (ESM) environments. It dropped explicit TypeScript transpilation for `async/await` and was bundled with `esbuild` for ESM compatibility. Projects should ensure their build setup (e.g., Vite) is configured for ESM.
- gotcha Properly generating `petstore.ts` (or equivalent) using `openapi-typescript` is crucial. The types generated are the foundation for the type safety provided by `openapi-typescript-fetch`. Outdated or incorrectly generated types will lead to `any` types or incorrect type inference.
- gotcha Error handling relies on `e instanceof operation.Error` and `e.getActualType()` to leverage OpenAPI's defined error responses as discriminated unions. Generic `catch (e: any)` blocks will lose this type safety.
- gotcha The `baseUrl` and `init` configurations set globally on the `fetcher` instance are merged with any `init` object provided directly to an operation. Be mindful of potential overwrites if not intended.
Install
-
npm install openapi-typescript-fetch -
yarn add openapi-typescript-fetch -
pnpm add openapi-typescript-fetch
Imports
- Fetcher
const { Fetcher } = require('openapi-typescript-fetch')import { Fetcher } from 'openapi-typescript-fetch' - Middleware
import { Middleware } from 'openapi-typescript-fetch' - OpArgType
import { OpArgType } from 'openapi-typescript-fetch'
Quickstart
import { Fetcher } from 'openapi-typescript-fetch';
import type { paths } from './petstore'; // Assume this is generated by 'npx openapi-typescript'
// Configure the fetcher with a base URL and optional global settings
const fetcher = Fetcher.for<paths>();
fetcher.configure({
baseUrl: 'https://petstore.swagger.io/v2',
init: {
headers: {
'Accept': 'application/json'
}
},
use: [async (url, init, next) => {
console.log(`[REQUEST] ${init.method || 'GET'} ${url}`);
const response = await next(url, init);
console.log(`[RESPONSE] ${url} - Status: ${response.status}`);
return response;
}]
});
// Define specific API operations
const findPetsByStatus = fetcher.path('/pet/findByStatus').method('get').create();
const addPet = fetcher.path('/pet').method('post').create();
async function runExample() {
try {
// Execute the findPetsByStatus operation with typed parameters
const { status, data: pets } = await findPetsByStatus({
status: ['available', 'pending'],
// No body for GET request, but type-safe parameters are enforced
});
console.log(`Found ${pets.length} pets. First pet ID: ${pets[0]?.id}`);
// Example of a POST request
const newPet = {
id: 987654321,
name: 'Max',
status: 'available',
category: { id: 1, name: 'Dog' },
photoUrls: ['http://example.com/max.jpg']
};
const addPetResult = await addPet(newPet);
console.log(`Added pet with ID: ${addPetResult.data.id}`);
} catch (e) {
// Handle typed errors
if (e instanceof addPet.Error) {
const error = e.getActualType();
console.error(`API Error for addPet (Status: ${error.status}):`, error.data);
} else {
console.error('An unexpected error occurred:', e);
}
}
}
runExample();