AI prompts
base on š± A better fetch API. Works everywhere. # ofetch
<!-- automd:badges -->
[](https://npmjs.com/package/ofetch)
[](https://npm.chart.dev/ofetch)
<!-- /automd -->
A better fetch API. Works on node, browser, and workers.
> [!IMPORTANT]
> You are on v2 (alpha) development branch. See [v1](https://github.com/unjs/ofetch/tree/v1) for v1 docs.
<details>
<summary>Spoiler</summary>
<img src="https://media.giphy.com/media/Dn1QRA9hqMcoMz9zVZ/giphy.gif">
</details>
## š Quick Start
Install:
```bash
npx nypm i ofetch
```
Import:
```js
import { ofetch } from "ofetch";
```
## āļø Parsing Response
`ofetch` smartly parse JSON responses.
```js
const { users } = await ofetch("/api/users");
```
For binary content types, `ofetch` will instead return a `Blob` object.
You can optionally provide a different parser than `JSON.parse`, or specify `blob`, `arrayBuffer`, `text` or `stream` to force parsing the body with the respective `FetchResponse` method.
```js
// Return text as is
await ofetch("/movie?lang=en", { parseResponse: (txt) => txt });
// Get the blob version of the response
await ofetch("/api/generate-image", { responseType: "blob" });
// Get the stream version of the response
await ofetch("/api/generate-image", { responseType: "stream" });
```
## āļø JSON Body
If an object or a class with a `.toJSON()` method is passed to the `body` option, `ofetch` automatically stringifies it.
`ofetch` utilizes `JSON.stringify()` to convert the passed object. Classes without a `.toJSON()` method have to be converted into a string value in advance before being passed to the `body` option.
For `PUT`, `PATCH`, and `POST` request methods, when a string or object body is set, `ofetch` adds the default `"content-type": "application/json"` and `accept: "application/json"` headers (which you can always override).
Additionally, `ofetch` supports binary responses with `Buffer`, `ReadableStream`, `Stream`, and [compatible body types](https://developer.mozilla.org/en-US/docs/Web/API/fetch#body). `ofetch` will automatically set the `duplex: "half"` option for streaming support!
**Example:**
```js
const { users } = await ofetch("/api/users", {
method: "POST",
body: { some: "json" },
});
```
## āļø Handling Errors
`ofetch` Automatically throws errors when `response.ok` is `false` with a friendly error message and compact stack (hiding internals).
A parsed error body is available with `error.data`. You may also use `FetchError` type.
```ts
await ofetch("https://google.com/404");
// FetchError: [GET] "https://google/404": 404 Not Found
// at async main (/project/playground.ts:4:3)
```
To catch error response:
```ts
await ofetch("/url").catch((error) => error.data);
```
To bypass status error catching you can set `ignoreResponseError` option:
```ts
await ofetch("/url", { ignoreResponseError: true });
```
## āļø Auto Retry
`ofetch` Automatically retries the request if an error happens and if the response status code is included in `retryStatusCodes` list:
**Retry status codes:**
- `408` - Request Timeout
- `409` - Conflict
- `425` - Too Early ([Experimental](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Early-Data))
- `429` - Too Many Requests
- `500` - Internal Server Error
- `502` - Bad Gateway
- `503` - Service Unavailable
- `504` - Gateway Timeout
You can specify the amount of retry and delay between them using `retry` and `retryDelay` options and also pass a custom array of codes using `retryStatusCodes` option.
The default for `retry` is `1` retry, except for `POST`, `PUT`, `PATCH`, and `DELETE` methods where `ofetch` does not retry by default to avoid introducing side effects. If you set a custom value for `retry` it will **always retry** for all requests.
The default for `retryDelay` is `0` ms.
```ts
await ofetch("http://google.com/404", {
retry: 3,
retryDelay: 500, // ms
retryStatusCodes: [404, 500], // response status codes to retry
});
```
## āļø Timeout
You can specify `timeout` in milliseconds to automatically abort a request after a timeout (default is disabled).
```ts
await ofetch("http://google.com/404", {
timeout: 3000, // Timeout after 3 seconds
});
```
## āļø Type Friendly
The response can be type assisted:
```ts
const article = await ofetch<Article>(`/api/article/${id}`);
// Auto complete working with article.id
```
## āļø Adding `baseURL`
By using `baseURL` option, `ofetch` prepends it for trailing/leading slashes and query search params for baseURL using [ufo](https://github.com/unjs/ufo):
```js
await ofetch("/config", { baseURL });
```
## āļø Adding Query Search Params
By using `query` option (or `params` as alias), `ofetch` adds query search params to the URL by preserving the query in the request itself using [ufo](https://github.com/unjs/ufo):
```js
await ofetch("/movie?lang=en", { query: { id: 123 } });
```
## āļø Interceptors
Providing async interceptors to hook into lifecycle events of `ofetch` call is possible.
You might want to use `ofetch.create` to set shared interceptors.
### `onRequest({ request, options })`
`onRequest` is called as soon as `ofetch` is called, allowing you to modify options or do simple logging.
```js
await ofetch("/api", {
async onRequest({ request, options }) {
// Log request
console.log("[fetch request]", request, options);
// Add `?t=1640125211170` to query search params
options.query = options.query || {};
options.query.t = new Date();
},
});
```
### `onRequestError({ request, options, error })`
`onRequestError` will be called when the fetch request fails.
```js
await ofetch("/api", {
async onRequestError({ request, options, error }) {
// Log error
console.log("[fetch request error]", request, error);
},
});
```
### `onResponse({ request, options, response })`
`onResponse` will be called after `fetch` call and parsing body.
```js
await ofetch("/api", {
async onResponse({ request, response, options }) {
// Log response
console.log("[fetch response]", request, response.status, response.body);
},
});
```
### `onResponseError({ request, options, response })`
`onResponseError` is the same as `onResponse` but will be called when fetch happens but `response.ok` is not `true`.
```js
await ofetch("/api", {
async onResponseError({ request, response, options }) {
// Log error
console.log(
"[fetch response error]",
request,
response.status,
response.body
);
},
});
```
### Passing array of interceptors
If necessary, it's also possible to pass an array of function that will be called sequentially.
```js
await ofetch("/api", {
onRequest: [
() => {
/* Do something */
},
() => {
/* Do something else */
},
],
});
```
## āļø Create fetch with default options
This utility is useful if you need to use common options across several fetch calls.
**Note:** Defaults will be cloned at one level and inherited. Be careful about nested options like `headers`.
```js
const apiFetch = ofetch.create({ baseURL: "/api" });
apiFetch("/test"); // Same as ofetch('/test', { baseURL: '/api' })
```
## š” Adding headers
By using `headers` option, `ofetch` adds extra headers in addition to the request default headers:
```js
await ofetch("/movies", {
headers: {
Accept: "application/json",
"Cache-Control": "no-cache",
},
});
```
## š£ Access to Raw Response
If you need to access raw response (for headers, etc), you can use `ofetch.raw`:
```js
const response = await ofetch.raw("/sushi");
// response._data
// response.headers
// ...
```
## šæ Using Native Fetch
As a shortcut, you can use `ofetch.native` that provides native `fetch` API
```js
const json = await ofetch.native("/sushi").then((r) => r.json());
```
## š” SSE
**Example:** Handle SSE response:
```js
const stream = await ofetch("/sse");
const reader = stream.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
// Here is the chunked text of the SSE response.
const text = decoder.decode(value);
}
```
## šµļø Adding HTTP(S) Agent
In Node.js (>= 18) environments, you can provide a custom dispatcher to intercept requests and support features such as Proxy and self-signed certificates. This feature is enabled by [undici](https://undici.nodejs.org/) built-in Node.js. [read more](https://undici.nodejs.org/#/docs/api/Dispatcher) about the Dispatcher API.
Some available agents:
- `ProxyAgent`: A Proxy Agent class that implements the Agent API. It allows the connection through a proxy in a simple way. ([docs](https://undici.nodejs.org/#/docs/api/ProxyAgent))
- `MockAgent`: A mocked Agent class that implements the Agent API. It allows one to intercept HTTP requests made through undici and return mocked responses instead. ([docs](https://undici.nodejs.org/#/docs/api/MockAgent))
- `Agent`: Agent allows dispatching requests against multiple different origins. ([docs](https://undici.nodejs.org/#/docs/api/Agent))
**Example:** Set a proxy agent for one request:
```ts
import { ProxyAgent } from "undici";
import { ofetch } from "ofetch";
const proxyAgent = new ProxyAgent("http://localhost:3128");
const data = await ofetch("https://icanhazip.com", { dispatcher: proxyAgent });
```
**Example:** Create a custom fetch instance that has proxy enabled:
```ts
import { ProxyAgent, setGlobalDispatcher } from "undici";
import { ofetch } from "ofetch";
const proxyAgent = new ProxyAgent("http://localhost:3128");
const fetchWithProxy = ofetch.create({ dispatcher: proxyAgent });
const data = await fetchWithProxy("https://icanhazip.com");
```
**Example:** Set a proxy agent for all requests:
```ts
import { ProxyAgent, setGlobalDispatcher } from "undici";
import { ofetch } from "ofetch";
const proxyAgent = new ProxyAgent("http://localhost:3128");
setGlobalDispatcher(proxyAgent);
const data = await ofetch("https://icanhazip.com");
```
**Example:** Allow self-signed certificates (USE AT YOUR OWN RISK!)
```ts
import { Agent } from "undici";
import { ofetch } from "ofetch";
// Note: This makes fetch unsecure against MITM attacks. USE AT YOUR OWN RISK!
const unsecureAgent = new Agent({ connect: { rejectUnauthorized: false } });
const unsecureFetch = ofetch.create({ dispatcher: unsecureAgent });
const data = await unsecureFetch("https://www.squid-cache.org/");
```
### šŖ Augment `FetchOptions` interface
You can augment the `FetchOptions` interface to add custom properties.
```ts
// Place this in any `.ts` or `.d.ts` file.
// Ensure it's included in the project's tsconfig.json "files".
declare module "ofetch" {
interface FetchOptions {
// Custom properties
requiresAuth?: boolean;
}
}
export {};
```
This lets you pass and use those properties with full type safety throughout `ofetch` calls.
```ts
const myFetch = ofetch.create({
onRequest(context) {
// ^? { ..., options: {..., requiresAuth?: boolean }}
console.log(context.options.requiresAuth);
},
});
myFetch("/foo", { requiresAuth: true });
```
## License
š Published under the [MIT](https://github.com/h3js/rou3/blob/main/LICENSE) license.
", Assign "at most 3 tags" to the expected json: {"id":"7891","tags":[]} "only from the tags list I provide: [{"id":77,"name":"3d"},{"id":89,"name":"agent"},{"id":17,"name":"ai"},{"id":54,"name":"algorithm"},{"id":24,"name":"api"},{"id":44,"name":"authentication"},{"id":3,"name":"aws"},{"id":27,"name":"backend"},{"id":60,"name":"benchmark"},{"id":72,"name":"best-practices"},{"id":39,"name":"bitcoin"},{"id":37,"name":"blockchain"},{"id":1,"name":"blog"},{"id":45,"name":"bundler"},{"id":58,"name":"cache"},{"id":21,"name":"chat"},{"id":49,"name":"cicd"},{"id":4,"name":"cli"},{"id":64,"name":"cloud-native"},{"id":48,"name":"cms"},{"id":61,"name":"compiler"},{"id":68,"name":"containerization"},{"id":92,"name":"crm"},{"id":34,"name":"data"},{"id":47,"name":"database"},{"id":8,"name":"declarative-gui "},{"id":9,"name":"deploy-tool"},{"id":53,"name":"desktop-app"},{"id":6,"name":"dev-exp-lib"},{"id":59,"name":"dev-tool"},{"id":13,"name":"ecommerce"},{"id":26,"name":"editor"},{"id":66,"name":"emulator"},{"id":62,"name":"filesystem"},{"id":80,"name":"finance"},{"id":15,"name":"firmware"},{"id":73,"name":"for-fun"},{"id":2,"name":"framework"},{"id":11,"name":"frontend"},{"id":22,"name":"game"},{"id":81,"name":"game-engine "},{"id":23,"name":"graphql"},{"id":84,"name":"gui"},{"id":91,"name":"http"},{"id":5,"name":"http-client"},{"id":51,"name":"iac"},{"id":30,"name":"ide"},{"id":78,"name":"iot"},{"id":40,"name":"json"},{"id":83,"name":"julian"},{"id":38,"name":"k8s"},{"id":31,"name":"language"},{"id":10,"name":"learning-resource"},{"id":33,"name":"lib"},{"id":41,"name":"linter"},{"id":28,"name":"lms"},{"id":16,"name":"logging"},{"id":76,"name":"low-code"},{"id":90,"name":"message-queue"},{"id":42,"name":"mobile-app"},{"id":18,"name":"monitoring"},{"id":36,"name":"networking"},{"id":7,"name":"node-version"},{"id":55,"name":"nosql"},{"id":57,"name":"observability"},{"id":46,"name":"orm"},{"id":52,"name":"os"},{"id":14,"name":"parser"},{"id":74,"name":"react"},{"id":82,"name":"real-time"},{"id":56,"name":"robot"},{"id":65,"name":"runtime"},{"id":32,"name":"sdk"},{"id":71,"name":"search"},{"id":63,"name":"secrets"},{"id":25,"name":"security"},{"id":85,"name":"server"},{"id":86,"name":"serverless"},{"id":70,"name":"storage"},{"id":75,"name":"system-design"},{"id":79,"name":"terminal"},{"id":29,"name":"testing"},{"id":12,"name":"ui"},{"id":50,"name":"ux"},{"id":88,"name":"video"},{"id":20,"name":"web-app"},{"id":35,"name":"web-server"},{"id":43,"name":"webassembly"},{"id":69,"name":"workflow"},{"id":87,"name":"yaml"}]" returns me the "expected json"