fetch-intercept

Lightweight interceptor library that lets you hook into every fetch request and response, in the browser, Node, or a web worker.

Library
npm
v2.4.0
422stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
37/100Needs Attention
Development Activity0
Maintenance0
Community68
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
49/100Fair
Architecture60
Code Quality40
Innovation50
Learning Curve45

fetch-intercept monkey-patches the global fetch function so you can register request and response interceptors around every call it makes, without touching the call sites themselves. Inspired directly by AngularJS’s $http interceptor pattern, it exposes a single register() call that accepts request, requestError, response, and responseError hooks, and returns an unregister() function so the interception can be torn down cleanly.

The library ships separate entrypoints for Node (lib/node.js, patching global.fetch) and the browser or a web worker (lib/browser.js, patching window.fetch or self.fetch), selected automatically via the package’s main/browser fields, plus a hand-written TypeScript declaration file. It has no runtime dependencies of its own beyond an optional whatwg-fetch polyfill fallback, making it a thin, drop-in addition to any project that already uses fetch.

What You Get

  • A register() function that installs request, requestError, response, and responseError hooks around every fetch() call
  • An unregister() callback returned from register() so a specific interceptor can be removed cleanly at runtime
  • A clear() function that wipes all registered interceptors in one call, useful for test teardown
  • Separate Node and browser/web-worker entrypoints selected automatically via the package’s main/browser fields
  • A hand-written TypeScript declaration file (lib/index.d.ts) describing the interceptor shape

Common Use Cases

  • Attaching an auth token or custom header to every outgoing fetch request from one place
  • Centralizing request/response logging or debugging across an app without editing every call site
  • Globally redirecting or retrying requests when a responseError interceptor detects a failed call
  • Normalizing or reshaping response payloads before they reach application code
  • Swapping in whatwg-fetch transparently in environments where native fetch isn’t available

Under The Hood

Architecture The entire library is a single attach(env) factory in src/attach.js: it wraps whatever fetch implementation is present on the given global object (falling back to requiring whatwg-fetch if none exists) and replaces it with a closure that runs each call through a promise chain built from a module-level interceptors array — request interceptors applied in registration order, then the actual fetch, then response interceptors applied in reverse. src/node.js and src/browser.js are two-line entrypoints that each call attach() with the appropriate global (global, or window/self for web workers), so both environments share one interceptor registry and one implementation; if the core interceptor() promise-chaining logic changed, every consumer in both entrypoints would be affected simultaneously since there is no per-environment override point.

Tech Stack Plain ES2015+ JavaScript transpiled with Babel 6 (babel-preset-es2015), bundled for the browser with Webpack 1, and tested via Karma + Mocha + PhantomJS with the expect assertion library; there are no runtime dependencies beyond the optional whatwg-fetch polyfill, and a hand-authored index.d.ts supplies TypeScript types rather than a generated declaration build. The toolchain (Webpack 1, PhantomJS, Babel 6) reflects the project’s original 2015 vintage and has not been modernized despite commits continuing into 2022.

Code Quality A single test file (test/index.js) exercises register, unregister, and error interception, but the tests make real network calls to external hosts (google.com, google.de, a literal http://404) inside a headless PhantomJS browser rather than mocking fetch, which makes them integration-style and network-dependent rather than isolated unit tests. There is no mocking library (e.g. sinon, nock), no CI status currently verifiable beyond a stale Travis badge, and no code coverage reporting wired into the test run beyond the unused karma-coverage/istanbul-instrumenter-loader devDependencies.

API Design The public surface is deliberately minimal: register(interceptorObject) returns an unregister() closure, and clear() resets everything — mirroring AngularJS’s $http interceptor shape closely enough that developers familiar with it can adopt this library with essentially zero new concepts. Getting started is a single import plus a single register() call with no configuration object, though the shared global interceptor registry (rather than an interceptor-scoped or fetch-instance-scoped API) means multiple independent consumers in the same process register into one global list, which can surprise larger applications composing several unrelated interceptor sets.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search