🐾
【TypeScript】非同期処理についてまとめる。fetch,axios編
はじめに
TypeScript で非同期処理を扱うについて、自分の知識が浅い部分があったので改めてまとめて行こうと思います。(初心者のため優しい目で見てください)
第一弾目は以下に書いてます!!
fetch
について
fetch
とは、HTTPリクエストを送信する関数で、ネットワークを介してリソース(データ)を取得するための仕組みで、Promiseを返します。
// GETリクエスト
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json()) // レスポンスをJSONに変換
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
ポイント
-
fetch
は常に Promise<Response> を返します。 - レスポンスのボディは response.json() や response.text() などで取り出すことが可能です。
- ネットワークエラー(サーバーがダウンしている、存在しないドメインにアクセスしたなど)は
catch
で捕まります。 - HTTPステータスエラー(400番台や500番台など)は
catch
では捕まらないため、必要に応じてres.ok
やres.status
をチェックして明示的に処理する必要があります。
interface Todo {
userId: number;
id: number;
title: string;
completed: boolean;
}
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(res => res.json())
.then((data: Todo) => {
console.log(data.title);
});
ポイント
-
fetch
で取得するJSONの型を明示すると、型安全になります。
HTTPメソッドの使い分け
fetch
は 任意のHTTPメソッド を指定できます。
CRUD処理での使い分けは以下の通りです。
メソッド | 用途 | 例 |
---|---|---|
GET | データ取得 | fetch('/api/todos') |
POST | 新規作成 | fetch('/api/todos', { method: 'POST', body: ... }) |
PUT | 全体更新 | fetch('/api/todos/1', { method: 'PUT', body: ... }) |
PATCH | 一部更新 | fetch('/api/todos/1', { method: 'PATCH', body: ... }) |
DELETE | 削除 | fetch('/api/todos/1', { method: 'DELETE' }) |
POSTリクエストの例
// まず型を定義
interface Todo {
userId: number;
id: number;
title: string;
completed: boolean;
}
// POSTリクエスト用データ
const newTodo = {
userId: 1,
title: 'Learn TypeScript',
completed: false
};
const createTodo = async (): Promise<void> => {
try {
const res = await fetch('https://jsonplaceholder.typicode.com/todos', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(newTodo)
});
if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`);
// 型注釈をつける
const data: Todo = await res.json();
console.log('Created:', data);
} catch (err) {
console.error(err);
}
};
createTodo();
クエリパラメータの付け方
fetch
でクエリパラメータを付けて条件付きデータを取得する例です。
URLSearchParams
を使うと URL に付与するクエリパラメータを簡単に作れます。
interface Todo {
userId: number;
id: number;
title: string;
completed: boolean;
}
async function fetchTodos() {
try {
const params = new URLSearchParams({
userId: '1',
completed: 'false'
});
const res = await fetch(`https://jsonplaceholder.typicode.com/todos?${params.toString()}`);
if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`);
const data: Todo[] = await res.json();
console.log(data);
} catch (err) {
console.error('Error:', err);
}
}
fetchTodos();
タイムアウト制御
fetch
はデフォルトでタイムアウトがなく、通信が止まったままになることがあります。
そこで AbortController
を使って中断します。
async function fetchWithTimeout() {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000); // 5秒で中断
try {
const res = await fetch('https://httpbin.org/delay/10', {
signal: controller.signal
});
if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`);
const data = await res.json();
console.log(data);
} catch (err: unknown) {
if (err instanceof DOMException && err.name === 'AbortError') {
console.error('Fetch aborted due to timeout');
} else if (err instanceof Error) {
console.error('Other error:', err.message);
} else {
console.error('Unexpected error', err);
}
} finally {
clearTimeout(timeoutId);
}
}
fetchWithTimeout();
axios
について
axios
とは、HTTPリクエストを送信するための 外部ライブラリ で、Promise ベースで動作します。
fetch
と同じくデータの取得や送信が可能ですが、以下の点が特徴です。
- JSON の送受信を自動で行ってくれる
- HTTPステータスエラー(400/500など)も catch で捕捉できる
- タイムアウトやリクエストヘッダーの設定が簡単
- クエリパラメータをオブジェクトで渡せる
postリクエスト例
import axios, { AxiosError } from 'axios';
interface Todo {
userId: number;
id: number;
title: string;
completed: boolean;
}
const newTodo = {
userId: 1,
title: 'Learn Axios',
completed: false
};
async function createTodo() {
try {
const res = await axios.post<Todo>(
'https://jsonplaceholder.typicode.com/todos',
newTodo,
{
headers: {
'Content-Type': 'application/json'
}
}
);
console.log('Created Todo:', res.data);
} catch (err: unknown) {
if (axios.isAxiosError(err)) {
// AxiosError なら response や request が安全に使える
if (err.response) {
console.error('HTTP error:', err.response.status, err.response.data);
} else if (err.request) {
console.error('No response:', err.request);
} else {
console.error('Axios error:', err.message);
}
} else if (err instanceof Error) {
console.error('Other error:', err.message);
} else {
console.error('Unexpected error', err);
}
}
}
createTodo();
ポイント
- axios.post<Todo>(url, data, config)
- 型注釈 <Todo> で返却データを型安全に扱える
- 第2引数に送信データ、第3引数にヘッダーなどの設定を指定
- Content-Type: 'application/json' → JSON データを送る場合に必要
- fetch と違って、HTTPステータスエラー(400/500)も catch に入る
→ err.response.status でステータスを確認可能 - axios は自動で JSON に変換して送信してくれるので、fetch のように JSON.stringify() は不要
- res.data に作成された Todo が返ってくる
HTTPメソッドの使い分け
メソッド | 用途 | axios の書き方 |
---|---|---|
GET | データ取得 | axios.get(url) |
POST | 新規作成 | axios.post(url, data) |
PUT | 全体更新 | axios.put(url, data) |
PATCH | 一部更新 | axios.patch(url, data) |
DELETE | 削除 | axios.delete(url) |
クエリパラメータの付け方
params にオブジェクトを渡すだけで自動でクエリ文字列に変換
URLSearchParams を使わなくても安全にエンコードされる
この例では userId=1 かつ completed=false の Todo だけを取得
import axios, { AxiosError } from 'axios';
interface Todo {
userId: number;
id: number;
title: string;
completed: boolean;
}
async function fetchTodos() {
try {
const res = await axios.get<Todo[]>('https://jsonplaceholder.typicode.com/todos', {
params: {
userId: 1,
completed: false
}
});
console.log(res.data);
} catch (err: unknown) {
if (axios.isAxiosError(err)) {
// AxiosError 型の場合
if (err.response) {
console.error('HTTP error:', err.response.status, err.response.data);
} else if (err.request) {
console.error('No response:', err.request);
} else {
console.error('Axios error:', err.message);
}
} else if (err instanceof Error) {
// その他のエラー
console.error('Other error:', err.message);
} else {
console.error('Unexpected error', err);
}
}
}
fetchTodos();
タイムアウト制御
fetch の AbortController の代わりに timeout オプションで簡単に制御できる
import axios from 'axios';
async function fetchWithTimeout() {
try {
const res = await axios.get('https://httpbin.org/delay/10', {
timeout: 5000 // 5秒でタイムアウト
});
console.log('Response received:', res.data);
} catch (err: unknown) {
if (axios.isAxiosError(err)) {
// AxiosError 型の場合
if (err.code === 'ECONNABORTED') {
console.error('Request timed out');
} else if (err.response) {
console.error('HTTP error:', err.response.status, err.response.data);
} else if (err.request) {
console.error('No response:', err.request);
} else {
console.error('Axios error:', err.message);
}
} else if (err instanceof Error) {
console.error('Other error:', err.message);
} else {
console.error('Unexpected error', err);
}
}
}
fetchWithTimeout();
エラーハンドリング
fetch と違い、HTTPステータスエラーも catch に入る
err.response.status でステータスコード確認可能
import axios from 'axios';
async function fetchWithErrorHandling() {
try {
// 存在しない URL で意図的に 404 を返す
const res = await axios.get('https://jsonplaceholder.typicode.com/todos/9999');
console.log(res.data);
} catch (err: unknown) {
if (axios.isAxiosError(err)) {
// AxiosError 型の場合
if (err.response) {
console.error('HTTP error:', err.response.status, err.response.data);
} else if (err.request) {
console.error('No response:', err.request);
} else {
console.error('Axios error:', err.message);
}
} else if (err instanceof Error) {
// その他の一般的なエラー
console.error('Other error:', err.message);
} else {
// 予期しない型のエラー
console.error('Unexpected error', err);
}
}
}
fetchWithErrorHandling();
まとめ
-
fetch
- HTTPリクエストを送信する関数で、Promise を返す
- データ取得や送信が可能だが、HTTPステータスエラーは自動では catch に入らない
- タイムアウト制御は AbortController を使う必要がある
- JSONの送受信やクエリパラメータの処理は自分で実装する必要がある
-
axios
- 外部ライブラリで、Promise ベースで動作
- JSON の送受信を自動で行ってくれる
- HTTPステータスエラーも catch で捕捉可能
- タイムアウトやヘッダー設定が簡単で、クエリパラメータもオブジェクトで安全に渡せる
Discussion