Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/molvqingtai/resreq
π Fetch-based onion model http client.
https://github.com/molvqingtai/resreq
axios deno fetch http nodejs request typescript xmlhttprequest
Last synced: 19 days ago
JSON representation
π Fetch-based onion model http client.
- Host: GitHub
- URL: https://github.com/molvqingtai/resreq
- Owner: molvqingtai
- License: mit
- Created: 2020-12-04T16:54:07.000Z (almost 4 years ago)
- Default Branch: master
- Last Pushed: 2024-03-18T22:37:09.000Z (8 months ago)
- Last Synced: 2024-10-23T18:47:16.893Z (23 days ago)
- Topics: axios, deno, fetch, http, nodejs, request, typescript, xmlhttprequest
- Language: TypeScript
- Homepage: https://molvqingtai.github.io/resreq
- Size: 1.38 MB
- Stars: 22
- Watchers: 1
- Forks: 4
- Open Issues: 8
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Resreq
[![version](https://img.shields.io/github/v/release/molvqingtai/resreq)](https://www.npmjs.com/package/resreq) [![deno land](http://img.shields.io/badge/available%20on-deno.land/x-lightgrey.svg?logo=deno&labelColor=black&color=blue)](https://deno.land/x/resreq) [![workflow](https://github.com/molvqingtai/resreq/actions/workflows/ci.yml/badge.svg)](https://github.com/molvqingtai/resreq/actions) [![download](https://img.shields.io/npm/dt/resreq)](https://www.npmjs.com/package/resreq) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
## What is resreq?
It is a modern http client, based on [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch), because it is implemented internally using the onion model, so you can use middleware to intercept requests and responses elegantly.
[Learn more](https://dev.to/molvqingtai/applying-koas-onion-model-to-front-end-requests-356p)
## Install
Resreq targets modern browsers and [Deno](https://github.com/denoland/deno)
```shell
pnpm install resreq
```**or**
```typescript
import Resreq from 'https://esm.sh/resreq'
```If you are using a lower version of [node](https://nodejs.org/en/), you may need to add some polyfill.
```typescript
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
```## Documentation
### Get Started
```typescript
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) // Objectconst res = await resreq.get('/api/download', {
responseType: 'blob'
})
console.log(res) // Blob
```**Cancel request**
```typescript
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 cancel
```**Use Middlewares**
```typescript
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)
```### API
**new Resreq(options?:Options)**
Create a resreq instance and configure the global options.
```typescript
const resreq = new Resreq({
baseURL: 'https://example.com',
timeout: 10000,
responseType: 'json',
throwHttpError: true,
onDownloadProgress(progress, chunk) {
console.log(progress, chunk)
}
})
```**resreq.request(options?:Options)**
Use ''request'' to send the request and configure the options.
```typescript
const resreq = new Resreq({
baseURL: 'https://example.com'
})const res = await resreq.request({
url: '/api',
method: 'GET',
params: { foo: 'bar' },
throwHttpError: true,
onDownloadProgress(progress, chunk) {
console.log(progress, chunk)
}
})console.log(res)
```**resreq\[method\](options?:Options)**
Use ''method'' to send the request and configure the options
```typescript
const resreq = new Resreq({
baseURL: 'https://example.com'
})const res = await resreq.get('/api', {
params: { foo: 'bar' },
throwHttpError: true,
onDownloadProgress(progress, chunk) {
console.log(progress, chunk)
}
})console.log(res)
```**resreq.use(middleware:Middleware)**
Add headers using middleware.
```typescript
import Resreq, { Middleware } from 'resreq'const resreq = new Resreq({
baseURL: 'https://example.com'
})// Implement a middleware that set token
const setAccessToken: Middleware = (next) => (req) => {
req.headers.set('Access-Token', 'foo-bar')
return next(req)
}// Register middleware
resreq.use(setAccessToken)await resreq.get('/api')
```Rewriting headers using middleware.
```typescript
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'
}
})
console.log(_req.headers.get('Content-Type')) // null
console.log(_req.headers.get('X-Custom-Header')) // barreturn await next(_req)
})await resreq.get('/api', {
headers: {
'Content-Type': 'application/json',
'X-Custom-Header': 'foo'
}
})
```**Req(request: Req, init: ReqInit | Request)**
**Res(response: Res, init: ResInit | Response)**
In the middleware, use `new Req()` and `new Res()` to rewrite the request and response.
```typescript
import Resreq, { Req, Res } from 'resreq'const resreq = new Resreq({
baseURL: 'https://example.com',
})resreq.use((next) => async (req) => {
const _req = new Req(req, {
url: 'https://example.com/mock'
})const res = await next(_req)
return new Res(res, {
body: { foo: 'bar' }
status: 200,
})
})const res: Response = await resreq.get('/api')
console.log(res.status) // 200
console.log(await res.json()) // { foo: 'bar' }
```> **Warning**
> Req & Res extends from [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request) and [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response); to create a new request and response in the middleware, use `new Req()` and `new Res()`.
>
> To access the contents of the `body` in the current middleware, please use `Res.clone()` to ensure that the res received by the next middleware are unlocked.### Interfaces
**Options**
Options extends from the [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request) type with some additional properties
```typescript
interface Options extends Omit {
baseURL?: string
url?: string
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD' | 'PATCH'
params?: Record
body?: BodyInit | Record
meta?: Record
timeout?: number
responseType?: 'json' | 'arrayBuffer' | 'blob' | 'formData' | 'text' | null | false
throwHttpError?: boolean
onDownloadProgress?: ProgressCallback
}
```- **baseURL**: The url prefix of the request will be concatenated with the url in `resreq[method]()` to form a complete request address, the default value is ' '.
- **url**: Request url, the default value is ' '.
- **method**οΌRequest method, the default value is 'GET'.
- **params**: The params of a `resreq.get` request are automatically added to the url via the [new URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) method.
- **body**: Based on [BodyInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request), and adding `Record`, which means you can pass `object` directly, instead of `JSON.stringify(object)`, which will automatically add `Content-Type: application/json` request headers.
- **meta**: The extra information that needs to be carried in the request is not really sent to the server, but it can be obtained in `Res.meta` and `Req.meta`.
- **timeout**: Specify the number of milliseconds of time before the request, if the time is exceeded the request will be aborted, the default value is 1000ms.
- **responseType**: Set how the response will be parsed, if not set or set to false, the [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) instance will be returned, the default value is undefined.
- **throwHttpError**: If true, a status code outside of 200-299 will throw an error, the default value is false.
- **onDownloadProgress**: The download progress hook, which depends on the [ReadableStream API](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream), polyfill is required in lower versions of node.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.
- **meta**: The meta within the method will be shallow merged with the global meta.
- **headers**: The headers defined in the method are merged into the global headers.
- **onDownloadProgress**: Defining onDownloadProgress in a method and the global onDownloadProgress are both retained.
**ReqInit**
Options extends from the [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request) type with some additional properties.
```typescript
interface ReqInit extends Omit {
url?: string
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD' | 'PATCH'
meta?: Record
timeout?: number
responseType?: ResponseType
throwHttpError?: boolean
body?: BodyInit | Record
onDownloadProgress?: ProgressCallback
}
```> **Note**
> That its 'headers' behave differently than 'Options.headers', which overrides the global headers.**ResInit**
ResInit extends from the [ResponseInit](https://developer.mozilla.org/en-US/docs/Web/API/Response/Response) type with some additional properties.
```typescript
interface ResInit extends ResponseInit {
meta?: Record
body?: BodyInit | Record | null
timeout?: number
responseType?: ResponseType
throwHttpError?: boolean
onDownloadProgress?: ProgressCallback
}
```**Middleware**
The middleware must call next(req) to return a promise.
```typescript
type Middleware = (next: Next) => (req: Req) => Promise
```### Standing on the shoulders of giants
Some of the inspiration for this project came from their.
- [Axios](https://github.com/axios/axios): Promise based HTTP client for the browser and node.js.
- [Ky](https://github.com/sindresorhus/ky): Tiny & elegant JavaScript HTTP client based on the browser Fetch API.
- [Redux](https://github.com/reduxjs/redux): Predictable state container for JavaScript apps.
- [Koa](https://github.com/koajs/koa): Next generation web framework for node.js.### License
This project is licensed under the MIT License - see the [LICENSE](https://github.com/molvqingtai/resreq/blob/master/LICENSE) file for details.