TypeScriptでAPI通信を型安全に行う方法!FetchやAxiosの設計パターン徹底解説
生徒
「TypeScriptを使って、インターネット上の外部の仕組みからデータを引っ張ってくる方法が知りたいです。型安全という言葉もよく聞くのですが、パソコン初心者にも分かりますか?」
先生
「素晴らしい疑問ですね。データを引っ張ってくる仕組みをAPI通信と呼びます。TypeScriptを使えば、間違ったデータを取り込んでパソコンのプログラムがバグを起こすことを、未然に防ぐ設定ができるんですよ。」
生徒
「FetchやAxiosという道具を使うと聞きました。具体的にどうやって型安全な設計図を作るのですか?」
先生
「それでは、初心者の方にも分かりやすい例えを交えながら、基本的な使い方と設計パターンを順番に見ていきましょう!」
1. API通信とREST APIの基本知識
パソコンのプログラムを動かすとき、別のコンピューターから情報を送ってもらうことがあります。この情報のやり取りを行う窓口のことをAPIと呼びます。その中でも、インターネットの住所のような仕組みを使って、分かりやすく整理された窓口の形式をREST APIと言います。
例えば、スマートフォンの天気予報アプリを想像してください。アプリ自体は全国の天気を記録していませんが、お天気を管理している大きなコンピューターに「東京の天気を教えてください」とお願いをして、結果を受け取っています。このお願いをする行為をAPI通信と呼び、情報を提供してくれる仕組みをAPIサーバーと呼びます。
未経験の方にとっては、自分のパソコンの外側にある別の部屋から、データを宅配便で届けてもらうイメージを持つと分かりやすいでしょう。このとき、届く箱の中に何が入っているかをあらかじめ指定しておくことが大切になります。
2. 型安全とはどういう意味か
プログラミング言語のTypeScriptにおける最も重要な特徴が、この型安全という仕組みです。型安全とは、プログラムで扱うデータに「名前」「数字」「日付」といった明確なラベルを貼り、間違った種類のデータが紛れ込まないように守る仕組みのことです。
もし型安全ではない、従来のJavaScriptという言語で通信を行うと、お化け屋敷のように何が飛び出すか分からない箱を開けることになります。名前が届くと思っていたのに、突然数字が届いたり、中身が空っぽだったりすると、プログラムは途中でパニックを起こして動かなくなってしまいます。
TypeScriptであらかじめ「この箱には必ず文字列の名前が入っています」という約束事を作っておけば、通信を行う前にパソコンが間違いを指摘してくれます。このように、開発者が安心してプログラムを書くことができる状態を、型安全と呼びます。
3. Fetch機能を使った一番シンプルな通信
まずは、パソコンに最初から備わっている標準的な道具であるFetchを使って、インターネットからデータを呼び出す方法を学びましょう。Fetchは特別な準備をしなくても、そのまま命令を呼び出すだけで通信ができる便利な仕組みです。
以下のプログラムは、ユーザーの情報を1人分だけ取得する最も単純な記述例です。型をまだ指定していない状態ですが、どのようにインターネットの住所へアクセスするのか、その流れを確認してください。
function getSimpleUser() {
fetch("https://jsonplaceholder.typicode.com/users/1")
.then(response => response.json())
.then(data => {
console.log(data);
});
}
この記述では、指定したインターネットの住所に手紙を送り、返事が戻ってきたら中身を文字の形式からプログラムが読める形に変換して、画面に出力しています。しかし、このままではデータの種類が保証されていないため、型安全とは言えません。
4. 通信データに型を定義する設計図の作り方
先ほどの単純な通信を型安全にするために、届くデータの設計図を作成します。TypeScriptでは、データの形状を定義するためにinterfaceという命令を使います。これは、データの詰め合わせ箱の表面に貼る、中身のお品書きのようなものです。
今回は、ユーザーの番号、お名前、そして電子メールのアドレスという3つの情報が届くことを想定した設計図を作ります。初心者の方でも理解しやすいように、それぞれの情報の種類を明記します。
interface UserProfile {
id: number;
name: string;
email: string;
}
ここで登場したnumberは数字の種類を表し、stringは文字の種類を表しています。この設計図を用意することで、これから行う通信でどのような情報が届くのか、パソコンに対して明確に宣言することができます。
5. Fetchと型定義を組み合わせる実装パターン
作成した設計図を、実際にFetchの処理に組み込んでみましょう。通信で取得したデータに対して、先ほど作ったお品書きのラベルを貼り付けることで、型安全な状態を作ります。
下記のコードでは、非同期処理という技術を使っています。インターネットとのやり取りには少し時間がかかるため、データの到着を待つためにasyncとawaitという言葉をペアで使用します。これにより、上から下へと順番にきれいに処理が進むようになります。
async function fetchSafeUser(): Promise<UserProfile> {
const response = await fetch("https://jsonplaceholder.typicode.com/users/1");
const data: UserProfile = await response.json();
return data;
}
async function startProcess() {
const user = await fetchSafeUser();
console.log(user.name);
}
このプログラムでは、受け取ったデータに対してUserProfileという型を割り当てています。これにより、user.nameと入力したときに、確実にお名前の文字が取得できるようになり、存在しない情報を呼び出そうとするとパソコンがエラーを出して教えてくれます。
6. Axiosという応用的な道具の特徴と導入方法
標準的なFetchのほかに、実際のシステム開発ではAxiosという、より高機能な外部の道具がよく使われます。Axiosを使うメリットは、最初からデータを読みやすい形に自動で変換してくれたり、通信の細かい設定をまとめて管理できる点にあります。
未経験の方にとっては、Fetchが普通のハサミだとすれば、Axiosは安全ガードがついた工作用の高性能なハサミのようなものです。より少ない記述で、安全に多くの仕事をこなすことができます。
Axiosを使用する場合は、事前に拡張機能としてパソコンのプロジェクトに組み込む必要がありますが、一度導入してしまえば、型安全な通信をより短いプログラム行数で記述することが可能になります。
7. Axiosを使用した型安全な設計パターン
それでは、Axiosを使った具体的な型安全の設計パターンを見ていきましょう。Axiosの素晴らしいところは、通信の命令を呼び出すときに、大なり小なりの記号を使って直接、型設計図を指定できる点にあります。
以下の例では、インターネットの住所からブログの投稿記事データを取得するプログラムを記述しています。新しく記事用の設計図も同時に用意して、別のパターンを表現しています。
import axios from "axios";
interface BlogPost {
userId: number;
id: number;
title: string;
body: string;
}
async function getBlogPost(postId: number): Promise<BlogPost> {
const url = `https://jsonplaceholder.typicode.com/posts/${postId}`;
const response = await axios.get<BlogPost>(url);
return response.data;
}
注目すべき部分は、axios.get<BlogPost>という書き方です。これにより、この通信の返り値は絶対にブログ記事の形をしている、ということが確定します。結果を受け取るresponse.dataの中身が、最初から安全な状態に守られているのです。
8. 通信エラーが発生したときの安全な対策
インターネットの通信は、常に成功するとは限りません。電波が悪かったり、相手のコンピューターが壊れていたりすると、エラーが発生してデータが届かないことがあります。型安全な設計では、この失敗したときの対策も考えておく必要があります。
プログラムが途中で異常終了してしまわないように、トラブルが起きたら別の処理へ案内するtry-catchという防護服のような仕組みを導入します。これにより、万が一通信に失敗しても、画面が真っ白にならずに「通信に失敗しました」という優しいメッセージを表示できます。
async function getRobustPost() {
try {
const post = await getBlogPost(1);
console.log(post.title);
} catch (error) {
console.log("データの取得中に問題が発生しました。時間をおいてやり直してください。");
}
}
このように、成功したときだけでなく、失敗したときのルートをあらかじめ作っておくことが、システム全体の安全性を高めるために不可欠な設計パターンとなります。
9. 実際のシステム開発における共通管理の考え方
実際の開発では、何十箇所からも通信を行うことがあります。そのたびにインターネットの住所を全部書いていると、もし住所が変わったときに修正作業が大変になってしまいます。そのため、通信の窓口を1つにまとめる専門の部品を作る設計がよく選ばれます。
これを通信の共通管理、またはAPIクライアントの共通化と呼びます。会社の受付窓口を1つにして、そこから各部署に書類を振り分けるようなイメージです。窓口を1つにしておけば、すべての通信に共通の安全対策を一元的に適用できるようになります。
この考え方を取り入れることで、プログラム全体の風通しが良くなり、後から改造を加えたり、不具合を見つけたりすることが圧倒的に簡単になります。初心者の方も、まずは基礎を学び、慣れてきたらこの共通化の設計パターンを意識してみると良いでしょう。