{"id":22273019,"url":"https://github.com/rexerwang/requete","last_synced_at":"2025-08-25T08:07:24.360Z","repository":{"id":153356451,"uuid":"628879357","full_name":"rexerwang/requete","owner":"rexerwang","description":"🚀 A lightweight client-side HTTP request library based on the Fetch API and supports middleware.","archived":false,"fork":false,"pushed_at":"2024-12-02T02:38:15.000Z","size":1371,"stargazers_count":5,"open_issues_count":2,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-12-02T03:27:31.798Z","etag":null,"topics":["fetch","http","middleware","promise","request","typescript","xhr"],"latest_commit_sha":null,"homepage":"https://npm.im/requete","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/rexerwang.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":"2023-04-17T07:07:51.000Z","updated_at":"2024-12-02T02:36:48.000Z","dependencies_parsed_at":null,"dependency_job_id":"9559e262-f84d-43eb-ab72-6355909c7359","html_url":"https://github.com/rexerwang/requete","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rexerwang%2Frequete","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rexerwang%2Frequete/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rexerwang%2Frequete/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rexerwang%2Frequete/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rexerwang","download_url":"https://codeload.github.com/rexerwang/requete/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227668663,"owners_count":17801510,"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":["fetch","http","middleware","promise","request","typescript","xhr"],"created_at":"2024-12-03T13:09:21.426Z","updated_at":"2024-12-03T13:09:22.033Z","avatar_url":"https://github.com/rexerwang.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# requete\n\n\u003e `requete` is the French word for `request`\n\n[![npm version](https://img.shields.io/npm/v/requete.svg?style=flat)](https://npm.im/requete)\n[![install size](https://packagephobia.com/badge?p=requete)](https://packagephobia.com/result?p=requete)\n[![npm bundle size](https://img.shields.io/bundlephobia/min/requete?style=flat)](https://bundlephobia.com/package/requete)\n[![build status](https://github.com/rexerwang/requete/actions/workflows/ci.yml/badge.svg)](https://github.com/rexerwang/requete/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/rexerwang/requete/branch/main/graph/badge.svg?token=IL9AYNO98T)](https://codecov.io/gh/rexerwang/requete)\n\n**requete** is a lightweight client-side HTTP request library based on the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API), and supports middleware for processing requests and responses.\nIt provides APIs similar to `Axios`.\n\nIn addition, **requete** also includes an `XMLHttpRequest` adapter, which allows it to be used in older browsers that do not support `Fetch`, and provides polyfills to simplify import.\n\nAlso, `requete` supports usage in `Node.js`, using `fetch` API (`nodejs \u003e= 17.5.0`).\n\n## Features\n\n- Use `Fetch API` on modern browsers or Node.js\n- Use `XMLHttpRequest` on older browsers\n- Supports `middleware` for handling request and response\n- Supports the Promise API\n- Transform request and response data\n- Abort requests by [`TimeoutAbortController`](#timeoutabortcontroller)\n- Automatic transforms for JSON response data, and supports custom transformer\n- Automatic data object serialization to `multipart/form-data` and `x-www-form-urlencoded` body encodings\n\n## Install\n\n### NPM\n\n```sh\npnpm add requete\n```\n\n```sh\nyarn add requete\n```\n\n```sh\nnpm i -S requete\n```\n\n### CDN\n\n```html\n\u003c!-- using jsdelivr --\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/requete/index.umd.min.js\"\u003e\u003c/script\u003e\n\u003c!-- or using unpkg --\u003e\n\u003cscript src=\"https://unpkg.com/requete/index.umd.min.js\"\u003e\u003c/script\u003e\n```\n\n## Usage\n\nFirst, you can import `requete` and use it directly.\n\n```ts\nimport requete from 'requete'\n\n// Make a GET request\nrequete.get('https://httpbin.org/get')\n\n// Make a POST request\nrequete.post('https://httpbin.org/post', { id: 1 })\n```\n\nYou can also create an instance and specify request configs by calling the `create()` function:\n\n```ts\nimport { create } from 'requete'\n\nconst requete = create({ baseURL: 'https://httpbin.org' })\n\n// Make a GET request\nrequete\n  .get\u003cIData\u003e('/post')\n  .then((r) =\u003e r.data)\n  .catch((error) =\u003e {\n    console.log(error) // error as `RequestError`\n  })\n```\n\n**For Nodejs (commonjs):**\n\n```js\nconst requete = require('requete')\n\n// use default instance\nrequete.get('https://httpbin.org/post')\n\n// create new instance\nconst http = requete.create({ baseURL: 'https://httpbin.org' })\n// Make a POST request\nhttp.post('/post', { id: 1 })\n```\n\n**For browsers:**\n\n- UMD\n\n```html\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/requete\"\u003e\u003c/script\u003e\n\n\u003cscript\u003e\n  // use default instance\n  requete.get('https://httpbin.org/get')\n\n  // create new instance\n  const http = requete.create()\n\u003c/script\u003e\n```\n\n- ESM: by `index.browser.mjs`\n\n```html\n\u003cscript type=\"module\"\u003e\n  import requete from 'https://cdn.jsdelivr.net/npm/requete/index.browser.mjs'\n\n  requete.get('https://httpbin.org/get')\n\u003c/script\u003e\n```\n\n- ESM: by `importmap`\n\n```html\n\u003cscript type=\"importmap\"\u003e\n  {\n    \"imports\": {\n      \"requete\": \"https://cdn.jsdelivr.net/npm/requete/index.mjs\",\n      \"requete/adapter\": \"https://cdn.jsdelivr.net/npm/requete/adapter.mjs\",\n      \"requete/shared\": \"https://cdn.jsdelivr.net/npm/requete/shared.mjs\"\n    }\n  }\n\u003c/script\u003e\n\u003cscript type=\"module\"\u003e\n  import { create } from 'requete'\n\n  const requete = create({ baseURL: 'https://httpbin.org' })\n\n  requete.get('/get')\n\u003c/script\u003e\n```\n\n### Request Methods\n\nThe following aliases are provided for convenience:\n\n```ts\nrequete.request\u003cD = any\u003e(config: IRequest): Promise\u003cIContext\u003cD\u003e\u003e\nrequete.get\u003cD = any\u003e(url: string, config?: IRequest): Promise\u003cIContext\u003cD\u003e\u003e\nrequete.delete\u003cD = any\u003e(url: string, config?: IRequest): Promise\u003cIContext\u003cD\u003e\u003e\nrequete.head\u003cD = any\u003e(url: string, config?: IRequest): Promise\u003cIContext\u003cD\u003e\u003e\nrequete.options\u003cD = any\u003e(url: string, config?: IRequest): Promise\u003cIContext\u003cD\u003e\u003e\nrequete.post\u003cD = any\u003e(url: string, data?: RequestBody, config?: IRequest): Promise\u003cIContext\u003cD\u003e\u003e\nrequete.put\u003cD = any\u003e(url: string, data?: RequestBody, config?: IRequest): Promise\u003cIContext\u003cD\u003e\u003e\nrequete.patch\u003cD = any\u003e(url: string, data?: RequestBody, config?: IRequest): Promise\u003cIContext\u003cD\u003e\u003e\n```\n\nExample:\n\n```ts\nimport { create } from 'requete'\n\nconst requete = create({ baseURL: 'https://your-api.com/api' })\n\n// Make a GET request for user profile with ID\nrequete\n  .get\u003cIUser\u003e('/users/profile?id=123')\n  .then((r) =\u003e r.data)\n  .catch(console.error)\n  .finally(() =\u003e {\n    // always executed\n  })\n\n// or use `config.params` to set url search params\nrequete.get\u003cIUser\u003e('/users/profile', { params: { id: '123' } })\nrequete.get\u003cIUser\u003e('/users/profile', { params: 'id=123' })\n\n// Make a POST request for update user profile\nrequete.post('/users/profile', { id: '123', name: 'Jay Chou' })\n// or use `requete.request`\nrequete.request({\n  url: '/users/profile',\n  method: 'POST'\n  data: { id: '123', name: 'Jay Chou' },\n})\n\nrequete.delete('/users/profile/123')\n\nrequete.put('/users/profile/123', { name: 'Jay Chou' })\n```\n\n### Use Middleware\n\n`requete.use` for add a middleware function to requete. It returns this, so is chainable.\n\n- The calling order of middleware should follow the **Onion Model**.\n  like [`Koa middleware`](https://github.com/koajs/koa/blob/master/docs/guide.md#writing-middleware).\n- `ctx` is the requete context object, type `IContext`. more information in [here](#response-typings).\n- `next()` must be called asynchronously in middleware\n- **Throwing an exception in middleware will break the middleware execution chain.**\n- Even if `ctx.ok === false`, there`s no error will be thrown in middleware.\n\n```ts\nrequete\n  .use(async (ctx, next) =\u003e {\n    const token = getToken()\n    // throw a `RequestError` if unauthorize\n    if (!token) ctx.throw('unauthorize')\n    // set Authorization header\n    else ctx.set('Authorization', token)\n\n    // wait for request responding\n    await next()\n\n    // when unauthorized, re-authenticate.\n    if (ctx.status === 401) reauthenticate()\n  })\n  .use((ctx, next) =\u003e\n    next().then(() =\u003e {\n      // throw a `RequestError` and break the subsequent execution\n      if (!ctx.data.some_err_code === '\u003cerror_code\u003e') {\n        ctx.throw('Server Error')\n      }\n    })\n  )\n```\n\n## Request Config\n\n### Config for create instance.\n\n\u003e `create(config?: RequestConfig)`\n\n```ts\ninterface RequestConfig {\n  baseURL?: string\n  /** request timeout (ms) */\n  timeout?: number\n  /** response body type */\n  responseType?: 'json' | 'formData' | 'text' | 'blob' | 'arrayBuffer'\n  /** A string indicating how the request will interact with the browser's cache to set request's cache. */\n  cache?: RequestCache\n  /** A string indicating whether credentials will be sent with the request always, never, or only when sent to a same-origin URL. Sets request's credentials. */\n  credentials?: RequestCredentials\n  /** A Headers object, an object literal, or an array of two-item arrays to set request's headers. */\n  headers?: HeadersInit\n  /** A cryptographic hash of the resource to be fetched by request. Sets request's integrity. */\n  integrity?: string\n  /** A boolean to set request's keepalive. */\n  keepalive?: boolean\n  /** A string to indicate whether the request will use CORS, or will be restricted to same-origin URLs. Sets request's mode. */\n  mode?: RequestMode\n  /** A string indicating whether request follows redirects, results in an error upon encountering a redirect, or returns the redirect (in an opaque fashion). Sets request's redirect. */\n  redirect?: RequestRedirect\n  /** A string whose value is a same-origin URL, \"about:client\", or the empty string, to set request's referrer. */\n  referrer?: string\n  /** A referrer policy to set request's referrerPolicy. */\n  referrerPolicy?: ReferrerPolicy\n  /** enable logger or set logger level # */\n  verbose?: boolean | number\n  /**\n   * parse json function\n   * (for transform response)\n   * @default JSON.parse\n   */\n  toJSON?(body: string): any\n}\n```\n\n`config.verbose` is used to toggle the logger output.\n\n- set `true` or `2`: output `info` and `error` level\n- set `1`: output `error` level\n- set `false` or `0` or not set: no output\n\n### Config for request methods.\n\n\u003e `requete.request(config?: IRequest)`\n\n```ts\ninterface IRequest extends RequestConfig {\n  url: string\n  /**\n   * A string to set request's method.\n   * @default GET\n   */\n  method?: Method\n  /** A string or object to set querystring of url */\n  params?: string | Record\u003cstring, any\u003e\n  /** request`s body */\n  data?: RequestBody\n  /**\n   * A TimeoutAbortController to set request's signal.\n   * @default new TimeoutAbortController(timeout)\n   */\n  abort?: TimeoutAbortController | null\n  /** specify request adapter */\n  adapter?: Adapter\n  /** flexible custom field */\n  custom?: any\n}\n```\n\n### Request Config Defaults\n\nYou can specify request config defaults globally, that will be applied to every request.\nAnd the `Requete.defaults` is defined [here](https://github.com/rexerwang/requete/blob/main/src/core/Requete.ts#L17).\n\n```ts\nimport { Requete } from 'requete'\n\nRequete.defaults.baseURL = 'https://your-api.com'\nRequete.defaults.timeout = 60000\nRequete.defaults.responseType = 'json'\nRequete.defaults.headers = { 'X-Request-Id': 'requete' }\n```\n\n## Response Typings\n\nThe response for a request is a context object, specifically of type `IContext`, which contains the following information.\n\n```ts\ninterface IResponse\u003cData = any\u003e {\n  headers: Headers\n  ok: boolean\n  redirected: boolean\n  status: number\n  statusText: string\n  type: ResponseType\n  url: string\n  data: Data\n  /** response text when responseType is `json` or `text` */\n  responseText?: string\n}\n\ninterface IContext\u003cData = any\u003e extends IResponse\u003cData\u003e {\n  /**\n   * request config.\n   * and empty `Headers` object as default\n   */\n  request: IRequest \u0026 { headers: Headers }\n\n  /**\n   * set request headers\n   * *And header names are matched by case-insensitive byte sequence.*\n   * @throws {RequestError}\n   */\n  set(headerOrName: HeadersInit | string, value?: string | null): this\n\n  /**\n   * Add extra params to `request.url`.\n   * If there are duplicate keys, then the original key-values will be removed.\n   */\n  params(params: RequestQuery): this\n\n  /**\n   * get `ctx.request.abort`,\n   * and **create one if not exist**\n   * @throws {RequestError}\n   */\n  abort(): TimeoutAbortController\n\n  /** throw {@link RequestError} */\n  throw(e: string | Error): void\n\n  /**\n   * Assign to current context\n   */\n  assign(context: Partial\u003cIContext\u003e): void\n\n  /**\n   * Replay current request\n   * And assign new context to current, with replay`s response\n   */\n  replay(): Promise\u003cvoid\u003e\n}\n```\n\nIn middleware, the first argument is `ctx` of type `IContext`. You can call methods such as `ctx.set`, `ctx.throw`, `ctx.abort` before sending the request (i.e., before the `await next()` statement).\nOtherwise, if these methods are called in other cases, a `RequestError` will be thrown.\n\n### ctx.set(key, value)\n\nset one header of request.\n_And header names are matched by case-insensitive byte sequence._\n\n### ctx.set(object)\n\nset multi headers of request.\n\n### ctx.params(params)\n\nAdd extra `params` to `request.url`.  \n**If there are duplicate keys, then the original key-values will be removed.**\n\n### ctx.abort()\n\nReturn the current `config.abort`, and **create one if not exist**\n\n### ctx.throw(error)\n\nIt is used to throw a [`RequestError`](#requesterror)\n\n### ctx.assign(context)\n\nIt is used to assign new context object to current. (`Object.assign`)\n\n### ctx.replay()\n\nIt is used to replay the request in middleware or other case.  \nAfter respond, will assign new context to current, with replay\\`s response,\nAnd will add counts of replay in `ctx.request.custom.replay`.\n\nExamples:\n\n```ts\nconst Auth = {\n  get token() {\n    return localStorage.getItem('token')\n  },\n  set token(value) {\n    return localStorage.setItem('token', value)\n  },\n  authenticate: () =\u003e\n    requete.post('/authenticate').then((r) =\u003e {\n      Auth.token = r.data.token\n    }),\n}\n\nrequete.use(async (ctx, next) =\u003e {\n  ctx.set('Authorization', `Bearer ${Auth.token}`)\n\n  await next()\n\n  // when unauthorized, re-authenticate\n  // Maybe causes dead loop if always respond 401\n  if (ctx.status === 401) {\n    await Auth.authenticate()\n    // replay request after re-authenticated.\n    await ctx.replay()\n  }\n})\n```\n\n## RequestError\n\n`RequestError` inherits from `Error`, contains the request context information.\n\nIt should be noted that all exceptions in requete are `RequestError`.\n\n```ts\nclass RequestError extends Error {\n  name = 'RequestError'\n  ctx: IContext\n\n  constructor(errMsg: string | Error, ctx: IContext)\n}\n```\n\n### Example\n\nIf needed, you can import `RequestError` it from `requete`\n\n```ts\nimport { RequestError } from 'requete'\n\nthrow new RequestError('\u003cerror message\u003e', ctx)\nthrow new RequestError(new Error('\u003cerror message\u003e'), ctx)\n```\n\nThrow `RequestError` in requete middleware\n\n```ts\n// in requete middleware\nctx.throw('\u003cerror message\u003e')\n```\n\nCaught `RequeteError` in request\n\n```ts\n// promise.catch\nrequete.post('/api').catch((e) =\u003e {\n  console.log(e.name) // \"RequestError\"\n  console.log(e.ctx.status) // response status\n  console.log(e.ctx.headers) // response header\n})\n\n// try-catch\ntry {\n  await requete.post('/api')\n} catch (e) {\n  console.log(e.name) // \"RequestError\"\n  console.log(e.ctx.status) // response status\n  console.log(e.ctx.headers) // response header\n}\n```\n\n## TimeoutAbortController\n\nit is used to auto-abort requests when timeout, and you can also call `abort()` to terminate them at any time. It is implemented based on [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).\n\nIn the requete configuration, you can add the `TimeoutAbortController` through the `abort` field.  \nIt should be noted that if you set the `timeout` field in config and unset the `abort` field, `requete` will add the `TimeoutAbortController` by default to achieve timeout termination.\n\nIf the target browser does not support `AbortController`, please [add a polyfill](#polyfills) before using it.\n\n```ts\nclass TimeoutAbortController {\n  /** if not supported, it will throw error when `new` */\n  static readonly supported: boolean\n\n  /** timeout ms */\n  constructor(timeout: number)\n\n  get signal(): AbortSignal\n\n  abort(reason?: any): void\n\n  /** clear setTimeout */\n  clear(): void\n}\n```\n\n### Example\n\n```ts\nimport { TimeoutAbortController } from 'requete'\n\n/** By `abort` config */\nconst controller = new TimeoutAbortController(5000)\nrequete\n  .get('https://httpbin.org/delay/10', { abort: controller })\n  .catch((e) =\u003e {\n    console.error(e) // \"canceled\"\n  })\ncontroller.abort('canceled') // you can abort request\n\n/** By `timeout` config */\nrequete.get('https://httpbin.org/delay/10', { timeout: 5000 })\n```\n\n## Request Adapter\n\nThere are two request adapters in requete: `FetchAdapter`, `XhrAdapter`.\n\n- **In Browser:** using `FetchAdapter` as default, and `XhrAdapter` is used as a fallback.\n- **In Node.js:** using `FetchAdapter`.\n\nOf course, you can also customize which adapter to use by declaring the `adapter` field in config.\nFor example, in browser environment, when obtaining download or upload progress events, you can choose to use the `XhrAdapter`. (like [Axios](https://github.com/axios/axios#request-config))\n\n```ts\nimport requete, { XhrAdapter } from 'requete'\n\nrequete.get('/download-or-upload', {\n  adapter: new XhrAdapter({ onDownloadProgress(e) {}, onUploadProgress(e) {} }),\n})\n```\n\nAdditionally, `requete` also supports custom adapters by inheriting the `abstract class Adapter` and implementing the `request` method.\n\n```ts\nabstract class Adapter {\n  abstract request(ctx: IContext): Promise\u003cIResponse\u003e\n}\n```\n\n### Example\n\n```ts\n// CustomAdapter.ts\n\nimport { Adapter } from 'requete/adapter'\n\nexport class CustomAdapter extends Adapter {\n  async request(ctx: IContext) {\n    // do request\n\n    return response\n  }\n}\n```\n\n## Polyfills\n\nIf needed, you can directly import `requete/polyfill`. It includes polyfills for `Headers` and `AbortController`.\n\n`requete/polyfill` will determine whether to add polyfills based on the user's browser.\n\n- Headers`s by [headers-polyfill](https://github.com/mswjs/headers-polyfill)\n- AbortController`s by [abortcontroller-polyfill](https://github.com/mo/abortcontroller-polyfill)\n\n**In ES Module:**\n\n```js\nimport 'requete/polyfill'\n```\n\n**In Browser:**\n\n```html\n\u003c!-- using jsdelivr --\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/requete/polyfill.umd.min.js\"\u003e\u003c/script\u003e\n\u003c!-- using unpkg --\u003e\n\u003cscript src=\"https://unpkg.com/requete/polyfill.umd.min.js\"\u003e\u003c/script\u003e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frexerwang%2Frequete","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frexerwang%2Frequete","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frexerwang%2Frequete/lists"}