Intercept fetch() API requests and responses in JavaScript

Solution 1:

Existing answers show the general structure for mocking fetch in the browser but omit important details.

The accepted answer shows the general pattern for replacing the window.fetch function with custom implementation that intercepts the call and forwards the arguments to fetch. However, the pattern shown doesn't let the interception function do anything with the response (for example, read the status or body or inject a mock) so is only useful for logging request parameters. This is a pretty narrow use case.

This answer uses an async function to let the interceptor await on the fetch promise and presumably work with the response (mocking, reading, etc) but (at the time of writing) has a superfluous closure and doesn't show how to read the response body non-destructively. It also contains a variable aliasing bug leading to a stack overflow.

This answer is the most complete so far but has some irrelevant noise in the callback and doesn't mention anything about cloning the response to enable the body to be collected by the interceptor. It doesn't illustrate how a mock could be returned.

Here's a minimal, complete example that rectifies these issues, showing how to handle parameter logging, reading the body without harming the original caller by cloning the response and (optionally) providing a mock response.

const {fetch: origFetch} = window;
window.fetch = async (...args) => {
  console.log("fetch called with args:", args);
  const response = await origFetch(...args);
  
  /* work with the cloned response in a separate promise
     chain -- could use the same chain with `await`. */
  response
    .clone()
    .json()
    .then(body => console.log("intercepted response:", body))
    .catch(err => console.error(err))
  ;
    
  /* the original response can be resolved unmodified: */
  //return response;
  
  /* or mock the response: */
  return {
    ok: true,
    status: 200,
    json: async () => ({
      userId: 1,
      id: 1,
      title: "Mocked!!",
      completed: false
    })
  };
};

// test it out with a typical fetch call
fetch("https://jsonplaceholder.typicode.com/todos/1")
  .then(response => response.json())
  .then(json => console.log("original caller received:", json))
  .catch(err => console.error(err))
;

Solution 2:

For intercepting the fetch request and parameter we can go for below mentioned way. its resolved my issue.

 const constantMock = window.fetch;
 window.fetch = function() {
     // Get the parameter in arguments
     // Intercept the parameter here 
    return constantMock.apply(this, arguments)
 }

Solution 3:

For intercepting the response body you need to create a new Promisse and resolve or reject current into "then" code. It solved for me and keep content for real app . eg. react etc..

const constantMock = window.fetch;
 window.fetch = function() {
  console.log(arguments);

    return new Promise((resolve, reject) => {
        constantMock.apply(this, arguments)
            .then((response) => {
                if(response.url.indexOf("/me") > -1 && response.type != "cors"){
                    console.log(response);
                    // do something for specificconditions
                }
                resolve(response);
            })
            .catch((error) => {
                reject(response);
            })
    });
 }

Solution 4:

const fetch = window.fetch;
window.fetch = (...args) => (async(args) => {
    var result = await fetch(...args);
    console.log(result); // intercept response here
    return result;
})(args);

Solution 5:

Further to Hariharan's answer, Here is how I updated spinner state in Redux before and after each fetch request

import store from './../store';

// Set up interceptor on all fetch API calls
// Increments redux spinner state when api is called
// Decrements redux spinner state again when it is returned
(function() {
    const originalFetch = window.fetch;
    window.fetch = function() {
        store.dispatch({type: 'show-spinner'})
        return originalFetch.apply(this, arguments)
            .then((res) => {
                store.dispatch({type: 'hide-spinner'})
                return res;
            })
    }
})();