It is a modern http client, based on fetch, because it is implemented internally using the onion model, so you can use middleware to intercept requests and responses elegantly.
Resreq targets modern browsers and Deno
pnpm install resreq
or
import Resreq from 'https://esm.sh/resreq'
If you use it in Node, you need to add some polyfill
import fetch, { Headers, Request, Response } from 'node-fetch'
import AbortController from 'abort-controller'
globalThis.fetch = fetch
globalThis.Headers = Headers
globalThis.Request = Request
globalThis.Response = Response
globalThis.AbortController = AbortController
import Resreq from 'resreq'
const resreq = new Resreq({
baseUrl: 'https://example.com',
responseType: 'json'
})
const res = await resreq.request({
url: '/api/user',
method: 'GET',
params: { foo: 'bar' }
})
console.log(res) // Object
const res = await resreq.get('/api/download', {
responseType: 'blob'
})
console.log(res) // Blob
Cancel request
const resreq = new Resreq()
const abortController = new AbortController()
resreq.get('https://example.com/api', {
signal: abortController.signal
}).catch(error => {
console.log(error) // Abort error
})
abortController.abort() // request abort
Use Middlewares
const resreq = new Resreq({
baseUrl: 'https://example.com'
})
// Intercepting responses and requests using middleware
resreq.use((next) => async (req) => {
try {
console.log(req) // Request can be changed here
const res = await next(req)
console.log(res) // Response can be changed here
return res
} catch (error) {
console.log(error) // Catch errors here
throw error
}
})
const res = await resreq.get('/api', {
params: { foo: 'bar' }
})
console.log(res)
new Resreq(options?:Options)
Create a resreq instance and configure the global options
const resreq = new Resreq({
baseUrl: 'https://example.com',
timeout: 10000,
responseType: 'json',
throwHttpError: true,
onResponseProgress(progress, chunk) {
console.log(progress, chunk)
}
})
resreq.request(options?:Options)
Use ''request'' to send the request and configure the options
const resreq = new Resreq({
baseUrl: 'https://example.com'
})
const res = await resreq.request({
url: '/api',
method: 'GET',
params: { foo: 'bar' },
throwHttpError: true,
onResponseProgress(progress, chunk) {
console.log(progress, chunk)
}
})
console.log(res)
resreq[method](options?:Options)
Use ''method'' to send the request and configure the options
const resreq = new Resreq({
baseUrl: 'https://example.com'
})
const res = await resreq.get('/api', {
params: { foo: 'bar' },
throwHttpError: true,
onResponseProgress(progress, chunk) {
console.log(progress, chunk)
}
})
console.log(res)
resreq.use(middleware:Middleware)
Rewriting request headers using middleware
import Resreq, { Req } from 'resreq'
const resreq = new Resreq({
baseUrl: 'https://example.com'
})
resreq.use(next => async req => {
// Create a new request with Req
const _req = new Req(req, {
headers: {
'X-Custom-Header': 'bar'
}
})
return await next(_req)
})
const res: Response = await resreq.get('/api', {
headers: {
'X-Custom-Header': 'foo'
}
})
console.log(res.headers.get('X-Custom-Header')) // bar
Req(req:Req, init?:ReqInit)
Res(res:Res, init?:ResInit)
In the middleware, use new Req()
and new Res()
to rewrite the request and response
import Resreq, { Middleware, Req, Res } from 'resreq'
const resreq = new Resreq({
baseUrl: 'https://example.com'
})
const middleware: Middleware = next => async req => {
const _req = new Req(req, {
url: 'http://localhost:3000/mock'
})
const res = await next(_req)
return new Res(res, {
status: 200,
statusText: 'mock success'
})
}
const res: Response = await resreq.get('/api')
console.log(res.status) // 200
Warning Req & Res extends from Request and Response; to create a new request and response in the middleware, use Req & Res
Options
Options extends from the RequestInit type with some additional properties
interface Options extends Omit<RequestInit, 'body'> {
baseUrl?: string
url?: string
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD' | 'PATCH'
params?: Record<string, any>
body?: BodyInit | Record<string, any>
meta?: Record<string, any>
timeout?: number
responseType?: 'json' | 'arrayBuffer' | 'blob' | 'formData' | 'text' | null | false
throwHttpError?: boolean
onResponseProgress?: ProgressCallback
}
resreq[method]()
to form a complete request address, the default value is ' 'resreq.get
request are automatically added to the url via the new URLSearchParams methodRecord<string, any>
, which means you can pass object
directly, instead of JSON.stringify(object)
, which will automatically add Content-Type: application/json
request headersres.meta
To avoid adding complexity, new Resreq(options)
and resreq[method](options)
, in which 'options' are of the same type
The options defined in new Resreq(options)
will take effect globally, resreq[method](options)
, will override the "global options", except for the following options which will not be overridden
headers: The headers defined in the method are merged into the global headers
onResponseProgress: Defining onResponseProgress in a method and the global onResponseProgress are both retained.
ReqInit
Options extends from the RequestInit type with some additional properties
interface ReqInit extends Omit<RequestInit, 'body'> {
url?: string
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD' | 'PATCH'
meta?: Record<string, any>
timeout?: number
responseType?: 'json' | 'arrayBuffer' | 'blob' | 'formData' | 'text' | null | false
throwHttpError?: boolean
body?: BodyInit | Record<string, any>
onResponseProgress?: ProgressCallback
}
Note That its 'headers' behave differently than 'Options.headers', which overrides the global headers
ResInit
ResInit extends from the ResponseInit type with some additional properties
interface ResInit extends ResponseInit {
meta?: Record<string, any>
timeout?: number
responseType?: 'json' | 'arrayBuffer' | 'blob' | 'formData' | 'text' | null | false
throwHttpError?: boolean
onResponseProgress?: ProgressCallback
}
Middleware
The middleware must call next(req) to return a promise
type Middleware = (next: Next) => (req: Req) => Promise<Res>
Some of the inspiration for this project came from their.
This project is licensed under the MIT License - see the LICENSE file for details
Generated using TypeDoc