Coder Social home page Coder Social logo

fetch-intercept's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fetch-intercept's Issues

TypeError: Already read at consumed

When I am trying to get Response body using Body mixin json() method

response: function (response) {
   response.json().then((data) => {
       alert(JSON.stringify(data))
   });
   return response;
}

I am able to see resonse body data in the alert box but I am getting error:

TypeError: Already read
    at consumed (blob:http://localhost:8081/10a78587-5550-4332-a55f-9e31c45f9f4f:17774:31)
    at Response.Body.text (blob:http://localhost:8081/10a78587-5550-4332-a55f-9e31c45f9f4f:17892:24)
    at Response.Body.json (blob:http://localhost:8081/10a78587-5550-4332-a55f-9e31c45f9f4f:17916:21)
    at response (blob:http://localhost:8081/10a78587-5550-4332-a55f-9e31c45f9f4f:1581:17)
    at tryCallOne (blob:http://localhost:8081/10a78587-5550-4332-a55f-9e31c45f9f4f:18312:14)
    at blob:http://localhost:8081/10a78587-5550-4332-a55f-9e31c45f9f4f:18413:17
    at blob:http://localhost:8081/10a78587-5550-4332-a55f-9e31c45f9f4f:5214:21
    at _callTimer (blob:http://localhost:8081/10a78587-5550-4332-a55f-9e31c45f9f4f:5103:9)
    at _callImmediatesPass (blob:http://localhost:8081/10a78587-5550-4332-a55f-9e31c45f9f4f:5139:9)
    at Object.callImmediates (blob:http://localhost:8081/10a78587-5550-4332-a55f-9e31c45f9f4f:5358:14)": TypeError: Already read
    at consumed (blob:http://localhost:8081/10a78587-5550-4332-a55f-9e31c45f9f4f:17774:31)
    at Response.Body.text (blob:http://localhost:8081/10a78587-5550-4332-a55f-9e31c45f9f4f:17892:24)
    at Response.Body.json (blob:http://localhost:8081/10a78587-5550-4332-a55f-9e31c45f9f4f:17916:21)
    at symbolicateStackTrace$ (blob:http://localhost:8081/10a78587-5550-4332-a55f-9e31c45f9f4f:17553:54)
    at tryCatch (blob:http://localhost:8081/10a78587-5550-4332-a55f-9e31c45f9f4f:18983:19)
    at Generator.invoke [as _invoke] (blob:http://localhost:8081/10a78587-5550-4332-a55f-9e31c45f9f4f:19156:24)
    at Generator.prototype.(anonymous function) [as next] (blob:http://localhost:8081/10a78587-5550-4332-a55f-9e31c45f9f4f:19026:23)
    at tryCatch (blob:http://localhost:8081/10a78587-5550-4332-a55f-9e31c45f9f4f:18983:19)
    at invoke (blob:http://localhost:8081/10a78587-5550-4332-a55f-9e31c45f9f4f:19059:22)
    at blob:http://localhost:8081/10a78587-5550-4332-a55f-9e31c45f9f4f:19069:15

Due to this error I not able to navigate to next screen.
I am using Mobx for State management.

Cannot read property 'apply' of undefined

This happens when I specify the requestError function. Tested it in a new create-react-app with https://github.com/github/fetch.

import fetchIntercept from 'fetch-intercept';

const unregister = fetchIntercept.register({
  requestError: (error) => {
    return Promise.reject(error);
  },
  responseError: (error) => {
    // catches bad error here
    return Promise.reject(error);
  },
});

fetch('http://google.com');

// Unregister your interceptor
unregister();

Looking at the source, _ref.request is undefined.

	  reversedInterceptors.forEach(function (_ref) {
	    var request = _ref.request; // request is undefined
	    var requestError = _ref.requestError;
	
	    if (request || requestError) {
	      promise = promise.then(function (args) {
	        return request.apply(undefined, _toConsumableArray(args));
	      }, requestError);
	    }
	  });

triger cors when work with swr

I have registered an interceptor in my app.js file in react as follows:

fetchIntercept.register({
  response: function (response) {
    if (response.status >= 500 && response.status < 600) {
      bottomToast("server error")
    }
    return response;
  }
});

However, when I use SWR to fetch data, I encounter a CORS error. Here's the code I'm using for the fetch:

const fetcher = (...args) => fetch(...args, { headers:{ accessToken: state.accessToken } }).then((res) => res.json())
const {data: profile} = useSWR(state.isLogin ? `${portalAddress}/user/${state.userId}` : null, fetcher);

It seems that the OPTIONS request is being sent before the fetch request, which is causing the CORS error.
It's important to note that this issue only occurs in production mode and not in the development environment. The error message I receive is shown in the attached screenshot.

image

Cannot set credentials options for fetch API

By default, fetch won't send or receive any cookies from the server, resulting in unauthenticated requests. In order to include cookies, we have to add "credentials:include" for each REST API requests which are implemented in Fetch API. But it is not maintainable if we manually add such an option everywhere when Fetch is used. So we decided to look for help from fetch-intercept. Here is our implementation:
fetchIntercept.register({ request: function (url, config) { config.credentials = 'include'; return [url, config]; }, ... };
But after the change, all Fetch functions stop working and the following exceptions are found in Chrome developer console:

auth-window-actions.js:81 Uncaught (in promise) Error: Failed to fetch login user info: TypeError: Cannot set property 'credentials' of undefined.

Any suggestion to it? Our front end is implemented by React v16.3.

fetch-intercept in React

Hi, the question is not complicated. How to use correctly your library with React?

I make a function call in this way:

import fetchIntercept from './fetchIntercept';

const App = () => {
  
  fetchIntercept(); <---

  return (
    <>
      ...content...
    </>
  );
};

Handling refresh token by recall same request after refreshing the token

Hi,
I am trying to make a common interceptor to authorize all my outgoing requests.

My logic is as follows:

All my outgoing requests/API calls passes through the interceptor first to check on my token expiry and in-case the response was un-authorized I make an internal call to refresh the token and update my storage keys with the new values.

Now I need to recall the original request with the new token value, but I can't figure out how to detect the original request that passed through the interceptor.

This is my code :

export  const unregister =  fetchIntercept.register({
  request: function (url, config) {
    return [url, config];
  },

  requestError: function (error) {
    return Promise.reject(error);
  },
  responseError: function (error) {
    return Promise.reject(error);
  },

  response: function (response) {
    if (response.status == 401) {
      Services.refreshToken((res)=>{
        if (res.message == 'success') {
          // if token has been refreshed
          // recall the request again
        }else {
          // login again
        }
      })
    }else {
      return response;
    }
  }
})

The problem is that I've no idea how to recall the same request that passed through the interceptor.. I did some search on this, but couldn't find a way to execute this.

How to pass in an arbitrary object as state from request to response or error?

Greetings! First of all, thank you for all your effort on the library, works great ๐Ÿ˜„

I am using version: 2.4.0.

I am using the interceptors to measure response time, so wanted to know a way I could pass in some kind of object as state between the request and the response functions. I am looking for something like this:

fetchIntercept.register({
    request: function (url, config) {
        return [url, config, {state: 'Good!'}]
    },
    response: async function (response, state) {
        console.log(state) // logs {state: "Good!"}
        return response
    }
})

My request comes that if I store the state inside a file, I'll get the values overriden when different respond at different times.

Any way to walk this around? It could also work to access the state from within the response object, as we do with the request object.

Thanks!

No fetch avaibale. Unable to register fetch-intercept

in Jest test

import fetch from 'node-fetch'
global.fetch= fetch
import fetchIntercept from "fetch-intercept";

throws

โ— Test suite failed to run

No fetch avaibale. Unable to register fetch-intercept

  10 | 
  11 | // fetchIntercept.register(errorInterceptor)
> 12 | // fetchIntercept.register(dataInterceptor)
     |                                              ^
  13 | // fetchIntercept.register(cookieInterceptor)
  14 | // fetchIntercept.register(headersInterceptor)
  15 | 

  at attach (node_modules/fetch-intercept/lib/webpack:/src/attach.js?1269:38:13)
  at Object.<anonymous> (node_modules/fetch-intercept/lib/webpack:/src/node.js:3:18)
  at Object.<anonymous> (node_modules/fetch-intercept/lib/node.js:53:31)
  at __webpack_require__ (node_modules/fetch-intercept/lib/webpack:/webpack/bootstrap 288f28a76d94cd56de0b?2753:19:1)
  at node_modules/fetch-intercept/lib/webpack:/webpack/bootstrap 288f28a76d94cd56de0b?2753:39:1
  at Object.<anonymous> (node_modules/fetch-intercept/lib/node.js:44:10)
  at Object.<anonymous> (src/api/index.js:12:46)
  at Object.<anonymous> (src/plugins/bottle.js:24:35)
  at Object.<anonymous> (src/models/AbstractSync.js:25:15)
  at Object.<anonymous> (src/models/index.js:27:44)
  at Object.<anonymous> (src/plugins/className.js:5:38)
  at Object.<anonymous> (tests/test-setup.js:30:1)

Add possibility to return promise instead of array in request event

My scenario is as follows:

  1. A fetch() call is made with a GET request to a REST API
  2. The 'request' event is handled so that it injects an auth token to the headers
  3. If the token is expired I'd like to refresh the token by making an additional call inside the 'request' event

The question is as follows: would it be possible to return a Promise from the 'request' event instead of a fixed array with the [url, config]? The token refresh call is made using a promise, and I'd like to inject the auth header in the .then of the promise. The 'request' does not wait for the promise resolve. Example code of what' I'm trying to do:

this.unregisterFetchInterceptor = fetchInterceptor.register({
         request: (url, config) => {
               this.refreshAuthTokenIfExpired(resourceName).then(() => {
                     let modifiedConfig = this.injectAuthHeader(resourceName, config);
                     return [url, modifiedConfig];
               });                   
         }
 });

Thanks,
Adam

Include fetch request inside Response and ResponseError

Similar logic to how the axios interceptor works. So for any 400 errors, we can refresh the token and send back the original request.

But without access to the original request and request body, this isn't possible.

There seems to be PR #36 open which addresses this, but it hasn't been merged.

Any update if / when this might get done?

TS Type mismatch when response is async function or returns promise

Type '(response: FetchInterceptorResponse) => Promise' is not assignable to type '(response: FetchInterceptorResponse) => FetchInterceptorResponse'.

export interface FetchInterceptor {
request?(url: string, config: any): Promise<any[]> | any[];
requestError?(error: any): Promise;
response?(response: FetchInterceptorResponse): FetchInterceptorResponse;
responseError?(error: any): Promise;
}

So, the example of refresh token is not usable with ts...

Is this still maintained?

Hi!
Is this still maintained? There are ongoing issues that could be easily fixed, and it hasn't been for months.

Thanks,

Nothing seems to get intercepted

I have the following code:

...
import fetchIntercept from 'fetch-intercept';

class UserActions {
    async logout() {
        const unregister = fetchIntercept.register({
            request: function (url, config) {
                // Modify the url or config here
                console.log("LOGOUT INTERCEPT", url, config);
                return [url, config];
            },

            requestError: function (error) {
                // Called when an error occured during another 'request' interceptor call
                return Promise.reject(error);
            },

            response: function (response) {
                // Modify the reponse object
                console.log("LOGOUT INTERCEPT", response);
                return response;
            },

            responseError: function (error) {
                // Handle an fetch error
                return Promise.reject(error);
            }
        });

        let err, response, stat;
        try {
            response = await fetch(`${apiUrl}/user/logout`);
            if (response.ok) {

Expectation: Requests are intercepted and logged in the console
Result: Nothing gets logged in the console.

Module not found: Error: Cannot resolve module 'whatwg-fetch' when building with webpack

I'm trying to use this as part of a webpack-based web UI. I installed it with npm install --save-dev fetch-intercept. My code looks like:

import fetchIntercept from 'fetch-intercept';

fetchIntercept.register({
  request: (url, config) => [url, config],
  requestError: err => Promise.reject(err),
  response: res => res,
  responseError: err => Promise.reject(err)
});

in authFetchIntercept.js and I have import './authFetchIntercept.js' inside my javascript's entrypoint. Trying to build the site with webpack results in:

ERROR in ./~/fetch-intercept/lib/index.js
Module not found: Error: Cannot resolve module 'whatwg-fetch' in /Users/jeffreycharles/projects/facial-recognition-webui/node_modules/fetch-intercept/lib
 @ ./~/fetch-intercept/lib/index.js 261:18-41

config is undefined in node express application

When I use this package in client with whatwg-fetch works perfect, but if I use in server with node-fetch config is undefined.

 global['fetch'] = require('node-fetch');
  fetchIntercept = require('fetch-intercept');
  fetchIntercept.register({
    request: function (url, config) {
        console.log(config);
        console.log('request server');

        return [url, config];
    },
});

Probably I'm doing something wrong here, but cannot find.

Why I need config? Because I want to modify headers, I did that but still not adding headers:


        const config = defaultConfig || {};
        config.headers = config.headers || {};

        config.headers['language-filter'] = true;
        config.headers['Accept-Language'] = 'en';

        return [url, config];

What if I don't use webpack ?

Hi,

Of course I prefer to use webpack as a bundler (I would highly recommend it)
But trouble is that I cannot get access to the index.js source file to use it in debug mode (without webpack-dev-server, with just some naive configuration)
Would you like to withdraw index.js file from .npmignore for me ?

(I know why you did that, I did the same once, I removed src so that people had to consider the module as a black box)

Thank you for your time,
LiBe.

TypeScript definitions

Are there any TypeScript definitions available anywhere for this module? Would really appreciate to be able to use this in my TypeScript environment.

Keep up the good work! ๐Ÿ‘

How to read request method from response

I'm writing a hook on fetch response. I need both the URL and the method of the request to decide whether the hook should be called or not.

However, in the response hook, I can only get URL. Do you know where could I get the method('post', 'get', 'put', etc.) that the request is using in the response hook?

fetchIntercept.register({
  response: function(response) {
      if(response.url === predefinedURL   &&   response.method /* I don't know how to get it */  === predefinedMethod) {
           //do something here
      }
  }
});

Many Thanks

How to fail a request?

Hi, I am using typescript with React Native and node. I need to add an interceptor to check for reachability by verifying whether the device has a network connection. How do I cause a request to fail from within the 'request' block. I have tried throwing an error but I get an 'unhanded promise rejection' error instead.

Here is my code:

//register the new interceptor
        ReachabilityFetchInterceptor._unregisterInterceptor = registerFetchIntercept({
            request: async (url: string, options: any): Promise<Array<string>> => {
                //Check whether the url matches the regexp

                //check whether react native thinks we're offline
                NetInfo.getConnectionInfo().then((connectionInfo) => {
                    if (connectionInfo.type === "NONE" || connectionInfo.type === "UNKNOWN") {
                        throw new Error("Reachability Error - Device offline");
                    }
                }).catch((err) => {                    
                    return Promise.reject(err);
                });
           },
           requestError: (error: any): Promise<void> => {
               //do something here after the error is caught 
},
...

i'd love some advice on how to proceed with this?

thanks!

Add ability to limit fetch interception to a specific component only

My scenario is this: on a single page I have multiple independent components that use the fetch API. All of them require to mutate requests (add request headers, etc.) and handle the response, so they all register an interceptor. The issue here is that a fetch request from one component is intercepted by all other components interceptors. Does anyone have an idea how to ensure that a fetch request originating from one component is intercepted only by an interceptor registered by the same component? In older versions of JS there was something like arguments.caller, so it was possible to identify where the function call originated, but this is deprecated now and not available in "use strict" mode.

Request Method as Async

I have a requirement to get a JWT from a service using an async request, and I'll need that token to set as a header in the 'request' part of the fetch-intercept pipeline here. However, since request is sync, I cannot set the token correctly unless I wait for the token to come back before running any requests. I am already able to set the token as I'm describing using an HttpInterceptor in Angular since the intercept() method they implement has the option to be a Promise.

If you could do the same, just like you already have with requestFailure and the other methods, then that would make your library a magnitude more powerful.

Re-use interceptor across multiple files

I currently have this in my auth.tsx file, and it works fine


import fetchIntercept from 'fetch-intercept';

export default fetchIntercept.register({
  request: function (url, config) {
    // Modify the url or config here
    config.headers.append = {
      'content-type': 'application/json',
      'Authorization': 'my authorization'
    }
    return [url, config];
  },

  requestError: function (error) {
    // Called when an error occured during another 'request' interceptor call
    return Promise.reject(error);
  },

  response: function (response) {
    // Modify the reponse object
    return response;
  },

  responseError: function (error) {
    // Handle an fetch error
    return Promise.reject(error);
  }
});

export function login(username: string, password: string) {
  // ${process.env.REACT_APP_API_BASE}/api/v1/users/login/
  return fetch('http://localhost:8000/api/v1/users/login/', {
    method: 'POST',
    body: JSON.stringify({ 'username': username, 'password': password })
  })
}

Let's say I have books.service.tsx file, and I wanna make use of the already defined interceptor from the auth.tsx in there. How do I go about it?

typing file incorrect

Request intercept Interface looks like this::
request?(url: string, config: any): Promise<any[]> | any[];

Based on looking at the code , the library invoked intercept's request api with the exact same args as that of fetch so it should be
request?(input: RequestInfo, init?: RequestInit): Promise<any[]> | any[];

This will make the library usage better

How can I read `response.request.body` in `response`?

Hey @mlegenhausen ๐Ÿ‘‹ Great library and amazing work.

I'm trying to read the response.request.body in the response interception:

response: function (response) {
        response.text().then((value) => {
          console.log('Response here')
          console.log(value)
        })

        const requestClone = response.request.clone()
        requestClone.text().then((value) => {
          console.log('Request body here')
          console.log(value)
        })

        return response;
      },

I'm getting Uncaught (in promise) TypeError: Failed to execute 'clone' on 'Request': Request body is already used. I have tried with:

response.request.text().then((value) => {
          console.log('Request body here')
          console.log(value)
        })

But I'm getting TypeError: Failed to execute 'clone' on 'Request': Request body is already used.

My use case is to whenever there's a response I would like to log the request body and the response body. Is it possible to do it entirely in the response or do I have to keep track of the request, and whenever I get a response I look for the request and merge them?

How to update the access token during 401 response

Hi guys,

I had a requirement where I want to intercept the response, when the token is expired using refresh token.

 response: async function (response) {
                if(response.status === 401)
                {
                   //call the refreshToken api
                   // update token
       
                   return fetch(url, config) //call fetch again with new token
                }
                else
                {
                    return response
                }        
            },

In the last release of the library, there was an update about request data passed with the response through which we can get the url. But how can I get the config details too. As there is no proper example or documentation on this, can anyone help me out here.

In the following open issue #39 , there is code provided but the implementation
wont work, in a case where there are multiple request been sent in same time.

Thanks,
:)

Intercepting 401 or responses not working?

I didnt want to comment on issue #16 but i see the same issue. i really just care about intercepting a 401 but the response console.log is never hit. even if its the only thing in there. responseError does tho.


fetchIntercept.register({
  responseError: function(error) {
    console.log('responseError', error)
  }
});

fetchIntercept.register({
  response: function(response) {
    console.log('fetchIntercept response', response)
    if (response.status >= 401) throw new Error('Request error');
    return response;
  }
});

// Call fetch to see your interceptors in action.
fetch('http://google.com');

TypeError: Cannot read property '_instance' of undefined

When I use the new Promise option for 'request' I get this error

Short
TypeError: Cannot read property '_instance' of undefined

Stacktrace location

TypeError: Cannot read property '_instance' of undefined
    at register (index.js:130)

index.js line 130

/**
    * Register intercept hooks & return an interceptor instance
    * @param {object} hooks - The intercept hooks
    * @return {FetchInterceptor} An interceptor object
    */
    value: function register() {
      var hooks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

      if (this._instance) {   // <<<<----- HERE IS LINE 130 of index.js
        return this._instance;
      }
      var interceptor = new this();
      for (var i = 0; i < this.hooks.length; i++) {
        var hook = this.hooks[i];
        if (typeof hooks[hook] === 'function') {
          interceptor[hook] = hooks[hook];
        }
      }
      interceptor.hijack();
      this._instance = interceptor;
      return interceptor;
    }

Here is how I setup my fetchInterceptor register call

fetchInterceptor.register({
      request: (url, config) => {
        return this.claimsService.getTokenForUser()
          .then(token => {
            config.headers['Authorization'] = token ? `Bearer: ${token}` : null;
            return [url, config];
          });
      },
      requestError: function (error) {
          return Promise.reject(error);
      },
      response: function (response) {
          return response;
      },
      responseError: function (error) {
          return Promise.reject(error);
      }
    });

The getTokenForUser() call is a Promise.

Maybe the switch to use Promise on the request method needs to take a closer look?

I make a suggest.

If you can make an automatic unregister interceptor, it will be perfect.

Request interceptor containing an async call

Hi, Is it possible to perform asynchronous calls in a "request" interceptor? I have an interceptor that gets the access token from the localforage library but all methods are asynchronous. If so could you provide a code example please? Thanks

Best way to unit test an interceptor?

Hey, I was wondering if there are any recommended ways to unit test fetch interceptors. I have tried using fetch-mock to mock a http request however that package doesn't allow the fetch request to hit the interceptor.

Does anyone have any experience testing fetch interceptors, specifically using mocha tests

Thanks!

Depend on the error

Fetch -intercept depends on whatwg-fetch, but in dependencies there is no whatwg-fetch, and this will be an error if the user does not have whatwg-fetch locally

"* whatwg-fetch in ./node_modules/fetch-intercept/lib/browser.js

To install it, you can run: npm install --save whatwg-fetch"

Meanwhile, I hope the author can try to upgrade the whatwg-fetch

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.