{"id":16871184,"url":"https://github.com/wilddima/node-http-clients-comparison","last_synced_at":"2025-04-11T11:13:46.827Z","repository":{"id":136292282,"uuid":"87319028","full_name":"wilddima/node-http-clients-comparison","owner":"wilddima","description":"Comparison of some http clients for Node.js","archived":false,"fork":false,"pushed_at":"2017-04-06T07:11:43.000Z","size":6,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-25T07:36:14.813Z","etag":null,"topics":["axios","client","fetch","nodejs","request","superagent"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wilddima.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2017-04-05T14:27:37.000Z","updated_at":"2018-09-21T05:34:28.000Z","dependencies_parsed_at":null,"dependency_job_id":"96d29d84-038c-4302-9d8e-8410a2b7f243","html_url":"https://github.com/wilddima/node-http-clients-comparison","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wilddima%2Fnode-http-clients-comparison","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wilddima%2Fnode-http-clients-comparison/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wilddima%2Fnode-http-clients-comparison/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wilddima%2Fnode-http-clients-comparison/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wilddima","download_url":"https://codeload.github.com/wilddima/node-http-clients-comparison/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248381790,"owners_count":21094528,"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","client","fetch","nodejs","request","superagent"],"created_at":"2024-10-13T15:06:40.366Z","updated_at":"2025-04-11T11:13:46.803Z","avatar_url":"https://github.com/wilddima.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# HTTP Clients compared\n\n\u003ctable\u003e\n\u003ctr\u003e\n  \u003cth\u003e\u003c/th\u003e\n  \u003cth\u003eRequest\u003c/th\u003e\n  \u003cth\u003eAxios\u003c/th\u003e\n  \u003cth\u003eSuperAgent\u003c/th\u003e\n  \u003cth\u003eNode-Fetch\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003ctd\u003eNodeJS\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n \u003c/tr\u003e\n\u003ctr\u003e\n  \u003ctd\u003eBrowser\u003c/td\u003e\n  \u003ctd\u003e–\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003ctd\u003eAPI\u003c/td\u003e\n  \u003ctd\u003eCallback / Stream\u003c/td\u003e\n  \u003ctd\u003ePromise\u003c/td\u003e\n  \u003ctd\u003ePromise-compatible\u003c/td\u003e\n  \u003ctd\u003ePromise\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003ctd\u003eQuery params\u003c/td\u003e\n  \u003ctd\u003eurl / object\u003c/td\u003e\n  \u003ctd\u003eurl / object\u003c/td\u003e\n  \u003ctd\u003eurl / object\u003c/td\u003e\n  \u003ctd\u003eurl\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003ctd\u003eCustom HTTP verbs\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003ctd\u003eCustom HTTP headers\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003ctd\u003eDefault HTTP headers\u003c/td\u003e\n  \u003ctd\u003e\u003ccode\u003eConnection\u003c/code\u003e\u003cbr/\u003e\u003ccode\u003eHost\u003c/code\u003e\u003c/td\u003e\n  \u003ctd\u003e\u003ccode\u003eAccept\u003c/code\u003e\u003cbr/\u003e\u003ccode\u003eConnection\u003c/code\u003e\u003cbr/\u003e\u003ccode\u003eHost\u003c/code\u003e\u003cbr/\u003e\u003ccode\u003eUser-Agent\u003c/code\u003e\u003c/td\u003e\n  \u003ctd\u003e\u003ccode\u003eAccept-Encoding\u003c/code\u003e\u003cbr/\u003e\n     \u003ccode\u003eConnection\u003c/code\u003e\u003cbr/\u003e\n     \u003ccode\u003eHost\u003c/code\u003e\u003cbr/\u003e\n     \u003ccode\u003eUser-Agent\u003c/code\u003e\u003c/td\u003e\n  \u003ctd\u003e\n    \u003ccode\u003eAccept\u003c/code\u003e\u003cbr/\u003e\n    \u003ccode\u003eAccept-Encoding\u003c/code\u003e\u003cbr/\u003e\n    \u003ccode\u003eConnection\u003c/code\u003e\u003cbr/\u003e\n    \u003ccode\u003eHost\u003c/code\u003e\u003cbr/\u003e\n    \u003ccode\u003eUser-Agent\u003c/code\u003e\n  \u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003ctd\u003eHTTPS\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003ctd\u003eForms\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e-\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003ctd\u003eCookies\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e-\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e-\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003ctd\u003eAuto Redirect On\u003c/td\u003e\n  \u003ctd\u003e++\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003ctd\u003eAuto Redirect Off\u003c/td\u003e\n  \u003ctd\u003eTODO ?\u003c/td\u003e\n  \u003ctd\u003eTODO ?\u003c/td\u003e\n  \u003ctd\u003eTODO ?\u003c/td\u003e\n  \u003ctd\u003eTODO ?\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003ctd\u003eBasic auth (by default)\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e+\u003c/td\u003e\n  \u003ctd\u003e-\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n## NodeJS\n\nAll platforms are available as NPM packages.\n\n## Browser\n\n1. You can bundle Request but it's way too big (~2 Mib) for Browser (due to NodeJS Streams etc.).\n2. Node-Fetch just emulates native [fetch API](https://developer.mozilla.org/en/docs/Web/API/Fetch_API).\n\n## API\n\n### Request\n\nSupports callback and streaming APIs natively. There are external plugins for promise API.\u003cbr/\u003e\nOr just `new Promise(...)` ;)\n\nTODO:\n* 404 is an \"error\" or not?\n* 500 is an \"error\" or not?\n\n```js\nlet opts = {\n  url: \"https://httpbin.org/get\",\n  qs: { id: 30 },\n}\n\n// callback\nrequest.get(opts, (err, response, body) =\u003e {\n  if (err) {\n    console.log(\"err:\", err)\n  }\n  else {\n    console.log(\"code:\", response.statusCode) // : number\n    console.log(\"headers:\", response.headers) // : Object\n    console.log(\"body:\", body)                // : TODO auto parsed due to mimetype?!\n  }\n})\n\n// streaming\nrequest(opts).pipe(process.stdout)\n```\n\n### Axios\n\nTODO:\n* 404 is an \"error\" or not?\n* 500 is an \"error\" or not?\n\n```js\nlet opts = {\n  url: \"https://httpbin.org/get\",\n  params: { id: 30 },\n}\n\naxios.get(opts)\n  .then((res) =\u003e {\n    console.log(\"code:\", res.status)     // TODO type\n    console.log(\"headers:\", res.headers) // TODO type\n    console.log(\"body:\", res.data)       // TODO type\n  })\n  .catch((err) =\u003e {\n    console.log(err.status)\n  })\n```\n\n\n### SuperAgent\n\nTODO:\n* 404 is an \"error\" or not?\n* 500 is an \"error\" or not?\n\n```js\nlet url = \"https://httpbin.org/get\"\nlet opts = { id: 30 }\n\nsuperagent.get(url)\n  .query(opts)\n  .end((err, res) =\u003e {\n    if (err) {\n      console.log(\"err:\", err.status)\n      console.log(\"err:\", err.response.error)\n    } else {\n      console.log(res.statusCode)\n      console.log(res.headers)\n      console.log(res.body)\n    }\n})\n```\n\n### Node-Fetch\n\nTODO:\n* 404 is an \"error\" or not?\n* 500 is an \"error\" or not?\n\n```js\nlet url = \"https://httpbin.org/get?id=30\"\n\nfetch(url)\n  .then(res =\u003e {\n    console.log(res.status)\n    console.log(res.headers)\n    return(res)\n  })\n  .then(res =\u003e res.json())\n  .then(res =\u003e {\n    console.log(res)\n  }).catch(err =\u003e {\n    console.log(error)\n  })\n```\n\n## Custom HTTP verbs\n\nTODO demo\n\n## Custom HTTP headers\n\nTODO demo\n\n## Custom HTTP verbs\n\n### Request\n\n```js\nlet opts = {\n  method: \"move\",\n  url: \"https://httpbin.org/get\",\n  qs: { id: 30 }\n}\n\nrequest(opts, (error, response, body) =\u003e {\n //....\n})\n```\n\n### Axios\n\n```js\nlet opts = {\n  method: \"move\",\n  url: \"https://httpbin.org/get\",\n  params: { id: 30 }\n}\n\naxios(opts)\n  .then((res) =\u003e {\n    //...\n  }).catch((err) =\u003e {\n    //...\n  })\n```\n\n### SuperAgent\n\n```js\nlet method = \"move\"\nlet url = \"https://httpbin.org/get\"\nlet params = { id: 30 }\n\nsuperagent(method, url)\n  .query(params)\n  .end(function(err, res) {\n    //...\n})\n```\n\n### Node-Fetch\n\n```js\nlet opts = { method: \"move\" }\nlet url = \"https://httpbin.org/get?id=30\"\n\nfetch(url, opts)\n  .then(\n    //...\n  })\n```\n\n## Query params\n\nAll four libraries support passing query params in URL.\u003cbr/\u003e\nNode-Fetch does not support query-as-object passing.\n\n## Forms\n\n### Request\n\n```js\nrequest\n  .post(\"https://httpbin.org/post\", { form: { test: \"test\" } })\n  .pipe(process.stdout)\n```\n\n### Axios\n\nTo perform post request with `application/x-www-form-urlencoded` in Axios, we need to use `querystring` or `qs`\n\n```js\nconst querystring = require(\"querystring\")\n\naxios\n  .post(endPoints.post.url, querystring.stringify({form: {test: \"test\"}}))\n  .then((res) =\u003e {\n    response(res)\n  })\n  .catch((err) =\u003e {\n    error(err)\n  })\n```\n\n### SuperAgent\n\nBy default SuperAgent user `json`, and to use `application/x-www-form-urlencoded` we need to invoke `type()`, and pass \"form\" to it.\n\n```js\nsuperagent\n  .post(\"https://httpbin.org/post\")\n  .type(\"form\")\n  .send({ test: \"test\"})\n  .end((err, res) =\u003e {\n    //....\n})\n```\n\n### Node-Fetch\n\nTo do the same in Node-Fetch we need to set headers manually, or use external libraries\n\n```js\nfetch(endPoints.post.url, { method: \"post\",\n                            headers: {\"Content-Type\": \"application/x-www-form-urlencoded\"},\n                            body: \"test=test\" })\n  .then(\n    //....\n  )\n```\n## Auto Redirect On\n\nRequest adds `Referer` header like:\n\n```\nReferer: http://httpbin.org/redirect-to?url=http://httpbin.org/get\n```\n\n## Auto Redirect Off\n\n...\n\n### Axios, Superagent, Node-Fetch\n\nThere is no difference between normal get request, and redirected request.\n\n## Basic-auth\n\nRequest and Axios have got similar API for BasicAuth:\n\n### Request\n\n```js\nlet basicAuth = {\n  method: \"get\",\n  uri: \"https://httpbin.org/basic-auth/user/passwd\",\n  auth: {\n    user: \"user\",\n    pass: \"passwd\"\n  }\n}\n\nrequest(basicAuth, (error, response, body) =\u003e console.log(response.statusCode))\n```\n### Axios\n\n```js\nlet basicAuth = {\n    method: \"get\",\n    url: \"https://httpbin.org/basic-auth/user/passwd\",\n    auth: {\n      username: \"user\",\n      password: \"passwd\"\n    }\n  }\n\naxios(basicAuth).then(res =\u003e console.log(res.status))\n```\n\n### SuperAgent\n\n```js\nsuperagent.get(\"https://httpbin.org/basic-auth/user/passwd\")\n  .auth(\"user\", \"passwd\")\n  .end((err, res) =\u003e console.log(res.statusCode))\n```\n\n## Plugins\n\nAll these libraries have a sufficient set of plugins created by the community (for example, the implementation of the promise api for the Request). However, from this point of view, it is worth highlighting SuperAgent, which has a specialized interface for connecting plugins (https://github.com/visionmedia/superagent#plugins)\n\n## Conclusion\n\nFor these tests, I used [HTTPbin](https://httpbin.org/).\n\nIn the process of comparing their libraries, I came to the conclusion that they all have enough positive sides to use them.\n\n**Request** – despite the fact that it is not cross-platform, it undoubtedly has the most opportunities out of the box. Ability to use NodeJS streams looks attractive.\n\n**Axios** – as for me has the most understandable syntax and follows the idea of \"principle of least surprise\".\n\n**SuperAgent** – also has a fairly understandable api, but much more important is the idea of its extensibility through plugins.\n\n**Node-Fetch** – good old fetch api. A small number of dependencies and a familiar interface.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwilddima%2Fnode-http-clients-comparison","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwilddima%2Fnode-http-clients-comparison","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwilddima%2Fnode-http-clients-comparison/lists"}