Baike.dev
All toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
U

up-fetch

> 开发工具
Open source

Advanced fetch client builder

1.4K stars0 likes0 views
WebsiteGitHub

About

Advanced fetch client builder

upfetch - advanced fetch client builder




_upfetch_ is an advanced fetch client builder with standard schema validation, automatic response parsing, smart defaults and more. Designed to make data fetching type-safe and developer-friendly while keeping the familiar fetch API. [中文文档 (AI 翻译)](./README_ZH.md) ## Table of Contents - [Highlights](#️-highlights) - [Agent Skill](#️-agent-skill) - [QuickStart](#️-quickstart) - [Key Features](#️-key-features) - [Request Configuration](#️-request-configuration) - [Simple Query Parameters](#️-simple-query-parameters) - [Automatic Body Handling](#️-automatic-body-handling) - [Schema Validation](#️-schema-validation) - [Lifecycle Hooks](#️-lifecycle-hooks) - [Timeout](#️-timeout) - [Retry](#️-retry) - [Error Handling](#️-error-handling) - [Usage](#️-usage) - [Authentication](#️-authentication) - [Delete a default option](#️-delete-a-default-option) - [FormData](#️-formdata) - [Multiple fetch clients](#️-multiple-fetch-clients) - [Streaming](#️-streaming) - [Progress](#️-progress) - [Advanced Usage](#️-advanced-usage) - [Error as value](#️-error-as-value) - [Custom response parsing](#️-custom-response-parsing) - [Custom response errors](#️-custom-response-errors) - [Custom params serialization](#️-custom-params-serialization) - [Custom body serialization](#️-custom-body-serialization) - [Defaults based on the request](#️-defaults-based-on-the-request) - [API Reference](#️-api-reference) - [Feature Comparison](#️-feature-comparison) - [Environment Support](#️-environment-support) ## ➡️ Highlights - **Lightweight** - 1.6kB gzipped, no dependency - **Typesafe** - Validate API responses with [zod][zod], [valibot][valibot] or [arktype][arktype] - ️ **Practical API** - Use objects for `params` and `body`, get parsed responses automatically - **Flexible Config** - Set defaults like `baseUrl` or `headers` once, use everywhere - **Comprehensive** - Built-in retries, timeouts, progress tracking, streaming, lifecycle hooks, and more - **Familiar** - same API as fetch with additional options and sensible defaults ## ➡️ Agent Skill Install the `up-fetch` skill with: ```bash npx skills add L-Blondy/up-fetch ``` ## ➡️ QuickStart ```bash npm i up-fetch ``` Create a new upfetch instance: ```ts import { up } from 'up-fetch' export const upfetch = up(fetch) ``` Make a fetch request with schema validation: ```ts import { upfetch } from './upfetch' import { z } from 'zod' const user = await upfetch('https://a.b.c/users/1', { schema: z.object({ id: z.number(), name: z.string(), avatar: z.string().url(), }), }) ``` The response is already **parsed** and properly **typed** based on the schema. _upfetch_ extends the native fetch API, which means all standard fetch options are available. ## ➡️ Key Features ### ✔️ Request Configuration Set defaults for all requests when creating an instance: ```ts const upfetch = up(fetch, () => ({ baseUrl: 'https://a.b.c', timeout: 30000, })) ``` Check out the the [API Reference][api-reference] for the full list of options. ### ✔️ Simple Query Parameters With raw fetch: ```ts fetch( `https://api.example.com/todos?search=${search}&skip=${skip}&take=${take}`, ) ``` With _upfetch_: ```ts upfetch('/todos', { params: { search, skip, take }, }) ``` Use the [serializeParams][api-reference] option to customize the query parameter serialization. ### ✔️ Automatic Body Handling With raw fetch: ```ts fetch('https://api.example.com/todos', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title: 'New Todo' }), }) ``` With _upfetch_: ```ts upfetch('/todos', { method: 'POST', body: { title: 'New Todo' }, }) ``` _upfetch_ also supports all [fetch body types](https://developer.mozilla.org/en-US/docs/Web/API/RequestInit#body). Check out the [serializeBody][api-reference] option to customize the body serialization. ### ✔️ Schema Validation Since _upfetch_ follows the [Standard Schema Specification][standard-schema] it can be used with any schema library that implements the spec. \ See the full list [here][standard-schema-libs]. With **zod** 3.24+ ```ts import { z } from 'zod' const posts = await upfetch('/posts/1', { schema: z.object({ id: z.number(), title: z.string(), }), }) ``` With **valibot** 1.0+ ```ts import { object, string, number } from 'valibot' const posts = await upfetch('/posts/1', { schema: object({ id: number(), title: string(), }), }) ``` ### ✔️ Lifecycle Hooks Control request/response lifecycle with simple hooks: ```ts const upfetch = up(fetch, () => ({ onRequest: (options) => { // Called before the request is made, options might be mutated here }, onSuccess: (data, options) => { // Called when the request successfully completes }, onError: (error, options) => { // Called when the request fails }, })) ``` ### ✔️ Timeout Set a timeout for one request: ```ts upfetch('/todos', { timeout: 3000, }) ``` Set a default timeout for all requests: ```ts const upfetch = up(fetch, () => ({ timeout: 5000, })) ``` ### ✔️ Retry The retry functionality allows you to automatically retry failed requests with configurable attempts, delay, and condition. ```ts const upfetch = up(fetch, () => ({ retry: { attempts: 3, delay: 1000, }, })) ``` Examples: Per-request retry config ```ts await upfetch('/api/data', { method: 'DELETE', retry: { attempts: 2, }, }) ``` Exponential retry delay ```ts const upfetch = up(fetch, () => ({ retry: { attempts: 3, delay: (ctx) => ctx.attempt ** 2 * 1000, }, })) ``` Retry based on the request method ```ts const upfetch = up(fetch, () => ({ retry: { // One retry for GET requests, no retries for other methods: attempts: (ctx) => (ctx.request.method === 'GET' ? 1 : 0), delay: 1000, }, })) ``` Retry based on the response status ```ts const upfetch = up(fetch, () => ({ retry: { when({ response }) { if (!response) return false return [408, 413, 429, 500, 502, 503, 504].includes(response.status) }, attempts: 1, delay: 1000, }, })) ``` Retry on network errors, timeouts, or any other error ```ts const upfetch = up(fetch, () => ({ retry: { attempts: 2, delay: 1000, when: (ctx) => { // Retry on timeout errors if (ctx.error) return ctx.error.name === 'TimeoutError' // Retry on 429 server errors if (ctx.response) return ctx.response.status === 429 return false }, }, })) ``` ### ✔️ Error Handling #### ResponseError Raised when `response.ok` is `false`. \ Use `isResponseError` to identify this error type. ```ts import { isResponseError } from 'up-fetch' try { await upfetch('/todos/1') } catch (error) { if (isResponseError(error)) { console.log(error.status) } } ``` - Use the [parseRejected][api-reference] option to throw a custom error instead. - Use the [reject][api-reference] option to decide **when** to throw. #### ResponseValidationError Raised when schema validation fails. \ Use `isResponseValidationError` to identify this error type. ```ts import { isResponseValidationError } from 'up-fetch' try { await upfetch('/todos/1', { schema: todoSchema }) } catch (error) { if (isResponseValidationError(error)) { console.log(error.issues) } } ``` ## ➡️ Usage ### ✔️ Authentication You can easily add authentication to all requests by setting a default header. Retrieve the token from `localStorage` before each request: ```ts const upfetch = up(fetch, () => ({ headers: { Authorization: localStorage.getItem('bearer-token') }, })) ``` Retrieve an async token: ```ts const upfetch = up(fetch, async () => ({ headers: { Authorization: await getToken() }, })) ``` ### ✔️ Delete a default option Simply pass `undefined`: ```ts upfetch('/todos', { signal: undefined, }) ``` Also works for single `params` and `headers`: ```ts upfetch('/todos', { headers: { Authorization: undefined }, }) ``` ### ✔️ FormData Grab the FormData from a `form`. ```ts const form = document.querySelector('#my-form') upfetch('/todos', { method: 'POST', body: new FormData(form), }) ``` Or create FormData from an object: ```ts import { serialize } from 'object-to-formdata' const upfetch = up(fetch, () => ({ serializeBody: (body) => serialize(body), })) upfetch('https://a.b.c', { method: 'POST', body: { file: new File(['foo'], 'foo.txt') }, }) ``` ### ✔️ Multiple fetch clients You can create multiple upfetch instances with different defaults: ```ts const fetchMovie = up(fetch, () => ({ baseUrl: 'https://api.themoviedb.org', headers: { accept: 'application/json', Authorization: `Bearer ${process.env.API_KEY}`, }, })) const fetchFile = up(fetch, () => ({ parseResponse: async (res) => { const name = res.url.split('/').at(-1) ?? '' const type = res.headers.get('content-type') ?? '' return new File([await res.blob()], name, { type }) }, })) ``` ### ✔️ Streaming _upfetch_ provides powerful streaming capabilities through `onRequestStreaming` for upload operations, and `onResponseStreaming` for download operations. Both handlers receive the following properties: - `chunk: Uint8Array`: The current chunk of data being streamed - `transferredBytes: number`: The amount of data transferred so far - `totalBytes?: number`: The total size of the data, read from the `"Content-Length"` header. \ For request streaming, if the header is not present, totalBytes are read from the request body. Here's an example of processing a streamed response from an AI chatbot: ```ts const decoder = new TextDecoder() upfetch('/ai-chatbot', { onResponseStreaming: ({ chunk }) => { const text = decoder.decode(chunk, { stream: true }) console.log(text) }, }) ``` ### ✔️ Progress #### Upload progress: ```ts upfetch('/upload', { method: 'POST', body: new File(['large file'], 'foo.txt'), onRequestStreaming: ({ transferredBytes, totalBytes }) => { console.log(`Progress: ${transferredBytes} / ${totalBytes}`) }, }) ``` #### Download progress: ```ts upfetch('/download', { onResponseStreaming: ({ transferredBytes, totalBytes = transferredBytes, }) => { console.log(`Progress: ${transferredBytes} / ${totalBytes}`) }, }) ``` ## ➡️ Advanced Usage ### ✔️ Error as value While the Fetch API does not throw an error when the response is not ok, _upfetch_ throws a `ResponseError` instead. If you'd rather handle errors as values, set `reject` to return `false`. \ This allows you to customize the `parseResponse` function to return both successful data and error responses in a structured format. ```ts const upfetch = up(fetch, () => ({ reject: () => false, parseResponse: async (response) => { const json = await response.json() return response.ok ? { data: json, error: null } : { data: null, error: json } }, })) ``` Usage: ```ts const { data, error } = await upfetch('/users/1') ``` ### ✔️ Custom response parsing By default _upfetch_ is able to parse

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

TypeScriptapifetchfetch-clientfetch-wrapper

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category开发工具
PricingOpen source

> Related tools

V
VS Code
流行的开源代码编辑器
G
Git
分布式版本控制系统
V
Vite
下一代前端构建工具