JavaScriptでAPIを叩く際に使用する代表的な武器として、fetchとaxiosが挙がると思います。
fetchはJavaScriptの標準ライブラリなのに対し、axiosはインストールする必要があります。
それでも僕がaxiosがfetchより使いやすいという理由を、ざっくりと両者の特徴を紹介しながらいくつか述べてみました!
サンプルのAPIとして、猫の雑学(英語)をランダムで返してくれるcatfact.ninjaをお借りしています😺
https://catfact.ninja/fact
1. エラーハンドリング
【fetchの場合】
fetchは、サーバのレスポンスが届きはじめた時点でPromiseを解決する
という特徴があります。つまり、サーバのレスポンスが届きさえすれば、とりあえずPromiseのresolve()
が実行されてしまうということです。
これが、若干不便です。
400エラーや500エラーが起きた場合でも、then
の中が実行されてしまうのです。
たとえば、以下のようなプログラムがあったとします。
fetch('https://catfact.ninja/foo').then((response) => {
console.log(response);
alert('Success!');
}).catch((error) => {
console.error(error);
});
https://catfact.ninja/foo
というURLは存在しないので、404ステータスが返るのですが、このプログラムを実行すると、ブラウザに「Success!」というアラートが出ます。
ステータスがどうであれ、サーバー(catfact.ninja)にリクエストが飛んでレスポンスを返しているのでPromiseはresolve
を実行し、then
の中の処理が実行されたという訳です。
以下が404ステータスが返った場合のResponseオブジェクトの内容になります。
{
body: ReadableStream,
bodyUsed: false,
headers: Headers,
ok: false,
redirected: false,
status: 404,
statusText: "",
type: "cors",
url: "https://catfact.ninja/foo"
}
fetchが返すResponseオブジェクトには、ok
というプロパティがあります。(上記4つ目のプロパティ)
レスポンスのステータスが200~299の場合、ok
プロパティがtrue
になり、それ以外のステータスの場合はfalse
になります。
このok
プロパティを利用してthen
の中に分岐を入れてあげることで、200~299以外のステータスの場合のハンドリングが可能になります。
とはいえ、エラーが発生しているのにthen
の中が実行されることに、僕は少しだけ違和感を感じちゃいます...
fetch('https://catfact.ninja/foo').then((response) => {
if (response.ok) {
console.log(response);
alert('Success!');
} else {
alert('Error!');
}
}).catch((error) => {
console.error(error);
});
ちなみに、200~299以外でもthen
が実行されるのなら、catch
はどのような場合に実行されるのかと、疑問に思う方もいると思います。
fetchにおいて、catch
はレスポンスがない場合、つまり通信状況の不具合などでHTTP通信そのものが失敗した場合に実行されます。
【axiosの場合】
axiosでは、200~299以外のHTTPステータスがレスポンスで返ってきた場合にはcatch
が実行されます。
なので、以下のプログラムを実行すると、サーバーから404レスポンスが返り、catch
が実行されブラウザにError!
というアラートが表示されます。
axios.get('https://catfact.ninja/foo').then((response) => {
alert('Success!');
}).catch((error) => {
alert('Error!');
});
2. GETメソッド以外の通信
【fetchの場合】
fetchを使用する場合、GET以外のメソッドのHTTP通信を行う場合には、以下のように実行時の第二引数のプロパティmethod
でHTTPメソッドを指定することでPOST通信などが可能になります。
また、リクエストボディを設定する際は、第二引数のプロパティにbody
にJSON.stringify
でJSON形式にフォーマットしたオブジェクトを設定します。
fetch('api/v1/users', {
method: 'POST',
body: JSON.stringify({
name: 'Whopper',
age: 24
})
}).then((response) => {
alert('Success!');
}).catch((error) => {
alert('Error!');
});
【axiosの場合】
axiosの場合は、それぞれのHTTPメソッド毎にメソッドが用意されてます。
また、リクエストボディを設定する際は、第二引数に渡したいオブジェクトを設定します。
デフォルトでJSON形式にフォーマットされる為、JSON.stringify
の記述は不要になります。
axios.post('api/v1/users', {
name: 'Whopper',
age: 24
}).then((response) => {
alert('Success!');
}).catch((error) => {
alert('Error!');
});
3. JSONの取得
【fetchの場合】
fetchでは、レスポンスにJSONデータを含む場合、基本的にthen
が2つあったりします。
1つめのthen
の中で実行されているresponse.json()
というやつが、レスポンスのJSONを解析しているメソッドになります。
その返り値を、2つめのthen
の引数として渡されているような感じです。
fetch('https://catfact.ninja/fact').then((response) => {
return response.json();
}).then((responseJson) => {
console.log(responseJson);
});
【axiosの場合】
axiosでは、レスポンスオブジェクトのdata
へアクセスすることで、JSON解析済みのオブジェクトを参照することができます。
JSON解析のためにthen
を増やす必要がないので、見た目もすっきりします。
axios('https://catfact.ninja/fact').then((response) => {
console.log(response.data);
});
4. インターセプター
【fetchの場合】
fetchでは、標準機能を用いてインターセプターを実装することができません。
fetch-interceptというライブラリを使用したり、fetchメソッド自体をオーバーライドしたりする必要があります。
【axiosの場合】
axiosでは、標準機能でインターセプターを実装することができます。
以下では、リクエストを送信する際にリクエスト送信
というログを出すリクエストインターセプターを定義しています。
axios.interceptors.request.use((config) => {
console.log('リクエスト送信');
return config;
});
以下では、レスポンスを受信した際にレスポンス受信
というログを出すレスポンスインターセプターを定義しています。
axios.interceptors.response.use((response) => {
console.log('レスポンス受信');
return response;
});
5. リクエスト時の共通設定を定義
axiosではcreate
メソッドを利用することでaxiosのインスタンスが作成できます。
これを利用することで、リクエスト毎のタイムアウトの時間や、ベースURLや、共通のヘッダーなどを定義することができます。
const baseRequest = axios.create({
baseUrl: 'https://catfact.ninja',
timeout: 2000
});
baseRequest.get('/fact').then((response) => {
console.log(response.data);
}).catch((error) => {
console.error(error);
});
まとめ
まとめると、axiosは以下の点でfetchより使いやすいと考えています。
- 200~299以外のステータスの場合は
catch
が実行される - HTTPメソッド毎にメソッドが用意されているのでGET以外の通信が楽
- レスポンスオブジェクトの
data
プロパティで、解析済みのJSONデータを取得できる - インターセプターの実装が楽
- 通信時の共通設定の定義が楽
他にも、「axiosはこういう点も便利!」や「fetchはこういう点で素晴らしい!」などがありましたら、是非コメントをお願いします!
最後まで読んでいただき、ありがとうございました!