{"id":19478869,"url":"https://github.com/xan105/node-request","last_synced_at":"2026-05-06T09:42:52.860Z","repository":{"id":37176006,"uuid":"202791814","full_name":"xan105/node-request","owner":"xan105","description":"HTTP request library based around Node.js' HTTP(S) API interfaces","archived":false,"fork":false,"pushed_at":"2023-05-12T01:37:22.000Z","size":314,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-08T11:46:27.170Z","etag":null,"topics":["client","download","http","https","json","nodejs","progress","promise","request","torrent","url","xml"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/xan105.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null},"funding":{"patreon":"xan105","custom":"https://www.paypal.me/xan105"}},"created_at":"2019-08-16T20:00:55.000Z","updated_at":"2022-04-23T06:50:52.000Z","dependencies_parsed_at":"2022-08-08T19:16:33.245Z","dependency_job_id":null,"html_url":"https://github.com/xan105/node-request","commit_stats":{"total_commits":78,"total_committers":1,"mean_commits":78.0,"dds":0.0,"last_synced_commit":"e7132c08a21a5c24f20f7f751a081e2338cf15ce"},"previous_names":["xan105/node-request-zero"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xan105%2Fnode-request","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xan105%2Fnode-request/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xan105%2Fnode-request/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xan105%2Fnode-request/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xan105","download_url":"https://codeload.github.com/xan105/node-request/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240709753,"owners_count":19845039,"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":["client","download","http","https","json","nodejs","progress","promise","request","torrent","url","xml"],"created_at":"2024-11-10T19:51:49.791Z","updated_at":"2026-05-06T09:42:52.832Z","avatar_url":"https://github.com/xan105.png","language":"JavaScript","funding_links":["https://patreon.com/xan105","https://www.paypal.me/xan105"],"categories":[],"sub_categories":[],"readme":"About\n=====\n\nHTTP request library based around Node.js' HTTP(S) API interfaces:\n\n- http/https\n- ~~http2~~¹\n- ~~undici/fetch (_included in Node.js 18_)¹~~\n\n¹ Work in progress\n\nProvides common features such as retry on error, following redirects, progress when downloading file, ...\u003cbr /\u003e\n\nThis library isn't intented to compete nor replace the well known libraries such as got, axios, node-fetch, ...\nThis is merely educational and for informational purposes in order to learn how HTTP requests work under the hood.\n\nThis was originally created as [request-zero](https://www.npmjs.com/package/request-zero) at a time were the module `request` was the main choice and I didn't quite like it.\nIt had a ton of dependencies, didn't use promises and I needed something very simple.\n\nExample\n=======\n\nSimplest call\n\n```js\nimport { request } from \"@xan105/request\";\nconst res = await request(\"https://www.google.com\");\nconsole.log(res.body);\n```\n\nJSON\n\n```js\nimport { getJSON } from \"@xan105/request\";\n\nconst json = await getJSON(\"https://jsonplaceholder.typicode.com/todos/1\");\nconsole.log(json); \n/*Output:\n{ userId: 1, id: 1, title: 'delectus aut autem', completed: false }\n*/\n\n//Github API\nconst json = await getJSON(\"https://api.github.com/repos/user/repo/releases/latest\",{\n  headers: {\"Accept\" : \"application/vnd.github.v3+json\"}\n});\nconsole.log(json);\n/*Output:\n{ url: '...', tag_name: '0.0.0', target_commitish: 'master', ... }\n*/\n```\n\nDownload file(s)\n\n```js\nimport { download, downloadAll } from \"@xan105/request\";\n\n//Callback example to output progress in the console\nfunction printProgress(percent, speed, file){\n  process.stdout.clearLine();\n  process.stdout.cursorTo(0);\n  process.stdout.write(`${percent}% @ ${speed} kb/s [${file}]`);\n}\n\n//Simple download to disk (pipe to stream)\nawait download(\n  \"http://ipv4.download.thinkbroadband.com/1GB.zip\", \n  \"D:/Downloads\", \n  printProgress\n);\n\n//Download from github ... aws redirection ... content disposition ... but custom filename\nconst res = await download(\n  \"https://github.com/user/repo/releases/download/0.0.0/Setup.exe\",\n  \"D:/Downloads/\", \n  { filename: \"supersetup.exe\" }, \n  printProgress\n);\nconsole.log(res); \n/*Output:\n{ status: 200, message: 'OK', headers: {...}, path: 'D:\\\\Downloads\\\\supersetup.exe' }\n*/\n\n//Download a list of files one by one\nawait request.download.all([\n  \"http://ipv4.download.thinkbroadband.com/5MB.zip\",\n  \"http://ipv4.download.thinkbroadband.com/10MB.zip\",\n  \"http://ipv4.download.thinkbroadband.com/20MB.zip\",\n  \"http://ipv4.download.thinkbroadband.com/50MB.zip\"],\n  \"D:\\\\Downloads\", printProgress);\n```\n\nDownload a torrent\n\n```js\nimport { download } from \"@xan105/request/torrent\";\ndownload(\"https://webtorrent.io/torrents/sintel.torrent\", \"D:\\\\Downloads\");\n```\n\nMisc\n\n```js\nimport * as h1 from \"@xan105/request\";\n\n//Head request\nconst res = await h1.head(`http://ipv4.download.thinkbroadband.com/1GB.zip`);\nconsole.log(res);\n/*Output:\n{ status: 200, message: 'OK', headers: {...} }\n*/\n\n//Manually specify retry on error and redirection to follow\nawait request(\"https://steamdb.info/app/220/\", { maxRetry: 2, maxRedirect: 2 });\n\n//Upload a single file multipart/form-data\nconst res = await h1.upload(\n  \"http://127.0.0.1/upload/test/\",\n  \"Hello world\", \n  {name: \"file\", filename: \"hello world.txt\"}\n);\nconsole.log(res);\n/*Output:\n{ status: 200, message: 'OK', headers: {...}, body: 'ok' }\n*/\n```\n\nInstallation\n============\n\n```\nnpm install @xan105/request\n```\n\n## Optional packages\n\n- [webtorrent](https://www.npmjs.com/package/webtorrent)\u003cbr /\u003e\n  Downloading torrent\u003cbr /\u003e\n```\nnpm i webtorrent\n```\n\n- [xml2js](https://www.npmjs.com/package/xml2js)\u003cbr /\u003e\n  XML parser\u003cbr /\u003e\n```\nnpm i xml2js\n```\n\nAPI\n===\n\n⚠️ This module is only available as an ECMAScript module (ESM) starting with version 1.0.0.\u003cbr /\u003e\nPrevious version(s) are CommonJS (CJS) with an ESM wrapper.\n\n💡 The underlying API used is determined by which namespace you import.\u003cbr /\u003e\nBy default this is the http/https (h1) API.\u003cbr /\u003e\nTorrent related are under the `torrent` namespace.\n\n```js\n//Default\nimport * as h1 from '@xan105/request';\n\n//http/https (h1)\nimport * as h1 from '@xan105/request/h1';\n\n//http2 (h2)¹\nimport * as h2 from '@xan105/request/h2';\n\n//Fetch¹\nimport * as fetch from '@xan105/request/fetch';\n\n//Torrent\nimport * as torrent from \"@xan105/request/torrent\";\n```\n\n¹ Work in progress (unavailable at the moment)\n\n## Named export\n\n### `request(href: string, payload?: any, option?: object): Promise\u003cobject\u003e`\n\nThis is the core request function every other functions are helper based on this one (_except download, downloadAll and torrent_).\n\nThe response object tries to be similar whether the request failed or succeeded.\n\n```ts\n{\n  code: string, //HTTP or Node error code\n  message: string, //HTTP or Node error message (if any)\n  trace: string[], //URL(s) of the request (redirection)\n  domain: string, //url domain\n  sent: object, //Header sent\n  address?: string, //IP address\n  family?: string, //IPv4 or IPv6\n  protocol?: string, //HTTP protocol (h1, h2, ...)\n  security?: string, //TLS (HTTPS)\n  port: number, //Network port\n  headers?: object, //Response header\n  body?: string //Response body\n}\n```\n\n💡 In a dual stack network, IPv4 isn't prefered over IPv6 unlike Node's default behavior (_Node \u003c 17_ ).\n\n💡 When making a `HEAD` request: \n\n- The promise always resolves no matter the HTTP response code.\n- **Doesn't** follow redirection **by design**.\u003cbr/\u003eIf you need to follow the redirection you can use the headers `location` from the response and make a new `HEAD` request.\n\n#### ⚙️ Options\n\n| option      | type        | default                            | description                                                                        |\n| ----------- | ----------- | ---------------------------------- | ---------------------------------------------------------------------------------- |\n| method      | string      | GET                                | HTTP method: get, post, head, etc                                                  |\n| encoding    | string      | utf8                               | Response encoding                                                                  |\n| timeout     | number      | 3000 (ms)                          | Time before aborting request                                                       |\n| maxRedirect | number      | 3                                  | How many redirections to follow before aborting.\u003cbr/\u003eUse 0 to not follow redirects |\n| maxRetry    | number      | 0                                  | How many retries on error before aborting.\u003cbr/\u003eUse 0 to not retry at all           |\n| retryDelay  | number      | 200 (ms)                           | How long to wait before a retry.\u003cbr/\u003eUse 0 to instantly retry                      |\n| headers     | object         | -\u003e Chrome UA and UA Hint if https  | Headers of your request                                                            |\n| signal      | AbortSignal | none                               | Abort signal                                                                       |\n\n### `get(url: string, option?: object): Promise\u003cobject\u003e`\nForce the `GET` method. Since `request()` default to 'GET' you could just use `request()` directly. This is here for completeness.\n\n### `head(url: string, option?: object): Promise\u003cobject\u003e`\nForce the `HEAD` method.\n\n### `getJSON(url: string, option?: object): Promise\u003cobject\u003e`\nParse the response body as a JSON string and return the result.\u003cbr/\u003e\nForce method to `GET` and the header `Accept` to `\"application/json\"`.\n\n- alias: `getJson()`\n\n### `postJSON(url: string, obj: object, option?: object): Promise\u003cobject\u003e`\n\nSend given object payload as a JSON encoded string.\u003cbr/\u003e\nParse the response body as a JSON string and return the result.\u003cbr/\u003e\nForce method to `POST` and the headers `Accept` and `Content-Type` to `\"application/json\"`.\n\n### `getXML(url: string, option?: object): Promise\u003cobject\u003e`\n\n⚠️ Requires the [xml2js](https://www.npmjs.com/package/xml2js) module.\n\nParse the response body as a XML string and return the result.\u003cbr/\u003e\nForce method to `GET` and the header `Accept` to `\"application/xml\"`.\n\n- alias: `getXml()`\n\n### `post(url: string, payload: unknown, option?: object): Promise\u003cobject\u003e`\nForce method to `POST` and write/push given payload.\u003cbr/\u003e\nNB: On HTTP 301, 302, 303 redirection the method will be [changed to GET](https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections)\n\n### `upload(url: string, payload: unknown, option?: object): Promise\u003cobject\u003e`\nForce method to `POST` and write/push a multipart/form-data payload.\u003cbr/\u003e\nYou can use option `{fieldname: string, filename: string}` to specify the form field name and the file name.\u003cbr/\u003e\nIf you don't they will default respectively to 'file' and Date.now().\u003cbr/\u003e\n\n### `download(href: string, destDir: string, option?: object, callbackProgress?: fn): Promise\u003cobject\u003e`\n\nDownload file to `destDir`.\n\nThe response object is like `request()` minus `body` and with the addition of a `file` object:\n```ts\n{\n  name: string, //filename\n  path: string, //relative\n  fullPath: string //absolute\n}\n```\nThis is useful for promise chaining to example unzip an archive, etc.\n\n💡 Progress gives you the following stats: percent, speed, file.\u003cbr/\u003e\n`callbackProgress(percent: number, speed: number, file: string)`\n\n#### ⚙️ Options\n\n| option      | type        | default                            | description                                                                        |\n| ----------- | ----------- | ---------------------------------- | ---------------------------------------------------------------------------------- |\n| timeout     | number      | 3000 (ms)                          | Time before aborting request                                                       |\n| maxRedirect | number      | 3                                  | How many redirections to follow before aborting.\u003cbr/\u003eUse 0 to not follow redirects |\n| maxRetry    | number      | 3                                  | How many retries on error before aborting.\u003cbr/\u003eUse 0 to not retry at all           |\n| retryDelay  | number      | 1000 (ms)                          | How long to wait before a retry.\u003cbr/\u003eUse 0 to instantly retry                      |\n| headers     | object         | -\u003e Chrome UA and UA Hint if https  | Headers of your request                                                            |\n| signal      | AbortSignal | none                               | Abort signal                                                                       |\n| filename    | string      | null                               | Use this if you want to specify the filename (force rename)                        |\n| hash        | object         | null                               | Verify checksum of downloaded file²                                                |\n\n²Checksum option\n\n```ts\n{\n  algo: string, //A Node.js supported crypto algo. eg: \"sha1\"\n  sum: string //Checksum\n}\n```\nOn error or mismatch it will trigger error/retry.\n\n### `downloadAll(href: string[], destDir: string|string[], option?: object, callbackProgress?: fn): Promise\u003cobject\u003e`\n\nDownload all the files in the list one-by-one to destDir.\n\nIf `destDir` is an array, files[i] will be written to destDir[i] in a 1:1 relation.\u003cbr/\u003e\nIn the same fashion you can force the filename of the files with option `{filename: [..,..,..]}`.\u003cbr/\u003e\nAnd again same thing for checksum: `{hash: [{algo: ..., sum: ...},..,..]}`.\u003cbr/\u003e\n\nReturns an array of `download()` response object.\n\n## Torrent\n\n### `download(torrent: string, dest: string, option?: object, callbackProgress?: fn): Promise\u003cobject\u003e`\n\n⚠️ Requires the [webtorrent](https://www.npmjs.com/package/webtorrent) module.\n\nDownload files from a torrent url, torrent file, torrent magnet to `destDir`.\u003cbr/\u003e\n\n💡 Progress gives you the following stats: percent, speed.\u003cbr/\u003e\n`callbackProgress(percent: number, speed: number)`\n\n💡 Torrent can be resumed.\u003cbr/\u003e\n\nReturns an objectect with torrent download location, torrent name, and for every files of the torrent its name, relative path and path.\u003cbr/\u003e  \n\n```ts\n{\n  path: string, //absolute\n  name: string, //torrent name\n  file: [\n    {\n      name: string, //filename\n      path: string, //relative\n      fullPath: string //absolute\n    }\n  ]\n}\n```\n\n\n\n#### ⚙️ Options\n\n| option        | type      | default      | description                                |\n| ------------- | ----------| ------------ | ------------------------------------------ |\n| timeout       | number    | 10 (sec)     | Time to wait for peers before aborting     |\n| exclusion     | string[]  | none         | Exclude files inside the torrent           |\n| downloadLimit | number    | -1 (none)    | Download speed limit                       |\n| uploadLimit   | number    | 100 (kb/s)   | Upload speed limit                         |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxan105%2Fnode-request","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxan105%2Fnode-request","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxan105%2Fnode-request/lists"}