「Fetch API」についてまとめる
今まで、ajax通信にはHTTPクライアント「axios」を使っていたが
最近はIE11をサポートしなくて良くなってきたので、
ブラウザでnativeでサポートされているFetch APIを使うことが多くなってきた。
挙動にちょっと癖があるのもあり、この際 きちんと詳細まで理解しておこうと思ったのでそのまとめ。
Fetch API
・(ネットワーク越しの通信を含む) リソース取得のためのインターフェースを提供。MLHttpRequestより簡単で便利
・fetch() は Promiseを返す
・レスポンスが404や500でもrejectを返さない。ネットワークエラーの時にのみrejectを返す
// 基本的な使い方
// function fetch(input: RequestInfo, init?: RequestInit | undefined): Promise<Response>
fetch('http://example.com/api')
.then(response => response.json())
.then(data => console.log(data))
fetch()でResponseオブジェクトを含むpromiseを返す。
このままでは、取得したデータを取得出来ないので、Responseオブジェクトが持つjsonメソッドでパースしてから使用する。
// ネットワークエラーの時しかrejectしない!
// 400番や500番の時は、 resolvedになる
fetch('http://example.com/api')
.then(response => response.json())
.then(data => console.log(data))
.catch(e => console.log(e)
エラーハンドリングにちょっと癖があり、
「ネットワークのエラーや、何かがリクエストの完了を妨げた場合のみ」
ということなので、上記だと漏れてしまう。
なので上記の記事を参考にさせてもらった。
fetch('/api')
.then((response) => {
// 400, 500系のエラーをキャッチ
console.log(response.ok);
console.log(response.status);
console.log(response.statusText);
if (!response.ok) {
throw new Error(response.statusText);
}
return response;
})
.then((response) => {
// jsonにパース
return response.json();
})
.then((data) => {
// 成功の時にする処理
console.log(data);
})
.catch((e) => {
// 失敗した時にする処理
// 400, 500系のエラーこちらにキャッチ
// ここでネットワークエラーもキャッチ
console.log('Error: ' + e.message);
});
使いやすいようにアレンジして、ラッパーを作成。
resolveでもrejectでも、どちらでも同じ形式のobjectを返すようにすれば
使いやすそう。
/**
* fetch APIの ラッパー
*/
type Props = {
url: string;
init: RequestInit;
debug?: boolean;
};
export function fetchApi<T>({
url,
init,
debug = false,
}: Props): Promise<{ data: T | null; fetchError: string | null }> {
return fetch(url, init)
.then((response) => {
if (debug) {
console.log(
'[ok]: ' + response.ok,
'[status]: ' + response.status,
'[text]: ' + response.statusText
);
}
if (!response.ok || response.status === 0) {
throw new Error(response.statusText); // 0, 400, 500 errors
}
return response.json();
})
.then((data: T) => {
return {
data: data,
fetchError: null,
};
})
.catch((e) => {
return {
data: null,
fetchError: e.message,
};
});
}
// usage
import { fetchApi } from '@/utils/fetchApi';
const onSubmit = async (data: Params) => {
const result = await fetchApi<dataType>({
url: '/contact_api/',
init: {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json',
'X-From': location.origin,
},
},
});
console.log(result);
};