{"id":22669562,"url":"https://github.com/benjamine/fetch-wrap","last_synced_at":"2025-07-29T06:33:38.812Z","repository":{"id":57234742,"uuid":"73534167","full_name":"benjamine/fetch-wrap","owner":"benjamine","description":"extend WHATWG fetch wrapping it with middlewares","archived":false,"fork":false,"pushed_at":"2023-02-27T19:27:45.000Z","size":428,"stargazers_count":23,"open_issues_count":11,"forks_count":8,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-16T03:46:54.689Z","etag":null,"topics":["fetch","fetch-api","http-client"],"latest_commit_sha":null,"homepage":null,"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/benjamine.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"MIT-LICENSE.txt","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":"2016-11-12T05:46:44.000Z","updated_at":"2023-08-30T04:11:30.000Z","dependencies_parsed_at":"2024-06-18T21:32:54.402Z","dependency_job_id":null,"html_url":"https://github.com/benjamine/fetch-wrap","commit_stats":{"total_commits":28,"total_committers":6,"mean_commits":4.666666666666667,"dds":0.25,"last_synced_commit":"822654dc4e42108872a980998d2b2eb6394654be"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/benjamine/fetch-wrap","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benjamine%2Ffetch-wrap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benjamine%2Ffetch-wrap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benjamine%2Ffetch-wrap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benjamine%2Ffetch-wrap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/benjamine","download_url":"https://codeload.github.com/benjamine/fetch-wrap/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benjamine%2Ffetch-wrap/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267639569,"owners_count":24119780,"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","status":"online","status_checked_at":"2025-07-29T02:00:12.549Z","response_time":2574,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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","fetch-api","http-client"],"created_at":"2024-12-09T15:33:59.325Z","updated_at":"2025-07-29T06:33:38.765Z","avatar_url":"https://github.com/benjamine.png","language":"JavaScript","readme":"fetch-wrap\n====\n[![Build Status](https://secure.travis-ci.org/benjamine/fetch-wrap.svg)](http://travis-ci.org/benjamine/fetch-wrap)\n[![Code Climate](https://codeclimate.com/github/benjamine/fetch-wrap/badges/gpa.svg)](https://codeclimate.com/github/benjamine/fetch-wrap)\n[![Test Coverage](https://codeclimate.com/github/benjamine/fetch-wrap/badges/coverage.svg)](https://codeclimate.com/github/benjamine/fetch-wrap)\n[![NPM version](https://badge.fury.io/js/fetch-wrap.svg)](http://badge.fury.io/js/fetch-wrap)\n[![NPM dependencies](https://david-dm.org/benjamine/fetch-wrap.svg)](https://david-dm.org/benjamine/fetch-wrap)\n\nextend [WHATWG fetch API](https://developer.mozilla.org/en/docs/Web/API/Fetch_API) with middleware\n\n- transparent, your extended fetch mantains fetch API `fetch(url, options)`\n- recursive, extend fetch, extend extended fetch, ...\n- use over any fetch implementation you like ([native fetch](http://caniuse.com/#search=fetch), [fetch-ponyfill](https://www.npmjs.com/package/fetch-ponyfill), [fetch-polyfill](https://www.npmjs.com/package/fetch-polyfill), etc.)\n- pick from built-in middleware and/or write yours\n- unit tested and benchmarked against plain fetch\n- isomorphic\n\nInstall\n-------\n``` sh\nnpm install fetch-wrap --save\n```\n\nUsage\n-----\n\n``` js\nconst fetchWrap = require('fetch-wrap');\n\n// you can use native fetch(), or the implementation you prefer\nlet fetch = require('fetch-ponyfill')();\n\n// extend fetch with a list of wrappers\nfetch = fetchWrap(fetch, [\n  function middleware1(url, options, innerFetch) {\n    // this middleware does nothing\n    return innerFetch(url, options);\n  },\n  middleware2,\n  middleware3,\n]);\n\n// use your extended fetch\nfetch('http://localhost:8080/file.json').then(result =\u003e console.log(result));\n```\n\nBuilt-in Middleware\n-------------------\n\nThere's some useful middleware in this package that you can optionally import\nsee [src/middleware.js](src/middleware.js) for details, here's a full example:\n\n\n``` js\nvar fetchWrap = require('fetch-wrap');\nvar middleware = require('fetch-wrap/middleware');\nvar fetch = fetchWrap(fetch, [\n  // support options.params, replace tokens in url and adds query string params\n  middleware.urlParams({\n    host: 'localhost'\n  }),\n  // apply options based on url (supports wildcards)\n  middleware.optionsByUrlPattern([\n    {\n      for: 'http://localhost*',\n      options: {\n        headers: {\n          Authorization: 'Token 1234'\n        },\n        timeouts: {\n          // will send log events at 2s and 5s with these levels\n          2: 'warn',\n          5: 'error' // 5sec timeout from localhost, error!\n        }\n      }\n    }\n  ]),\n  // automatically serialize body to JSON if needed\n  middleware.sendJson(),\n  // automatically parse JSON (revives Dates), optionally send Accept header\n  //   throws on http errors\n  middleware.receiveJson()\n  // logs events (start, success, fail, timeouts), defaults to console but supports custom .log handler\n  middleware.logger()\n]);\n\nfetch('http://{host}:8080/test.json', {\n  params: {\n    utm_source: 'nodejs'\n  }\n}).then(result =\u003e console.log(result));\n\n```\n\nWrite your own Middleware!\n-------------------\n\n``` js\nconst fetchWrap = require('fetchWrap');\nfetch = fetchWrap(fetch, [\n\n  function(url, options, fetch) {\n    // modify url or options\n    return fetch(url.replace(/^(http:)?/, 'https:'), options);\n  },\n\n  function(url, options, fetch) {\n    // add headers\n    return fetch(url, fetchWrap.merge({}, options, {\n      headers: {\n        Authorization: 'Token 123456'\n      }\n    });\n  }\n\n  function(url, options, fetch) {\n    // modify result\n    return fetch(url, options).then(function(response) {\n      if (!response.ok) {\n        throw new Error(result.status + ' ' + result.statusText);\n      }\n      if (/application\\/json/.test(result.headers.get('content-type'))) {\n        return response.json();\n      }\n      return response.text();\n    });\n  }\n\n  function(url, options, fetch) {\n    // catch errors\n    return fetch(url, options).catch(function(err) {\n      console.error(err);\n      throw err;\n    });\n  }\n\n]);\n\n// use your customized fetch!\n\nfetch('http://somedomain.com/news.json').then(function(news) {\n  // GET https://somedomain.com/news.json with Authorization header, and parsed to json\n  console.log(news.items);\n});\n```\n\nTesting\n-------\n\nFor unit testing, you can use the built-in `testing` middleware to mock or spy fetch calls.\n\n``` js\nvar fetchWrap = require('fetch-wrap');\nvar middleware = require('fetch-wrap/middleware');\nvar spyLog = [];\nvar fetch = fetchWrap(fetch, [\n  middleware.optionsByUrlPattern([\n    {\n      for: 'http://localhost*',\n      options: {\n        // mock every request to this url\n        mock: { name: 'john' }\n      }\n    }\n  ])\n  middleware.testing({\n    // optional spy function\n    spy(url, options) {\n      spyLog.push({ url: url, options: options })\n    }\n  })\n]);\n\n// it will fail if no `options.mock` is found, to prevent real requests during unit-testing\nfetch('http://localhost:8080').then(function(result) {\n  expect(spyLog[0].url).to.eql('http://localhost:8080');\n  expect(result).to.eql({ name: 'john' });\n})\n\n```\n\nFor details on built-in middleware check [src/middleware.js](src/middleware.js)\n\nBenchmark\n---------\n\n``` sh\nnode src/benchmark\n```\n\ncompares fetch (fetch-ponyfill, not extended), with extended fetch (fetch-ponyfill extended with some of the built-in middleware).\n\nTypically results show performance cost is neglectable, example:\n```\nfetch GET json x 435 ops/sec ±1.52% (80 runs sampled)\nextended fetch GET json x 438 ops/sec ±1.24% (81 runs sampled)\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbenjamine%2Ffetch-wrap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbenjamine%2Ffetch-wrap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbenjamine%2Ffetch-wrap/lists"}