{"id":22923886,"url":"https://github.com/husseyexplores/xfetch-hook","last_synced_at":"2026-03-07T00:33:12.277Z","repository":{"id":57401336,"uuid":"448331093","full_name":"husseyexplores/xfetch-hook","owner":"husseyexplores","description":"Fetch and XHR hooks/middlewares, just like a piece of 🍰","archived":false,"fork":false,"pushed_at":"2024-07-16T18:09:59.000Z","size":109,"stargazers_count":4,"open_issues_count":0,"forks_count":4,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-01T18:14:15.976Z","etag":null,"topics":["fetch","xhr","xmlhttprequest"],"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/husseyexplores.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2022-01-15T16:30:08.000Z","updated_at":"2025-05-14T17:03:40.000Z","dependencies_parsed_at":"2024-07-16T21:47:12.171Z","dependency_job_id":null,"html_url":"https://github.com/husseyexplores/xfetch-hook","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/husseyexplores/xfetch-hook","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/husseyexplores%2Fxfetch-hook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/husseyexplores%2Fxfetch-hook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/husseyexplores%2Fxfetch-hook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/husseyexplores%2Fxfetch-hook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/husseyexplores","download_url":"https://codeload.github.com/husseyexplores/xfetch-hook/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/husseyexplores%2Fxfetch-hook/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30204154,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-06T19:07:06.838Z","status":"ssl_error","status_checked_at":"2026-03-06T18:57:34.882Z","response_time":250,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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","xhr","xmlhttprequest"],"created_at":"2024-12-14T08:17:49.678Z","updated_at":"2026-03-07T00:33:12.255Z","avatar_url":"https://github.com/husseyexplores.png","language":"JavaScript","readme":"# Fetch/XHR Middleware\n\nExtremly simple way to:\n- Intercept a fetch/XHR request\n- Listen on a fetch/XHR request\n\n## Usage:\nCan be used with or without ES modules. Use only `fetch` or `XMLHttpRequest` or both at the same time.\nCheck all the available [CDN exports](https://unpkg.com/browse/xfetch-hook@latest/dist/):\n\nOr install it via npm:\n```\nnpm install xfetch-hook@latest\n```\n```javascript\nimport { fetchHook, xhrHook } from 'xfetch-hook'\n```\n\n**ES modules via CDN**\n```html\n\u003cscript type=\"module\"\u003e\n  // Import both, fetch and xhr\n  import * as xfetch from 'https://unpkg.com/browse/xfetch-hook@latest/dist/fetch-xhr.module.min.js'\n\n  const { fetchHook, xhrHook } = xfetch\n\n  // Or only import what's needed\n  import fetchHook from 'https://unpkg.com/browse/xfetch-hook@latest/dist/fetch.module.min.js'\n  import xhrHook from 'https://unpkg.com/browse/xfetch-hook@latest/dist/xhr.module.min.js'\n\n  // Initialize once\n  fetchHook()\n  xhrHook()\n\n  // Start using by registering your middleware functions! (See the middleware functions signature below)\n  fetch.onRequest(fetchMiddleware1)\n  fetch.onRequest(fetchMiddleware2)\n  XMLHttpRequest.onRequest(xhrMiddleware1)\n  XMLHttpRequest.onRequest(xhrMiddleware2)\n  // ... register any number of hooks\n\u003c/script\u003e\n```\n\n**NON-ESM/Global export via CDN**\n```html\n\u003c!-- Load the script --\u003e\n\u003cscript src=\"https://unpkg.com/browse/xfetch-hook@latest/dist/fetch-xhr.module.min.js\"\u003e\n\u003c/script\u003e\n\n\u003c!-- `xfetch` is now accessible --\u003e\n\u003cscript\u003e\n  // Initialize once\n  xfetch.fetchHook()\n  xfetch.xhrHook()\n\n  // Start using by registering your middleware functions!\n  fetch.onRequest(middleware1)\n  ...\n\u003c/script\u003e\n```\n\n### Fetch Middleware\nOnce the hook is initialized, `onRequest` function will be exposed on the interface.\nIt expects a middleware function which is called before any fetch request is made, giving you a chance to listen or intercept it.\n\n```js\n// Fetch middleware function signature\nasync function middleware({ request, url, headers }) {\n  // Return null/falsy if this request does not need to be hooked\n  return null\n\n\n  return {\n    // Optional - if specified, original request will be overriden - Must be an instance of `Request` class\n    request?: new Request(),\n\n    // Optional - if specified, actual network call will not be made (bypass mechanism) - Must be an instance of `Response` class\n    response?: new Response(),\n\n    // Optional - if specified, `listen` function will receive `parsedData` as second argument\n    // Required - if `transformResponse`, is specified\n    as?: 'json' | 'text' | 'blob' | 'arrayBuffer' | 'formData'\n\n    // Optional - Provide a listener function. It will be called with `response`, once the request is complete\n    // `parsedData` will be available if `as` is specified.\n    listen?: (response, parsedData?) =\u003e {},\n\n    // Once the network call is made, the parsed response data will be transformed using this transformer function\n    // and then passed to the original caller. Think of it as a hook to transform any data before it reaches to the caller.\n    // `listen` function will always receive the transformed response and transformed data\n    transformResponse?: (parsedData) =\u003e {\n      return modifyData(parsedData)\n    }\n  }\n}\n```\n\n**XMLHttpRequest Middleware**\n\n```js\n// XHR middleware function signature\nasync function middleware({ method, url, body, headers }) {\n\n  // Override any of the paramer\n  return {\n    // Optional - override the method of xhr. (GET, POST, PUT, etc)\n    method?: 'String',\n\n    // Optional - override the xhr URL. Can be string or instance of `new URL()` class\n    url?: 'String' | new URL()\n\n    // Optional - update the body of the request\n    body,\n\n    // Optional - update the headers of the request - Must be an instance of `new Headers()` class\n    headers,\n\n    // Optional - Provide a listener function. It will be called with `response` and `xhr`, once the request is complete\n    // Note: `data` refers to `xhr.response`, (not to be confused with `new Response()` constructor)\n    listen?: (data, xhr) =\u003e {\n\n    },\n\n    // Once the network call is made, the response data will be transformed using this transformer function,\n    // and then passed to the original caller. Think of it as a hook to transform any data before it reaches to the caller.\n    // `listen` function will always receive the transformed data\n    transformResponse?: (data) =\u003e {\n      return modifyData(data)\n    }\n  }\n}\n```\n\nHooks/middlewares are called in the order they're registered. If any middleware modifies the data\n(`request`, `response`, `as`, `method`, `url`, `body`, `transformResponse`), the next middleware will receive the modified data\n\n### Working example\nShopify provides the following endpoings for cart:\n- GET `/cart.js` or `/cart.json`\n- POST `/cart/update.js` and `/cart/change.js`\n\nThese endpoints return cart data in JSON format.\nIn this example, we want to hide particular items in the cart.\n\n```html\n\u003cscript type=\"module\"\u003e\n  import fetchHook from 'https://unpkg.com/browse/xfetch-hook@latest/dist/fetch.module.min.js'\n\n  // Initialize once\n  fetchHook()\n\n\n  // Hook for GET: '/cart.json'\n  const unsubscribe1 = fetch.onRequest(async ({ url, request }) =\u003e {\n    // we need to listen on only GET requests\n    if (request.method  !== 'GET') return\n\n    const isCartRequest = url.pathname === '/cart.json' || url.pathname === '/cart.js'\n\n    // If it's not a cart request, don't do anything\n    if (!isCartRequest) return\n\n    return {\n      as: 'json',\n\n      // `cartJson` has `items` array. We will filter out all the items that have 'HIDDEN' product_type\n      // so that original caller will receive the modified data\n      transformResponse: cartJson =\u003e {\n        cartJson.items = cartJson.items.filter(item =\u003e item.product_type === 'HIDDEN')\n        return cartJson\n      },\n    }\n  })\n\n  // Hook for /cart/change.js and /cart/update.js\n  const unsubscribe2 = fetch.onRequest(async ({ url, request }) =\u003e {\n    const isCartChangeOrUpdateRequest = /\\/cart\\/(change|update).js(on)?/.test(url.pathname)\n    if (!isCartChangeOrUpdateRequest) return\n\n    return {\n      as: 'json',\n\n      // `cartJson` has `items` array. We will filter out all the items that have 'HIDDEN' product_type\n      // so that original caller will receive the modified data\n      transformResponse: cartJson =\u003e {\n        cartJson.items = cartJson.items.filter(item =\u003e item.product_type === 'HIDDEN')\n        return cartJson\n      },\n\n      // Since this is a POST request, it means the cart has been updated\n      // We can listen for the latest data, and react to it\n      listen: (response, cartJson) =\u003e {\n        // `cartJson` is the trasnfromed cart object\n        console.log('Cart has been updated. Time to update our UI', cartJson)\n\n        // Invoke your logic\n        // rerenderCart(cartJson)\n      }\n    }\n  })\n\u003c/script\u003e\n```\n\nEach `fetch.onRequest` middleware registration returns an `unsubscribe` function. Hint hint, this `unsubscribe` function's job is to remove the registered middleware.","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhusseyexplores%2Fxfetch-hook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhusseyexplores%2Fxfetch-hook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhusseyexplores%2Fxfetch-hook/lists"}