TypeScriptでAPI通信!AxiosとFetchでリトライ処理付きの安全なAPI呼び出し設計を完全解説
生徒
「TypeScriptを使って、インターネット上のデータを安全に読み込む方法を知りたいです。通信が失敗したときに自動でやり直すリトライ処理というものも作ってみたいです。」
先生
「インターネットを通じたデータのやり取りは、時に電波が悪くて失敗することもありますね。TypeScriptでは、Fetch機能やAxiosという仕組みを使って、失敗しても自動で再挑戦する安全な仕組みを組み立てることができます。」
生徒
「パソコンの操作もあまりやったことがないのですが、そんな私でも安全な通信の仕組みを作ることができますか。」
先生
「大丈夫ですよ。基礎から一つずつ、実際の道具に例えながら仕組みを解説していきます。それでは、基本的な使い方を見ていきましょう!」
1. API通信とTypeScriptの基本的な役割とは?
パソコンの操作をしたことがない方にとって、API通信という言葉は難しく聞こえるかもしれません。API通信とは、簡単に言うと「自分のパソコン」と「インターネットの向こう側にある別のパソコン(サーバー)」の間で、データの貸し借りを行うお約束のことです。例えば、スマートフォンのアプリで天気予報を見るとき、アプリはインターネットを通じて最新の天気データをどこかから持ってきています。この、データを持ってくる行為そのものを通信と呼びます。
TypeScript(タイプスクリプト)は、この通信をとても安全に行うためのプログラミング言語です。プログラミングにおける「安全」とは、プログラムが途中で急に動かなくなったり、おかしなデータを間違えて読み込んで画面が真っ白になったりしないことを意味します。TypeScriptは、これからやり取りするデータの形(名前や年齢、日付など)をあらかじめ厳しくチェックする機能を持っています。そのため、間違ったデータが紛れ込もうとしたときに、動かす前の段階で間違いを見つけて教えてくれる、とても親切な案内役なのです。
2. データを取得する道具であるFetchとAxiosの違い
インターネットからデータを取ってくるためには、専用の道具が必要です。代表的な道具として、Fetch(フェッチ)とAxios(アクシオス)という二つの道具があります。これらは、手紙を届ける配達員のような役割を持っています。どちらを使っても目的のデータを取ってくることができますが、少しだけ性格が違います。
Fetchは、パソコンにあらかじめ標準で用意されている最初から使える道具です。新しく何かを準備する必要がないため、手軽に使い始めることができるのが大きな利点です。一方で、Axiosは、後から追加でインストールして使う専門的な道具です。Axiosは非常に気が利く道具で、通信が失敗したときの処理や、通信の細かい設定を自動で助けてくれる便利な機能をたくさん持っています。今回の解説では、初心者でも書きやすくて安全な設計がしやすいAxiosを中心とした書き方と、標準的なFetchの両方の動かし方を見ていきましょう。
3. 最初に知っておきたい非同期処理とエラーの意味
通信のプログラムを書くときに必ず登場するのが、非同期処理(ひどうきしょり)という考え方です。普段、パソコンのプログラムは上から順番に一瞬で実行されます。しかし、インターネットを通じて遠くのパソコンからデータを取ってくるのには、少しだけ時間がかかります。ほんの数秒ですが、データが届くまでプログラムが完全に止まってしまうと、パソコンの画面が固まって操作できなくなってしまいます。
そこで、データを待っている間も他の処理を先に進めておき、データが届いたらその中身を開いて処理をするという仕組みを使います。これが非同期処理です。TypeScriptでは、async(エイシンク)やawait(アウェイト)という特別な言葉を使って、この時間のかかる処理を表現します。また、通信は常に成功するとは限りません。山の中で電波が途切れたり、相手のパソコンが故障していたりすると、データは届きません。これをエラー(異常事態)と呼びます。安全なプログラムを作るためには、このエラーが起きたときに画面を壊さず、優しく対応する処理が必要になります。
4. Fetchを使った最もシンプルな通信のプログラム
まずは、一番基本となるFetchを使ったプログラムを見てみましょう。インターネット上にある架空のデータ置き場から、ユーザーの名前を取得する簡単な例です。難しい仕組みは入れず、まずはどのようにデータが流れるかを確認します。ここでは、データを正しく受け取るための通り道を作っています。
async function getRandomUser() {
try {
const response = await fetch("https://jsonplaceholder.typicode.com/users/1");
const data = await response.json();
console.log("通信が成功しました");
console.log(data.name);
} catch (error) {
console.log("通信の途中で何かがおかしくなりました");
}
}
このプログラムでは、try(トライ)とcatch(キャッチ)という仕組みを使っています。これは「まずは試しにこの枠中を実行してみて、もし途中でエラーが起きたら、隣のキャッチの枠に移動して安全に処理を逃がす」という防護服のような役割を持っています。これにより、通信が失敗してもプログラム全体が突然終了してしまうのを防ぐことができます。
通信が成功しました
Leanne Graham
5. Axiosを使って安全にデータを読み込む基本的な方法
次に、専門的な道具であるAxiosを使った方法を見てみましょう。Axiosを使うと、先ほどのFetchよりもデータの変換作業が少なくなり、よりすっきりとした見た目でプログラムを書くことができます。さらに、TypeScriptの強みである「型(データの設計図)」を組み合わせることで、届いたデータの中に何が入っているのかをパソコンが完全に把握できるようになります。
import axios from "axios";
interface UserProfile {
id: number;
name: string;
email: string;
}
async function fetchUserProfile() {
try {
const response = await axios.get<UserProfile>("https://jsonplaceholder.typicode.com/users/1");
console.log("プロフィールを取得しました");
console.log(response.data.email);
} catch (error) {
console.log("データの取得に失敗しました");
}
}
ここで新しく登場したinterface(インターフェース)とは、データの設計図のようなものです。この中では、数字が入る場所にはnumber、文字が入る場所にはstringという指定をしています。こうすることで、これから届くデータに名前やメールアドレスが必ず含まれていることを、プログラムを実行する前に保証することができます。これがTypeScriptが安全と言われる最大の理由です。
プロフィールを取得しました
Sincere@april.biz
6. なぜ自動でやり直すリトライ処理が必要なのか?
どれほど完璧なプログラムを書いても、通信の失敗を完全にゼロにすることはできません。なぜなら、利用者が電車に乗っていてトンネルに入った瞬間かもしれないですし、お家の無線LANの調子が一時的に悪くなっただけかもしれないからです。このような、少し待てば直るかもしれない一時的な失敗のことを、専門用語で「一時的なエラー」と呼びます。
もし通信が一瞬だけ失敗したときに、すぐに画面に「エラーが起きました」と大きな警告を出して諦めてしまったら、利用者はもう一度ボタンを押し直さなければならず、不便に感じてしまいます。そこで、一回目の通信が失敗したら、少しだけ時間を置いてから「もう一回だけ自動で試してみる」という仕組みを作ります。これがリトライ処理(再試行処理)です。人間の代わりにプログラムが健気に何度も挑戦してくれることで、利用者は通信の乱れに気づくことなく、快適にアプリを使い続けることができるようになります。
7. 安全なリトライ処理を自分で設計して組み立てる
それでは、通信が失敗したときに、指定した回数だけ自動でやり直す安全な設計を実際に作ってみましょう。今回は、最大で三回まで通信に挑戦し、それでも駄目だった場合に初めて諦めるという親切な仕組みを構築します。少しずつ時間をあけながら挑戦するように工夫しています。
async function fetchWithRetry(url: string, maxAttempts: number) {
let currentAttempt = 1;
while (currentAttempt <= maxAttempts) {
try {
console.log(currentAttempt + "回目の通信に挑戦します");
const response = await fetch(url);
if (!response.ok) {
throw new Error("通信の状態が良くありません");
}
const data = await response.json();
return data;
} catch (error) {
console.log(currentAttempt + "回目は失敗しました");
currentAttempt = currentAttempt + 1;
if (currentAttempt > maxAttempts) {
console.log("すべての挑戦が失敗しました");
throw error;
}
console.log("少し待ってからやり直します");
}
}
}
この仕組みでは、while(ワイル)という繰り返しの命令を使っています。一回目が失敗すると、currentAttemptという現在の挑戦回数を表す数字が一つずつ増えていき、指定した最大の回数を超えるまで何度も挑戦を繰り返します。失敗した直後にすぐ次の通信を始めると、相手のパソコンに大きな負担をかけてしまうため、本来は少しだけお休み時間を挟むのがより良い設計となります。
1回目の通信に挑戦します
1回目は失敗しました
少し待ってからやり直します
2回目の通信に挑戦します
1回目は失敗しました
少し待ってからやり直します
3回目の通信に挑戦します
8. Axiosの拡張機能を使ってよりスマートにリトライを実現する
先ほどは仕組みを理解するために自分で繰り返しのプログラムを書きましたが、実際の本格的な開発では、もっとスマートに間違いのない方法をとることが一般的です。Axiosには、通信の部品を拡張して、自動リトライの機能を後から合体させることができる便利な専用の道具が用意されています。これを使うと、より簡潔で間違いのない安全な設計が完成します。
import axios from "axios";
const safeHttpClient = axios.create({
timeout: 5000
});
safeHttpClient.interceptors.response.use(
(response) => response,
async (error) => {
const config = error.config;
if (!config) {
return Promise.reject(error);
}
config.retryCount = config.retryCount || 0;
if (config.retryCount >= 3) {
return Promise.reject(error);
}
config.retryCount += 1;
console.log("自動リトライを行います。回数: " + config.retryCount);
return safeHttpClient(config);
}
);
ここで使っているinterceptors(インターセプター)とは、通信が成功したときや失敗したときに、そのデータを途中で待ち伏せして、独自の処理を割り込ませるための関門のようなものです。通信がエラーの関門を通ったとき、挑戦回数がまだ三回未満であれば、設定をそのまま引き継いでもう一度同じ通信を発射するという賢い動きをします。また、timeout(タイムアウト)を設定することで、応答が遅いときにいつまでも待ち続けず、五秒で区切るという安全対策も同時に行っています。これで、初心者でも安心して運用できる、頑丈で安全な通信設計の基礎ができあがりました。
自動リトライを行います。回数: 1
自動リトライを行います。回数: 2