Gathering detailed insights and metrics for up-fetch
Gathering detailed insights and metrics for up-fetch
Gathering detailed insights and metrics for up-fetch
Gathering detailed insights and metrics for up-fetch
be-looking-up
fetch data from a url.
@cardbrother/up-fetch
Advanced fetch client builder for typescript.
fetch-fic
Package up delicious, delicious fanfic from various sources into epub ebooks ready for reading in your ereader of choice.
fetch-response-handler
A function that wraps up the fetch API with opinionated handling of the Response Promise which effectively removes all boiler plate from making REST requests to back-end APIs
npm install up-fetch
Typescript
Module System
Min. Node Version
Node Version
NPM Version
56.9
Supply Chain
35.1
Quality
90.5
Maintenance
100
Vulnerability
0
License
TypeScript (99.04%)
HTML (0.96%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
MIT License
1,252 Stars
902 Commits
16 Forks
6 Watchers
1 Branches
3 Contributors
Updated on Jul 18, 2025
Latest Version
2.1.7
Package Id
up-fetch@2.1.7
Unpacked Size
313.66 kB
Size
92.03 kB
File Count
39
NPM Version
10.9.2
Node Version
22.17.0
Published on
Jul 18, 2025
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
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.
params
and body
, get parsed responses automaticallybaseUrl
or headers
once, use everywhere1npm i up-fetch
Create a new upfetch instance:
1import { up } from 'up-fetch' 2 3export const upfetch = up(fetch)
Make a fetch request with schema validation:
1import { upfetch } from './upfetch' 2import { z } from 'zod' 3 4const user = await upfetch('https://a.b.c/users/1', { 5 schema: z.object({ 6 id: z.number(), 7 name: z.string(), 8 avatar: z.string().url(), 9 }), 10})
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.
Set defaults for all requests when creating an instance:
1const upfetch = up(fetch, () => ({ 2 baseUrl: 'https://a.b.c', 3 timeout: 30000, 4}))
Check out the the API Reference for the full list of options.
👎 With raw fetch:
1fetch( 2 `https://api.example.com/todos?search=${search}&skip=${skip}&take=${take}`, 3)
👍 With upfetch:
1upfetch('/todos', { 2 params: { search, skip, take }, 3})
Use the serializeParams option to customize the query parameter serialization.
👎 With raw fetch:
1fetch('https://api.example.com/todos', { 2 method: 'POST', 3 headers: { 'Content-Type': 'application/json' }, 4 body: JSON.stringify({ title: 'New Todo' }), 5})
👍 With upfetch:
1upfetch('/todos', { 2 method: 'POST', 3 body: { title: 'New Todo' }, 4})
upfetch also supports all fetch body types.
Check out the serializeBody option to customize the body serialization.
Since upfetch follows the Standard Schema Specification it can be used with any schema library that implements the spec.
See the full list here.
👉 With zod 3.24+
1import { z } from 'zod' 2 3const posts = await upfetch('/posts/1', { 4 schema: z.object({ 5 id: z.number(), 6 title: z.string(), 7 }), 8})
👉 With valibot 1.0+
1import { object, string, number } from 'valibot' 2 3const posts = await upfetch('/posts/1', { 4 schema: object({ 5 id: number(), 6 title: string(), 7 }), 8})
Control request/response lifecycle with simple hooks:
1const upfetch = up(fetch, () => ({ 2 onRequest: (options) => { 3 // Called before the request is made, options might be mutated here 4 }, 5 onSuccess: (data, options) => { 6 // Called when the request successfully completes 7 }, 8 onError: (error, options) => { 9 // Called when the request fails 10 }, 11}))
Set a timeout for one request:
1upfetch('/todos', { 2 timeout: 3000, 3})
Set a default timeout for all requests:
1const upfetch = up(fetch, () => ({ 2 timeout: 5000, 3}))
The retry functionality allows you to automatically retry failed requests with configurable attempts, delay, and condition.
1const upfetch = up(fetch, () => ({ 2 retry: { 3 attempts: 3, 4 delay: 1000, 5 }, 6}))
Examples:
1await upfetch('/api/data', { 2 method: 'DELETE', 3 retry: { 4 attempts: 2, 5 }, 6})
1const upfetch = up(fetch, () => ({ 2 retry: { 3 attempts: 3, 4 delay: (ctx) => ctx.attempt ** 2 * 1000, 5 }, 6}))
1const upfetch = up(fetch, () => ({ 2 retry: { 3 // One retry for GET requests, no retries for other methods: 4 attempts: (ctx) => (ctx.request.method === 'GET' ? 1 : 0), 5 delay: 1000, 6 }, 7}))
1const upfetch = up(fetch, () => ({ 2 retry: { 3 when: (ctx) => 4 [408, 413, 429, 500, 502, 503, 504].includes(ctx.response?.status), 5 attempts: 1, 6 delay: 1000, 7 }, 8}))
1const upfetch = up(fetch, () => ({ 2 retry: { 3 attempts: 2, 4 delay: 1000, 5 when: (ctx) => { 6 // Retry on timeout errors 7 if (ctx.error) return ctx.error.name === 'TimeoutError' 8 // Retry on 429 server errors 9 if (ctx.response) return ctx.response.status === 429 10 return false 11 }, 12 }, 13}))
Raised when response.ok
is false
.
Use isResponseError
to identify this error type.
1import { isResponseError } from 'up-fetch' 2 3try { 4 await upfetch('/todos/1') 5} catch (error) { 6 if (isResponseError(error)) { 7 console.log(error.status) 8 } 9}
Raised when schema validation fails.
Use isValidationError
to identify this error type.
1import { isValidationError } from 'up-fetch' 2 3try { 4 await upfetch('/todos/1', { schema: todoSchema }) 5} catch (error) { 6 if (isValidationError(error)) { 7 console.log(error.issues) 8 } 9}
You can easily add authentication to all requests by setting a default header.
Retrieve the token from localStorage
before each request:
1const upfetch = up(fetch, () => ({ 2 headers: { Authorization: localStorage.getItem('bearer-token') }, 3}))
Retrieve an async token:
1const upfetch = up(fetch, async () => ({ 2 headers: { Authorization: await getToken() }, 3}))
Simply pass undefined
:
1upfetch('/todos', { 2 signal: undefined, 3})
Also works for single params
and headers
:
1upfetch('/todos', { 2 headers: { Authorization: undefined }, 3})
Grab the FormData from a form
.
1const form = document.querySelector('#my-form') 2 3upfetch('/todos', { 4 method: 'POST', 5 body: new FormData(form), 6})
Or create FormData from an object:
1import { serialize } from 'object-to-formdata' 2 3const upfetch = up(fetch, () => ({ 4 serializeBody: (body) => serialize(body), 5})) 6 7upfetch('https://a.b.c', { 8 method: 'POST', 9 body: { file: new File(['foo'], 'foo.txt') }, 10})
You can create multiple upfetch instances with different defaults:
1const fetchMovie = up(fetch, () => ({ 2 baseUrl: 'https://api.themoviedb.org', 3 headers: { 4 accept: 'application/json', 5 Authorization: `Bearer ${process.env.API_KEY}`, 6 }, 7})) 8 9const fetchFile = up(fetch, () => ({ 10 parseResponse: async (res) => { 11 const name = res.url.split('/').at(-1) ?? '' 12 const type = res.headers.get('content-type') ?? '' 13 return new File([await res.blob()], name, { type }) 14 }, 15}))
upfetch provides powerful streaming capabilities through onRequestStreaming
for upload operations, and onResponseStreaming
for download operations.
Both handlers receive the following event object plus the request/response:
1type StreamingEvent = { 2 chunk: Uint8Array // The current chunk of data being streamed 3 totalBytes: number // Total size of the data 4 transferredBytes: number // Amount of data transferred so far 5}
The totalBytes
property of the event is read from the "Content-Length"
header.
For request streaming, if the header is not present, the total bytes are read from the request body.
Here's an example of processing a streamed response from an AI chatbot:
1const decoder = new TextDecoder() 2 3upfetch('/ai-chatbot', { 4 onResponseStreaming: (event, response) => { 5 const text = decoder.decode(event.chunk) 6 console.log(text) 7 }, 8})
Upload progress:
1upfetch('/upload', { 2 method: 'POST', 3 body: new File(['large file'], 'foo.txt'), 4 onRequestStreaming: ({ transferredBytes, totalBytes }) => { 5 console.log(`Progress: ${transferredBytes} / ${totalBytes}`) 6 }, 7})
Download progress:
1upfetch('/download', { 2 onResponseStreaming: ({ transferredBytes, totalBytes }) => { 3 console.log(`Progress: ${transferredBytes} / ${totalBytes}`) 4 }, 5})
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.
1const upfetch = up(fetch, () => ({ 2 reject: () => false, 3 parseResponse: async (response) => { 4 const json = await response.json() 5 return response.ok 6 ? { data: json, error: null } 7 : { data: null, error: json } 8 }, 9}))
Usage:
1const { data, error } = await upfetch('/users/1')
By default upfetch is able to parse json
and text
sucessful responses automatically.
The parseResponse
method is called when reject
returns false
.
You can use that option to parse other response types.
1const upfetch = up(fetch, () => ({ 2 parseResponse: (response) => response.blob(), 3}))
💡 Note that the parseResponse
method is called only when reject
returns false
.
By default upfetch throws a ResponseError
when reject
returns true
.
If you want to throw a custom error instead, you can pass a function to the parseRejected
option.
1const upfetch = up(fetch, () => ({ 2 parseRejected: async (response) => { 3 const status = response.status 4 const data = await response.json() 5 return new CustomError(status, data) 6 }, 7}))
By default upfetch serializes the params using URLSearchParams
.
You can customize the params serialization by passing a function to the serializeParams
option.
1import queryString from 'query-string' 2 3const upfetch = up(fetch, () => ({ 4 serializeParams: (params) => queryString.stringify(params), 5}))
By default upfetch serializes the plain objects using JSON.stringify
.
You can customize the body serialization by passing a function to the serializeBody
option. It lets you:
BodyInit
typeThe following example show how to restrict the valid body type to Record<string, any>
and serialize it using JSON.stringify
:
1// Restrict the body type to Record<string, any> and serialize it 2const upfetch = up(fetch, () => ({ 3 serializeBody: (body: Record<string, any>) => JSON.stringify(body), 4})) 5 6// ❌ type error: the body is not a Record<string, any> 7upfetch('https://a.b.c/todos', { 8 method: 'POST', 9 body: [['title', 'New Todo']], 10}) 11 12// ✅ works fine with Record<string, any> 13upfetch('https://a.b.c/todos', { 14 method: 'POST', 15 body: { title: 'New Todo' }, 16})
The following example uses superjson
to serialize the body. The valid body type is inferred from SuperJSON.stringify
.
1import SuperJSON from 'superjson' 2 3const upfetch = up(fetch, () => ({ 4 serializeBody: SuperJSON.stringify, 5}))
The default options receive the fetcher arguments, this allows you to tailor the defaults based on the actual request.
1const upfetch = up(fetch, (input, options) => ({ 2 baseUrl: 'https://example.com/', 3 // Add authentication only for protected routes 4 headers: { 5 Authorization: 6 typeof input === 'string' && input.startsWith('/api/protected/') 7 ? `Bearer ${getToken()}` 8 : undefined, 9 }, 10 // Add tracking params only for public endpoints 11 params: { 12 trackingId: 13 typeof input === 'string' && input.startsWith('/public/') 14 ? crypto.randomUUID() 15 : undefined, 16 }, 17 // Increase timeout for long-running operations 18 timeout: 19 typeof input === 'string' && input.startsWith('/export/') ? 30000 : 5000, 20}))
Creates a new upfetch instance with optional default options.
1function up( 2 fetchFn: typeof globalThis.fetch, 3 getDefaultOptions?: ( 4 input: RequestInit, 5 options: FetcherOptions, 6 ) => DefaultOptions | Promise<DefaultOptions>, 7): UpFetch
Option | Signature | Description |
---|---|---|
baseUrl | string | Base URL for all requests. |
onError | (error, request) => void | Executes on error. |
onSuccess | (data, request) => void | Executes when the request successfully completes. |
onRequest | (request) => void | Executes before the request is made. |
onRequestStreaming | (event, request) => void | Executes each time a request chunk is send. |
onResponseStreaming | (event, response) => void | Executes each time a response chunk is received. |
onRetry | (ctx) => void | Executes before each retry. |
params | object | The default query parameters. |
parseResponse | (response, request) => data | The default success response parser. If omitted json and text response are parsed automatically. |
parseRejected | (response, request) => error | The default error response parser. If omitted json and text response are parsed automatically |
reject | (response) => boolean | Decide when to reject the response. |
retry | RetryOptions | The default retry options. |
serializeBody | (body) => BodyInit | The default body serializer. Restrict the valid body type by typing its first argument. |
serializeParams | (params) => string | The default query parameter serializer. |
timeout | number | The default timeout in milliseconds. |
...and all other fetch options |
Makes a fetch request with the given options.
1function upfetch( 2 url: string | URL | Request, 3 options?: FetcherOptions, 4): Promise<any>
Options:
Option | Signature | Description |
---|---|---|
baseUrl | string | Base URL for the request. |
onError | (error, request) => void | Executes on error. |
onSuccess | (data, request) => void | Executes when the request successfully completes. |
onRequest | (request) => void | Executes before the request is made. |
onRequestStreaming | (event, request) => void | Executes each time a request chunk is send. |
onResponseStreaming | (event, response) => void | Executes each time a response chunk is received. |
onRetry | (ctx) => void | Executes before each retry. |
params | object | The query parameters. |
parseResponse | (response, request) => data | The success response parser. |
parseRejected | (response, request) => error | The error response parser. |
reject | (response) => boolean | Decide when to reject the response. |
retry | RetryOptions | The retry options. |
schema | StandardSchemaV1 | The schema to validate the response against. The schema must follow the Standard Schema Specification. |
serializeBody | (body) => BodyInit | The body serializer. Restrict the valid body type by typing its first argument. |
serializeParams | (params) => string | The query parameter serializer. |
timeout | number | The timeout in milliseconds. |
...and all other fetch options |
Option | Signature | Description |
---|---|---|
when | (ctx) => boolean | Function that determines if a retry should happen based on the response or error |
attempts | number | function | Number of retry attempts or function to determine attempts based on request. |
delay | number | function | Delay between retries in milliseconds or function to determine delay based on attempt number |
Checks if the error is a ResponseError
.
Checks if the error is a ValidationError
.
Determines whether a value can be safely converted to json
.
Are considered jsonifiable:
toJSON
methodCheck out the Feature Comparison table to see how upfetch compares to other fetching libraries.
No vulnerabilities found.
No security vulnerabilities found.