今回はJavaScriptのFetchAPIとHTTP通信のライブラリであるaxiosの違いについて解説します。
「fetchAPIとaxiosってやってること同じ...?何が違うの?」という疑問から色々調べてみたのでまとめてみました。
なお、基本構文や根底にある非同期通信、Promise自体の解説は割愛します。
FetchAPIとは
まずイメージを掴むために、Fetchの語源から確認してみます。
フェッチとは、取りに行く、取ってくる、持ってくる、などの意味を持つ英単語。ITの分野では機器やプログラムなどが特定の場所からデータなどを読み出す動作のことを指すことが多い。
(フェッチとは - IT用語辞典 より)
プログラミングではAPIサーバーなどからデータを持ってくる、取ってくるという意味でfetchという単語がよく使われていますね。
次にFetchAPIに関して確認してみましょう。
Fetch APIはHTTP通信を行ってリソースを取得するためのAPIです。 Fetch APIを使うことで、ページ全体を再読み込みすることなく指定したURLからデータを取得できます。 Fetch APIは同じくHTTP通信を扱うXMLHttpRequestと似たAPIですが、より強力で柔軟な操作が可能です。
JSprimerより引用
つまり、XMLHttpRequest
に変わる、モダンな非同期通信の手段といえます。
次に、fetchAPIの特徴を見ていきます。
FetchAPIの対応ブラウザ
IEでは使えません。また Android 4.4.4
、iOS Safari 10.2
以下 も非対応です。
Can I use... Support tables for HTML5, CSS3, etc
そのため上記に対応させるには Pollyfill が必要です。
FetchAPIは最新のブラウザの標準機能
FetchAPIはモダンブラウザの標準機能として提供されているので、ライブラリなどをインストールする必要はありません。
ただ、先程確認したようにIEなどのブラウザでは標準では使えないので、一長一短です。
返ってくるのはResponseオブジェクト
fetchAPIにより返されるResponseオブジェクトは、ただの HTTP レスポンスであり実際の JSON ではありません。
response オブジェクトからJSON を抽出するには、 json()
メソッドを使用する必要があります。
返ってきたレスポンスにjsonメソッドをつけることでJSONとしてパースして使用できます。
Fetchから返されるPromiseは404や500をrejectしない
これが分かりにくい仕様の一つですね。
要はfetchを使ってAPIにアクセスして404エラーや500エラーがでても.catchできず(rejectされず)、.thenの方の処理(resolve)が走ってしまうというもの。
この仕様は、fetchの役割はあくまで「リクエストを投げてレスポンスを受け取って返すことである」というのが関係しています。
HTTP404や500の場合でも「エラーというレスポンスを返す」という役割は成功しているためrejectされないという仕組みになっています。
rejectされるのはネットワークのエラーや、リクエストの完了を妨げた場合のみらしいです。
サンプルコードで確認してみましょう。
DogAPIというランダムな犬の画像を返す、外部APIを使ってテストしてみます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
<h2>Fetch Test</h2>
<button id="button">Fetch!!</button>
</div>
<script>
const button = document.querySelector('#button');
button.addEventListener('click', () => {
fetch('https://dog.ceo/api/breeds/image/random')
.then(response => {
console.log("resolvedの処理です");
console.log(response.json());
}).catch(err => {
console.log("rejectedの処理です");
console.error(err);
});
});
</script>
</body>
</html>
APIにアクセスして、成功すればresponseをjsonにパースしてコンソールに表示。
失敗したらエラーをコンソールに表示しています。
すると以下のようにresolvedでレスポンスが返ってきます。
resolvedの処理です
Promise {<pending>}
__proto__: Promise
[[PromiseStatus]]: "resolved"
[[PromiseValue]]: Object
message: "https://images.dog.ceo/breeds/havanese/00100trPORTRAIT_00100_BURST20191126134713895_COVER.jpg"
status: "success"
__proto__: Object
次にAPIのURLを少しいじって404エラーを発生させてみます。
<script>
const button = document.querySelector('#button');
button.addEventListener('click', () => {
fetch('https://dog.ceo/api/breeds/image/random/ntiafupd') //存在しないURLに変更
.then(response => {
console.log("resolvedの処理です");
console.log(response.json());
}).catch(err => {
console.log("rejectedの処理です");
console.error(err);
});
});
</script>
これでAPIにアクセスしてみると、、
resolvedの処理です
Promise {<pending>}
__proto__: Promise
[[PromiseStatus]]: "resolved"
[[PromiseValue]]: Object
code: 404
message: "No route found for "GET /api/breeds/iamage/random" with code: 0"
status: "error"
__proto__: Object
上記のようにresolved側の処理が走っていることが分かりますね。
これを解決するためには、fetchから返ってくるresponseオブジェクトのokプロパティを使って判断します。
response.okはレスポンスが成功(200-299 の範囲のステータス)したか否かの真偽値が入っているプロパティです。
okプロパティを使って書き換えてみると以下のようになります。
<script>
const button = document.querySelector('#button');
button.addEventListener('click', () => {
fetch('https://dog.ceo/api/breeds/image/random')
.then(response => {
if(!response.ok) {
console.error("エラーレスポンス", response);
} else {
console.log(response.json());
}
}).catch(err => {
console.error(err);
});
});
</script>
このように、response.okで条件分岐させることで404や500が返ってきたときもエラーとして処理できるようになりました。
普通にHTTP404や505が返ってきたときにエラーを発生させるのにも、一工夫必要ということに注意です。
axiosとは
axiosとはブラウザやnode.js上で動くPromiseベースのHTTPクライアントです。非同期にHTTP通信を行いたいときに容易に実装できるライブラリです。
axiosとは WillStyleより引用
非同期でHTTP通信できるというのはfetchAPIと同じですね。
ただ、axiosはライブラリなのでここでは紹介しきれないほどのオプションや設定があります。
今回は頻出で便利な機能や特徴を紹介します。
axiosもPromiseを返す
axiosはPromiseベースのライブラリなのでPromiseを返してくれます。
そのため、thenやcatchで処理を続けることが可能です。
また成功時に返ってくるresonseもJSON形式なので特にパースの処理などは必要なく、そのままresponse.dataで使用することができます。
404や500もrejectしてくれる
先程FetchAPIではHTTPで404や500が返ってきた時も、resolveされてしまうということを確認しました。
axiosもPromiseを返しますが、404や500もrejectされcatch側の処理が走るようになっています。
これは直感的に使えるので嬉しいですね。
axios.createでインスタンス作成できる
axiosの特徴としてカスタムインスタンスを作成できる、というのがあります。
例えばaxiosでAPIにアクセスする時に同じようなオプションを設定したいときがあるかと思います。
axios.get('/some/url', {
xsrfHeaderName: 'X-CSRF-Token',
withCredentials: true
})
axios.post('/some/other/url',{foo: 'bar'}, {
xsrfHeaderName: 'X-CSRF-Token',
withCredentials: true
})
こんな場合にaxios.createでインスタンスを作成することで設定などをまとめられるという訳ですね。
const myAxios = axios.create({
xsrfHeaderName: 'X-CSRF-Token',
withCredentials: true
})
myAxios.get('/some/url')
myAxios.post'/some/other/url',{foo: 'bar'})
インスタンスは複数作成できるので用途に合わせてファイルを分け、モジュールとして分割することも可能です。
interceptorで任意の処理を追加できる
axiosにはintereceptorという任意の処理を割り込ませる機能もついています。
interceptとは捕捉する、捕まえるといった意味。
axiosを通したリクエストやレスポンスを捕まえて任意の処理を差し込むことができます。
以下はリクエストのヘッダーに常に"XSRF-TOKEN"を付与してリクエストを送るというサンプルコードです。
window.axios.interceptors.request.use(config => {
// クッキーからトークンを取り出してヘッダーに添付する
config.headers["X-XSRF-TOKEN"] = getCookieValue("XSRF-TOKEN");
return config;
});
このようにリクエストの前に何か共通の処理を自動化したいなどのときにinterceptorは便利です。
複数の処理を以下のように分けて記述することも可能です。
const myAxios = axios.create({}); //インスタンスを作成
// responseの処理ひとつめ
myAxios.interceptors.response.use( (response) => {
/* なにかしらの処理 */
:
return response
})
// responseの処理ふたつめ
myAxios.interceptors.response.use( (response) => {
/* なにかしらの処理 */
:
return response
})
axiosは使う機能次第で色々なことができそうですね。
他にもたくさんの機能がありますが、紹介しきれないので公式ドキュメントを参考にしてください。

FetchAPIとaxiosの違いや共通点 まとめ
個人的には、やれることも多いaxiosを使うという結論に落ち着きました。
ライブラリをインストールしたくないなど特別な理由がない限り、axiosに軍配が上がりそうです。