Security News
Supply Chain Attack Detected in @solana/web3.js Library
A supply chain attack has been detected in versions 1.95.6 and 1.95.7 of the popular @solana/web3.js library.
openapi-fetch
Advanced tools
Ultra-fast fetching for TypeScript generated automatically from your OpenAPI schema. Weighs in at 1 kb and has virtually zero runtime. Works with React, Vue, Svelte, or vanilla JS.
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.
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();
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 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 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 an ultra-fast fetch client for TypeScript using your OpenAPI schema. Weighs in at 1 kb and has virtually zero runtime. Works with React, Vue, Svelte, or vanilla JS.
Library | Size (min) |
---|---|
openapi-fetch | 1 kB |
openapi-typescript-fetch | 4 kB |
openapi-typescript-codegen | 345 kB |
The syntax is inspired by popular libraries like react-query or Apollo client, but without all the bells and whistles and in a 1 kb package.
import createClient from "openapi-fetch";
import { paths } from "./v1"; // (generated from openapi-typescript)
const { get, post } = createClient<paths>({ baseUrl: "https://myapi.dev/v1/" });
// Type-checked request
await post("/create-post", {
body: {
title: "My New Post",
// ❌ Property 'publish_date' is missing in type …
},
});
// Type-checked response
const { data, error } = await get("/post/my-blog-post");
console.log(data.title); // ❌ 'data' is possibly 'undefined'
console.log(error.message); // ❌ 'error' is possibly 'undefined'
console.log(data?.foo); // ❌ Property 'foo' does not exist on type …
Notice there are no generics, and no manual typing. Your endpoint’s exact request & response was inferred automatically off the URL. This makes a big difference in the type safety of your endpoints! This eliminates all of the following:
any
types that hide bugsas
type overrides that can also hide bugsInstall this library along with openapi-typescript:
npm i openapi-fetch
npm i -D openapi-typescript
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
Always use
tsc --noEmit
to check for type errors! Your build tools (Vite, esbuild, webpack, etc.) won’t typecheck as accurately as the TypeScript compiler itself.
Using openapi-fetch is as easy as reading your schema! For example, given the following schema:
Here’s how you’d fetch /post/{post_id}
and /create-post
:
import createClient from "openapi-fetch";
import { paths } from "./v1";
const { get, post } = createClient<paths>({ baseUrl: "https://myapi.dev/v1/" });
// GET /post/{post_id}
const { data, error } = await get("/post/{post_id}", {
params: {
path: { post_id: "my-post" },
query: { version: 2 },
},
});
// POST /create-post
const { data, error } = await post("/create-post", {
body: {
title: "New Post",
body: "<p>New post body</p>",
publish_date: new Date("2023-03-01T12:00:00Z").getTime(),
},
});
The pathname of get()
, put()
, post()
, etc. must match your schema literally. Note in the example, the URL is /post/{post_id}
. This library will replace all path
params for you (so they can be typechecked)
✨ Tip
openapi-fetch infers types from the URL. Prefer static string values over dynamic runtime values, e.g.:
- ✅
"/post/{post_id}"
- ❌
[...pathParts].join("/") + "{post_id}"
The get()
request shown needed the params
object that groups parameters by type (path
or query
). If a required param is missing, or the wrong type, a type error will be thrown.
The post()
request required a body
object that provided all necessary requestBody data.
All methods return an object with data, error, and response.
2xx
response if the server returned 2xx
; otherwise it will be undefined
4xx
/5xx
response if the server returned either; otherwise it will be undefined
default
will also be interpreted as error
, since its intent is handling unexpected HTTP codesstatus
, headers
, etc. It is not typechecked.createClient accepts the following options, which set the default settings for all subsequent fetch calls.
createClient<paths>(options);
Name | Type | Description |
---|---|---|
baseUrl | string | Prefix all fetch URLs with this option (e.g. "https://myapi.dev/v1/" ). |
fetch | fetch | Fetch function used for requests (defaults to globalThis.fetch ) |
(Fetch options) | Any valid fetch option (headers , mode , cache , signal …) (docs) |
import { paths } from "./v1";
const { get, put, post, del, options, head, patch, trace } = createClient<paths>({ baseUrl: "https://myapi.dev/v1/" });
const { data, error, response } = await get("/my-url", options);
Name | Type | Description |
---|---|---|
params | ParamsObject | Provide path and query params from the OpenAPI schema |
params.path | { [name]: value } | Provide all path params (params that are part of the URL) |
params.query | { [name]: value } | Provide all `query params (params that are part of the searchParams |
body | { [name]:value } | The requestBody data, if needed (PUT/POST/PATCH/DEL only) |
querySerializer | QuerySerializer | (optional) Override default param serialization (see Parameter Serialization) |
(Fetch options) | Any valid fetch option (headers , mode , cache , signal …) (docs) |
In the spirit of being lightweight, this library only uses URLSearchParams to serialize parameters. So for complex query param types (e.g. arrays) you’ll need to provide your own querySerializer()
method that transforms query params into a URL-safe string:
import createClient from "openapi-fetch";
import { paths } from "./v1"; // generated from openapi-typescript
const { get, post } = createClient<paths>({ baseUrl: "https://myapi.dev/v1/" });
const { data, error } = await get("/post/{post_id}", {
params: {
path: { post_id: "my-post" },
query: { version: 2 },
},
querySerializer: (q) => `v=${q.version}`, // ✅ Still typechecked based on the URL!
});
Note that this happens at the request level so that you still get correct type inference for that URL’s specific query params.
Thanks, @ezpuzz!
Authentication often requires some reactivity dependent on a token. Since this library is so low-level, there are myriad ways to handle it:
Here’s how it can be handled using nanostores, a tiny (334 b), universal signals store:
// src/lib/api/index.ts
import { atom, computed } from "nanostores";
import createClient from "openapi-fetch";
import { paths } from "./v1";
export const authToken = atom<string | undefined>();
someAuthMethod().then((newToken) => authToken.set(newToken));
export const client = computed(authToken, (currentToken) =>
createClient<paths>({
headers: currentToken ? { Authorization: `Bearer ${currentToken}` } : {},
baseUrl: "https://myapi.dev/v1/",
})
);
// src/some-other-file.ts
import { client } from "./lib/api";
const { get, post } = client.get();
get("/some-authenticated-url", {
/* … */
});
You can also use proxies which are now supported in all modern browsers:
// src/lib/api/index.ts
import createClient from "openapi-fetch";
import { paths } from "./v1";
let authToken: string | undefined = undefined;
someAuthMethod().then((newToken) => (authToken = newToken));
const baseClient = createClient<paths>({ baseUrl: "https://myapi.dev/v1/" });
export default new Proxy(baseClient, {
get(_, key: keyof typeof baseClient) {
const newClient = createClient<paths>({
headers: authToken ? { Authorization: `Bearer ${authToken}` } : {},
baseUrl: "https://myapi.dev/v1/",
});
return newClient[key];
},
});
// src/some-other-file.ts
import client from "./lib/api";
client.get("/some-authenticated-url", {
/* … */
});
fetch()
API while reducing boilerplate (such as await res.json()
)FAQs
Fast, type-safe fetch client for your OpenAPI schema. Only 6 kb (min). Works with React, Vue, Svelte, or vanilla JS.
The npm package openapi-fetch receives a total of 307,999 weekly downloads. As such, openapi-fetch popularity was classified as popular.
We found that openapi-fetch demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
A supply chain attack has been detected in versions 1.95.6 and 1.95.7 of the popular @solana/web3.js library.
Research
Security News
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
Security News
Research
Socket researchers have discovered malicious npm packages targeting crypto developers, stealing credentials and wallet data using spyware delivered through typosquats of popular cryptographic libraries.