nomurabbitのブログ

nomurabbitのブログはITを中心にした技術ブログです。

nomurabbitのブログ

【Typescript】axiosのREADME読んでみた Part7【React】

この記事はReactaxiosを使うために、axiosのREADMEを読んで得た情報をまとまたものです。React×Typescriptのサンプルコードも載せています。

こんにちは!nomurabbitです。今回はaxiosに関する記事です。

Part7の今回はインターセプターについてです。リクエスト実行時に毎回ログを書き出したいときなどに使えます。Typescriptの解説やサンプルコードを交えて一緒に勉強していきましょう

Interceptors

You can intercept requests or responses before they are handled by then or catch.

thenやcatchの前に処理を差し込めるんですね。

// Add a request interceptor
axios.interceptors.request.use(function (config) {
    // Do something before request is sent
    return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
  });

// Add a response interceptor
axios.interceptors.response.use(function (response) {
    // Any status code that lie within the range of 2xx cause this function to trigger
    // Do something with response data
    return response;
  }, function (error) {
    // Any status codes that falls outside the range of 2xx cause this function to trigger
    // Do something with response error
    return Promise.reject(error);
  });

Typescriptのサンプルコードはこんな感じです。

サンプルコード nomurabbit ver.

const apiUrl_dammy = "https://dammy/api/fuga";

axios.interceptors.request.use(function (config) {
  console.log('request resolve');
  return config;
}, function (error) {
  console.log('request reject');
  return Promise.reject(error);
});

axios.interceptors.response.use(function (response) {
  console.log('response resolve');
  return response;
}, function (error) {
  console.log('response reject');
  return Promise.reject(error);
});

const getHttpPostResponseBbk = () => {
  axios.post(apiUrl_dammy, {
    headers: {
      'Content-Type': 'text/plain'
    },
    data: {httpRequestMessage}
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
}||<

実行結果
[f:id:nomurabbit:20211228165125p:plain]

<p class="l-fuki noa">こちらはerrorの例ですが、consoleにログが吐かれていますね。</p>

>>
If you need to remove an interceptor later you can.
<<

グローバルで指定したインターセプターを<span style="color: #ea902d"><strong>個別にキャンセル</strong></span>することもできます。

>|javascript|
const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);

Typescriptだとこんな感じです。

サンプル1 nomurabbit ver.

const apiUrl_dammy = "https://dammy/api/fuga";

const my_request_interceptor = axios.interceptors.request.use(function (config) {
  console.log('request resolve');
  return config;
}, function (error) {
  console.log('request reject');
  return Promise.reject(error);
});

const my_response_interceptor = axios.interceptors.response.use(function (response) {
  console.log('response resolve');
  return response;
}, function (error) {
  console.log('response reject');
  return Promise.reject(error);
});

// requestのインターセプターをキャンセル
axios.interceptors.request.eject(my_request_interceptor);

const getHttpPostResponseBbk = () => {
  axios.post(apiUrl_dammy, {
    headers: {
      'Content-Type': 'text/plain'
    },
    data: {httpRequestMessage}
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
}

実行結果
f:id:nomurabbit:20211228165951p:plain

requestのインターセプターがキャンセルされて、responseのインターセプターだけになりました。

You can add interceptors to a custom instance of axios.

カスタムインスタンスにもインターセプターを定義することができます。

const instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});

サンプル2 nomurabbit ver.

const apiUrl_dammy = "https://dammy/api/fuga";

const instance = axios.create();

const my_request_interceptor = instance.interceptors.request.use(function (config) {
  console.log('request resolve');
  return config;
}, function (error) {
  console.log('request reject');
  return Promise.reject(error);
});

const my_response_interceptor = instance.interceptors.response.use(function (response) {
  console.log('response resolve');
  return response;
}, function (error) {
  console.log('response reject');
  return Promise.reject(error);
});

const getHttpPostResponseBbk = () => {
  instance.post(apiUrl_dammy, {
    headers: {
      'Content-Type': 'text/plain'
    },
    data: {httpRequestMessage}
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
}

実行結果
f:id:nomurabbit:20211228170421p:plain

キャンセルもいけます。

サンプル3 nomurabbit ver.

const apiUrl_dammy = "https://dammy/api/fuga";

const instance = axios.create();

const my_request_interceptor = instance.interceptors.request.use(function (config) {
  console.log('request resolve');
  return config;
}, function (error) {
  console.log('request reject');
  return Promise.reject(error);
});

const my_response_interceptor = instance.interceptors.response.use(function (response) {
  console.log('response resolve');
  return response;
}, function (error) {
  console.log('response reject');
  return Promise.reject(error);
});

// requestのインターセプターをキャンセル
instance.interceptors.request.eject(my_request_interceptor);

const getHttpPostResponseBbk = () => {
  instance.post(apiUrl_dammy, {
    headers: {
      'Content-Type': 'text/plain'
    },
    data: {httpRequestMessage}
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
}

実行結果
f:id:nomurabbit:20211228170654p:plain

When you add request interceptors, they are presumed to be asynchronous by default. This can cause a delay in the execution of your axios request when the main thread is blocked (a promise is created under the hood for the interceptor and your request gets put on the bottom of the call stack). If your request interceptors are synchronous you can add a flag to the options object that will tell axios to run the code synchronously and avoid any delays in request execution.

requestのインターセプターは非同期で実行されます。もし同期的に実行させる場合はフラグを指定することで、インターセプター > then or catchの処理の順に実行させることができます。

axios.interceptors.request.use(function (config) {
  config.headers.test = 'I am only a header!';
  return config;
}, null, { synchronous: true });

If you want to execute a particular interceptor based on a runtime check, you can add a runWhen function to the options object. The interceptor will not be executed if and only if the return of runWhen is false. The function will be called with the config object (don't forget that you can bind your own arguments to it as well.) This can be handy when you have an asynchronous request interceptor that only needs to run at certain times.

runWhen 関数を使うことで、特定の条件の時にのみインターセプターを実行させることができます。ただし、v0.24.0の時点ではTypescriptのaxios.interceptors.request.use()メソッドに第三引数をとることができないので、javascript向けの機能となります。

function onGetCall(config) {
  return config.method === 'get';
}
axios.interceptors.request.use(function (config) {
  config.headers.test = 'special get headers';
  return config;
}, null, { runWhen: onGetCall });

Multiple Interceptors

インターセプターを複数指定した時の挙動についてです。

Given you add multiple response interceptors and when the response was fulfilled

then each interceptor is executed
then they are executed in the order they were added
then only the last interceptor's result is returned
then every interceptor receives the result of it's predecessor
and when the fulfillment-interceptor throws
then the following fulfillment-interceptor is not called
then the following rejection-interceptor is called
once caught, another following fulfill-interceptor is called again (just like in a promise chain).
Read the interceptor tests for seeing all this in code.

というわけで今回はインターセプターについて勉強してきましたが、axiosのREADME読んでみた Part7いかがでしたでしょうか?

次回もぜひご覧ください。では!

参考

axios
github.com