{"id":17784756,"url":"https://github.com/molvqingtai/resreq","last_synced_at":"2025-03-16T04:30:42.080Z","repository":{"id":37027740,"uuid":"318579832","full_name":"molvqingtai/resreq","owner":"molvqingtai","description":"🍭 Fetch-based onion model http client.","archived":false,"fork":false,"pushed_at":"2024-03-18T22:37:09.000Z","size":1443,"stargazers_count":25,"open_issues_count":8,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-12T00:14:39.023Z","etag":null,"topics":["axios","deno","fetch","http","nodejs","request","typescript","xmlhttprequest"],"latest_commit_sha":null,"homepage":"https://molvqingtai.github.io/resreq","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/molvqingtai.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-12-04T16:54:07.000Z","updated_at":"2025-01-02T01:58:23.000Z","dependencies_parsed_at":"2023-02-13T04:00:37.271Z","dependency_job_id":"5f6f88b4-9a7e-4700-88c0-aae10845be3b","html_url":"https://github.com/molvqingtai/resreq","commit_stats":{"total_commits":145,"total_committers":2,"mean_commits":72.5,"dds":"0.11724137931034484","last_synced_commit":"292b52792c5a84b5453a16973726156d8b79aa54"},"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/molvqingtai%2Fresreq","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/molvqingtai%2Fresreq/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/molvqingtai%2Fresreq/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/molvqingtai%2Fresreq/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/molvqingtai","download_url":"https://codeload.github.com/molvqingtai/resreq/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243769963,"owners_count":20345217,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["axios","deno","fetch","http","nodejs","request","typescript","xmlhttprequest"],"created_at":"2024-10-27T08:06:17.816Z","updated_at":"2025-03-16T04:30:41.476Z","avatar_url":"https://github.com/molvqingtai.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/molvqingtai/resreq/blob/master/logo.svg\" width=\"300px\"/\u003e\n\u003c/p\u003e\n\n# Resreq\n\n[![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\u0026labelColor=black\u0026color=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)\n\n## What is resreq?\n\nIt 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.\n\n[Learn more](https://dev.to/molvqingtai/applying-koas-onion-model-to-front-end-requests-356p)\n\n## Install\n\nResreq targets modern browsers and [Deno](https://github.com/denoland/deno)\n\n```shell\npnpm install resreq\n```\n\n**or**\n\n```typescript\nimport Resreq from 'https://esm.sh/resreq'\n```\n\nIf you are using a lower version of [node](https://nodejs.org/en/), you may need to add some polyfill.\n\n```typescript\nimport fetch, { Headers, Request, Response } from 'node-fetch'\nimport AbortController from 'abort-controller'\n\nglobalThis.fetch = fetch\nglobalThis.Headers = Headers\nglobalThis.Request = Request\nglobalThis.Response = Response\nglobalThis.AbortController = AbortController\n```\n\n## Documentation\n\n### Get Started\n\n```typescript\nimport Resreq from 'resreq'\n\nconst resreq = new Resreq({\n  baseURL: 'https://example.com',\n  responseType: 'json'\n})\n\nconst res = await resreq.request({\n  url: '/api/user',\n  method: 'GET',\n  params: { foo: 'bar' }\n})\nconsole.log(res) // Object\n\nconst res = await resreq.get('/api/download', {\n  responseType: 'blob'\n})\nconsole.log(res) // Blob\n```\n\n**Cancel request**\n\n```typescript\nconst resreq = new Resreq()\n\nconst abortController = new AbortController()\n\nresreq.get('https://example.com/api', {\n    signal: abortController.signal\n  })\n  .catch((error) =\u003e {\n    console.log(error) // Abort error\n  })\n\nabortController.abort() // request cancel\n```\n\n**Use Middlewares**\n\n```typescript\nconst resreq = new Resreq({\n  baseURL: 'https://example.com'\n})\n\n// Intercepting responses and requests using middleware\nresreq.use((next) =\u003e async (req) =\u003e {\n  try {\n    console.log(req) // Request can be changed here\n    const res = await next(req)\n    console.log(res) // Response can be changed here\n    return res\n  } catch (error) {\n    console.log(error) // Catch errors here\n    throw error\n  }\n})\n\nconst res = await resreq.get('/api', {\n  params: { foo: 'bar' }\n})\n\nconsole.log(res)\n```\n\n### API\n\n**new Resreq(options?:Options)**\n\nCreate a resreq instance and configure the global options.\n\n```typescript\nconst resreq = new Resreq({\n  baseURL: 'https://example.com',\n  timeout: 10000,\n  responseType: 'json',\n  throwHttpError: true,\n  onDownloadProgress(progress, chunk) {\n    console.log(progress, chunk)\n  }\n})\n```\n\n**resreq.request(options?:Options)**\n\nUse ''request'' to send the request and configure the options.\n\n```typescript\nconst resreq = new Resreq({\n  baseURL: 'https://example.com'\n})\n\nconst res = await resreq.request({\n  url: '/api',\n  method: 'GET',\n  params: { foo: 'bar' },\n  throwHttpError: true,\n  onDownloadProgress(progress, chunk) {\n    console.log(progress, chunk)\n  }\n})\n\nconsole.log(res)\n```\n\n**resreq\\[method\\](options?:Options)**\n\nUse ''method'' to send the request and configure the options\n\n```typescript\nconst resreq = new Resreq({\n  baseURL: 'https://example.com'\n})\n\nconst res = await resreq.get('/api', {\n  params: { foo: 'bar' },\n  throwHttpError: true,\n  onDownloadProgress(progress, chunk) {\n    console.log(progress, chunk)\n  }\n})\n\nconsole.log(res)\n```\n\n**resreq.use(middleware:Middleware)**\n\nAdd  headers using middleware.\n\n```typescript\nimport Resreq, { Middleware } from 'resreq'\n\nconst resreq = new Resreq({\n  baseURL: 'https://example.com'\n})\n\n// Implement a middleware that set token\nconst setAccessToken: Middleware = (next) =\u003e (req) =\u003e {\n  req.headers.set('Access-Token', 'foo-bar')\n  return next(req)\n}\n\n// Register middleware\nresreq.use(setAccessToken)\n\nawait resreq.get('/api')\n```\n\nRewriting  headers using middleware.\n\n```typescript\nimport Resreq, { Req } from 'resreq'\n\nconst resreq = new Resreq({\n  baseURL: 'https://example.com'\n})\n\nresreq.use((next) =\u003e async (req) =\u003e {\n  \n  // Create a new request with Req\n  const _req = new Req(req, {\n    headers: {\n      'X-Custom-Header': 'bar'\n    }\n  })\n  \n  console.log(_req.headers.get('Content-Type')) // null\n  console.log(_req.headers.get('X-Custom-Header')) // bar\n\n  return await next(_req)\n})\n\nawait resreq.get('/api', {\n  headers: {\n    'Content-Type': 'application/json',\n    'X-Custom-Header': 'foo'\n  }\n})\n```\n\n**Req(request: Req, init: ReqInit | Request)**\n\n**Res(response: Res, init: ResInit | Response)**\n\nIn the middleware, use `new Req()` and `new Res()` to rewrite the request and response.\n\n```typescript\nimport Resreq, { Req, Res } from 'resreq'\n\nconst resreq = new Resreq({\n  baseURL: 'https://example.com',\n})\n\nresreq.use((next) =\u003e async (req) =\u003e {\n  \n  const _req = new Req(req, {\n    url: 'https://example.com/mock'\n  })\n\n  const res = await next(_req)\n  return new Res(res, {\n    body: { foo: 'bar' }\n    status: 200,\n  })\n})\n\nconst res: Response = await resreq.get('/api')\n\nconsole.log(res.status) // 200\nconsole.log(await res.json()) // { foo: 'bar' }\n```\n\n\u003e **Warning**\n\u003e Req \u0026 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()`.\n\u003e\n\u003e 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.\n\n### Interfaces\n\n**Options**\n\nOptions extends from the [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request) type with some additional properties\n\n```typescript\ninterface Options extends Omit\u003cRequestInit, 'body'\u003e {\n  baseURL?: string\n  url?: string\n  method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD' | 'PATCH'\n  params?: Record\u003cstring, any\u003e\n  body?: BodyInit | Record\u003cstring, any\u003e\n  meta?: Record\u003cstring, any\u003e\n  timeout?: number\n  responseType?: 'json' | 'arrayBuffer' | 'blob' | 'formData' | 'text' | null | false\n  throwHttpError?: boolean\n  onDownloadProgress?: ProgressCallback\n}\n```\n\n- **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 ' '.\n- **url**: Request url, the default value is ' '.\n- **method**：Request method, the default value is 'GET'.\n- **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.\n- **body**: Based on [BodyInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request), and adding `Record\u003cstring, any\u003e`, which means you can pass `object` directly, instead of `JSON.stringify(object)`, which will automatically add `Content-Type: application/json` request headers.\n- **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`.\n- **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.\n- **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.\n- **throwHttpError**: If true, a status code outside of 200-299 will throw an error, the default value is false.\n- **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.\n\nTo avoid adding complexity, `new Resreq(options)` and `resreq[method](options)`, in which 'options' are of the same type.\n\nThe 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.\n\n- **meta**: The meta within the method will be shallow merged with the global meta.\n\n- **headers**: The headers defined in the method are merged into the global headers.\n\n- **onDownloadProgress**: Defining onDownloadProgress in a method and the global onDownloadProgress are both retained.\n\n**ReqInit**\n\nOptions extends from the [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request) type with some additional properties.\n\n```typescript\ninterface ReqInit extends Omit\u003cRequestInit, 'body'\u003e {\n  url?: string\n  method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD' | 'PATCH'\n  meta?: Record\u003cstring, any\u003e\n  timeout?: number\n  responseType?: ResponseType\n  throwHttpError?: boolean\n  body?: BodyInit | Record\u003cstring, any\u003e\n  onDownloadProgress?: ProgressCallback\n}\n```\n\n\u003e **Note**\n\u003e That its 'headers' behave differently than 'Options.headers', which overrides the global headers.\n\n**ResInit**\n\nResInit extends from the [ResponseInit](https://developer.mozilla.org/en-US/docs/Web/API/Response/Response) type with some additional properties.\n\n```typescript\ninterface ResInit extends ResponseInit {\n  meta?: Record\u003cstring, any\u003e\n  body?: BodyInit | Record\u003cstring, any\u003e | null\n  timeout?: number\n  responseType?: ResponseType\n  throwHttpError?: boolean\n  onDownloadProgress?: ProgressCallback\n}\n```\n\n**Middleware**\n\nThe middleware must call next(req) to return a promise.\n\n```typescript\ntype Middleware = (next: Next) =\u003e (req: Req) =\u003e Promise\u003cRes\u003e\n```\n\n### Standing on the shoulders of giants\n\nSome of the inspiration for this project came from their.\n\n- [Axios](https://github.com/axios/axios): Promise based HTTP client for the browser and node.js.\n- [Ky](https://github.com/sindresorhus/ky): Tiny \u0026 elegant JavaScript HTTP client based on the browser Fetch API.\n- [Redux](https://github.com/reduxjs/redux): Predictable state container for JavaScript apps.\n- [Koa](https://github.com/koajs/koa): Next generation web framework for node.js.\n\n### License\n\nThis project is licensed under the MIT License - see the [LICENSE](https://github.com/molvqingtai/resreq/blob/master/LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmolvqingtai%2Fresreq","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmolvqingtai%2Fresreq","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmolvqingtai%2Fresreq/lists"}