What is openapi-fetch?
The openapi-fetch npm package is a tool designed to simplify the process of making HTTP requests to APIs that are defined using the OpenAPI specification. It provides a type-safe way to interact with APIs, ensuring that the requests and responses conform to the defined API schema.
What are openapi-fetch's main functionalities?
Type-safe API requests
This feature allows you to make type-safe API requests based on the OpenAPI definition. The `createClient` function initializes the client with the API definition, and you can then use methods like `get` to make requests. The types are inferred from the OpenAPI schema, ensuring that your requests and responses are type-checked.
const { createClient } = require('openapi-fetch');
const api = createClient({ definition: 'https://api.example.com/openapi.json' });
async function fetchUser() {
const response = await api.get('/users/{id}', { params: { id: 1 } });
console.log(response.data);
}
fetchUser();
Automatic request validation
This feature ensures that the requests you make are validated against the OpenAPI schema. If the request does not conform to the schema, an error will be thrown. This helps in catching errors early in the development process.
const { createClient } = require('openapi-fetch');
const api = createClient({ definition: 'https://api.example.com/openapi.json' });
async function createUser() {
const response = await api.post('/users', { body: { name: 'John Doe', email: 'john.doe@example.com' } });
console.log(response.data);
}
createUser();
Response validation
This feature validates the responses from the API against the OpenAPI schema. It ensures that the data you receive is in the expected format, reducing the chances of runtime errors due to unexpected data structures.
const { createClient } = require('openapi-fetch');
const api = createClient({ definition: 'https://api.example.com/openapi.json' });
async function fetchUser() {
const response = await api.get('/users/{id}', { params: { id: 1 } });
if (response.status === 200) {
console.log('User data:', response.data);
} else {
console.error('Failed to fetch user:', response.error);
}
}
fetchUser();
Other packages similar to openapi-fetch
axios
Axios is a popular HTTP client for making requests to APIs. While it does not provide built-in support for OpenAPI specifications, it is highly configurable and can be used with additional libraries to achieve similar functionality. Compared to openapi-fetch, axios requires more manual setup for type safety and validation.
swagger-client
Swagger Client is a JavaScript client for connecting to APIs that use the OpenAPI (Swagger) specification. It provides similar functionality to openapi-fetch, including type-safe requests and response validation. However, Swagger Client is more tightly integrated with the Swagger ecosystem and may offer more features for users already using Swagger tools.
openapi-client-axios
openapi-client-axios is a library that combines the features of OpenAPI and axios. It generates an axios client based on an OpenAPI definition, providing type-safe requests and response validation. It is similar to openapi-fetch in terms of functionality but leverages axios for the underlying HTTP requests.
openapi-fetch is a type-safe fetch client that pulls in your OpenAPI schema. Weighs 4 kB and has virtually zero runtime. Works with React, Vue, Svelte, or vanilla JS.
Library | Size (min) | “GET” request* |
---|
openapi-fetch | 5 kB | 300k ops/s (fastest) |
openapi-typescript-fetch | 4 kB | 150k ops/s (2× slower) |
axios | 32 kB | 225k ops/s (1.3× slower) |
superagent | 55 kB | 50k ops/s (6× slower) |
openapi-typescript-codegen | 367 kB | 100k ops/s (3× slower) |
* Benchmarks are approximate to just show rough baseline and will differ among machines and browsers. The relative performance between libraries is more reliable.
The syntax is inspired by popular libraries like react-query or Apollo client, but without all the bells and whistles and in a 2 kB package.
import createClient from "openapi-fetch";
import type { paths } from "./my-openapi-3-schema";
const client = createClient<paths>({ baseUrl: "https://myapi.dev/v1/" });
const {
data,
error,
} = await client.GET("/blogposts/{post_id}", {
params: {
path: { post_id: "123" },
},
});
await client.PUT("/blogposts", {
body: {
title: "My New Post",
},
});
data
and error
are typechecked and expose their shapes to Intellisense in VS Code (and any other IDE with TypeScript support). Likewise, the request body
will also typecheck its fields, erring if any required params are missing, or if there’s a type mismatch.
GET
, PUT
, POST
, etc. are only thin wrappers around the native fetch API (which you can swap for any call).
Notice there are no generics, and no manual typing. Your endpoint’s request and response were inferred automatically. This is a huge improvement in the type safety of your endpoints because every manual assertion could lead to a bug! This eliminates all of the following:
- ✅ No typos in URLs or params
- ✅ All parameters, request bodies, and responses are type-checked and 100% match your schema
- ✅ No manual typing of your API
- ✅ Eliminates
any
types that hide bugs - ✅ Also eliminates
as
type overrides that can also hide bugs - ✅ All of this in a 5 kb client package 🎉
🔧 Setup
Install this library along with openapi-typescript:
npm i openapi-fetch
npm i -D openapi-typescript typescript
Highly recommended: enable noUncheckedIndexedAccess in your tsconfig.json
(docs)
Next, generate TypeScript types from your OpenAPI schema using openapi-typescript:
npx openapi-typescript ./path/to/api/v1.yaml -o ./src/lib/api/v1.d.ts
⚠️ Be sure to validate your schemas! openapi-typescript will err on invalid schemas.
Lastly, be sure to run typechecking in your project. This can be done by adding tsc --noEmit
to your npm scripts like so:
{
"scripts": {
"test:ts": "tsc --noEmit"
}
}
And run npm run test:ts
in your CI to catch type errors.
Tip: use tsc --noEmit
to check for type errors rather than relying on your linter or your build command. Nothing will typecheck as accurately as the TypeScript compiler itself.
Usage
The best part about using openapi-fetch over oldschool codegen is no documentation needed. openapi-fetch encourages using your existing OpenAPI documentation rather than trying to find what function to import, or what parameters that function wants:
import createClient from "openapi-fetch";
import type { paths } from "./my-openapi-3-schema";
const client = createClient<paths>({ baseUrl: "https://myapi.dev/v1/" });
const { data, error } = await client.GET("/blogposts/{post_id}", {
params: {
path: { post_id: "my-post" },
query: { version: 2 },
},
});
const { data, error } = await client.PUT("/blogposts", {
body: {
title: "New Post",
body: "<p>New post body</p>",
publish_date: new Date("2023-03-01T12:00:00Z").getTime(),
},
});
- The HTTP method is pulled directly from
createClient()
- You pass in your desired
path
to GET()
, PUT()
, etc. - TypeScript takes over the rest and returns helpful errors for anything missing or invalid
📓 Docs
View Docs