TypeScriptでAxiosのレスポンス型を明示的に定義する方法!API通信の初心者向け解説
生徒
「TypeScriptを使ってインターネットからデータを取得するとき、データの形をあらかじめ決めておく方法があると聞きました。どうやるのでしょうか?」
先生
「それはレスポンス型の定義ですね。Axiosという便利な道具を使うときに、受け取るデータの設計図をあらかじめ用意しておくことで、安全にプログラムを動かすことができますよ。」
生徒
「データの設計図ですか!パソコンをあまり触ったことがない私でも、具体的にどのように書けばいいか分かりますか?」
先生
「大丈夫です。基本から順番に、分かりやすい例えを交えて説明しますね。それでは、実際の使い方を詳しく見ていきましょう!」
1. API通信とAxiosとは何か
プログラミングを始めたばかりの方にとって、API通信やAxiosという言葉は難しく感じるかもしれません。まずはこれらの基本を、日常生活の例えを使って分かりやすく解説します。
インターネットの世界では、自分のパソコンやスマートフォンと、遠くにある別のコンピューターが情報のやり取りをしています。この遠くにあるコンピューターのことをサーバーと呼びます。そして、サーバーに「このデータをください」とお願いして、データを送ってもらう仕組みのことをAPI通信と言います。
これをレストランに例えてみましょう。あなたが席に座っているお客さんだとします。厨房にいる料理人に直接「ハンバーグをください」と言いに行くのは大変ですよね。そこで、注文を代わりに伝えて、料理をテーブルまで運んでくれる店員さんが必要になります。この店員さんの役割を果たすのが、Axios(アクシオス)というプログラムの道具です。
Axiosは、JavaScriptやTypeScriptというプログラミング言語で、とても簡単にサーバーと通信を行うために作られた便利な仕組みです。これを使うことで、複雑な通信の仕組みを知らなくても、数行の命令を書くだけで、インターネット上のデータを自分の画面に表示させることができるようになります。
2. TypeScriptで型を定義する理由とメリット
では、なぜTypeScriptを使うときに、わざわざ型(かた)というものを定義する必要があるのでしょうか。普通のJavaScriptでは、型を決めなくても通信を行うことができますが、TypeScriptではここを厳しく管理します。
型とは、データの種類や中身のルールのことです。例えば、「お名前」を入れる場所には文字だけを入れる、「年齢」を入れる場所には数字だけを入れる、というようなお約束のことを指します。これをプログラムの世界では型定義と呼びます。
もし型を決めていないと、どのような問題が起きるでしょうか。レストランの例に戻ります。店員さんであるAxiosが、厨房から料理を運んできました。しかし、中身がハンバーグなのか、カレーライスなのか、あるいはデザートなのか、フタを開けてみるまで分かりません。スープなのに平らなお皿で受け取ろうとしたら、こぼれてしまいますよね。プログラムでも同じことが起きます。数字が返ってくると思っていたのに文字が返ってくると、パソコンは混乱してしまい、画面が真っ白になったり、エラーで動かなくなったりします。
事前に「この通信では、こういうデータが返ってきます」という設計図を作っておくことで、パソコンは事前に準備をすることができます。もし間違った使い方をしようとすると、プログラムを実行する前に「使い方が間違っていますよ」と教えてくれます。これが、TypeScriptで型を明示的に定義する最大のメリットです。未経験の方でも、エラーを事前に防ぐことができるため、安心して開発を進めることができます。
3. レスポンス型を定義するためのインターフェースの使い方
型を定義するためには、TypeScriptに用意されているinterface(インターフェース)という仕組みを使います。インターフェースとは、まさにデータの設計図や説明書のようなものです。
例えば、インターネットからユーザーの情報を取得したいとします。そのユーザー情報には、「識別番号(ID)」「名前」「メールアドレス」が含まれているとしましょう。この情報の形をインターフェースで表現すると、次のようになります。
interface User {
id: number;
name: string;
email: string;
}
ここで出てきた英単語について説明します。id: numberの「number」は、数字を表す型です。name: stringやemail: stringの「string」は、文字を表す型です。このように、それぞれの項目がどのような種類のデータであるかを細かく指定していきます。
この設計図を一枚作っておくことで、これから行うAPI通信で返ってくるデータが、必ずこの形をしているということをTypeScriptに伝えることができます。これが、明示的に型を定義するための第一歩となります。
4. Axiosのレスポンス型を明示的に指定する基本的な書き方
設計図が準備できたら、いよいよAxiosを使ってデータを取得してみましょう。データを取得するときは、Axiosのgetという命令を使います。このときに、先ほど作ったインターフェースを組み合わせて指定します。
具体的な書き方を見てみましょう。プログラムの中に不等号の記号を使って型を挟み込むのが特徴です。実際のコードは以下のようになります。
import axios from 'axios';
interface User {
id: number;
name: string;
email: string;
}
axios.get<User>('https://api.example.com/user')
.then(response => {
console.log(response.data.id);
console.log(response.data.name);
console.log(response.data.email);
});
このコードの中にあるaxios.get<User>という部分に注目してください。getのすぐ後ろにある<User>が、「この通信で返ってくるデータは、Userという設計図の通りですよ」と指定している部分です。これをジェネリクスと呼びますが、今は「型を教えてあげるための目印」と覚えておけば大丈夫です。
このように書くことで、response.dataの中身が自動的にUserの形になり、パソコンが名前やメールアドレスを正しく認識できるようになります。
5. 複数のデータを受け取る配列のレスポンス型定義
先ほどの例では、一人のユーザー情報を取得する場合を説明しました。しかし、実際のホームページやアプリでは、複数のユーザー一覧をまとめて取得することの方が多いです。このように、複数のデータを並べて管理する仕組みを配列(はいれつ)と呼びます。
TypeScriptで配列の型を表現するときは、型名の後ろに四角い括弧を二つ[]並べて書きます。例えば、先ほどのUserが何人も集まった一覧データを受け取る場合は、User[]と書きます。実際のプログラム例を見てみましょう。
import axios from 'axios';
interface User {
id: number;
name: string;
email: string;
}
axios.get<User[]>('https://api.example.com/users')
.then(response => {
response.data.forEach(user => {
console.log(user.name);
});
});
今回の通信では、axios.get<User[]>と指定していますね。これによって、受け取るデータが単一のデータではなく、たくさんのユーザー情報が入ったリストであることが保証されます。リストの中にある一人ひとりの名前を、順番に安全に読み出すことができるようになります。
6. 複雑な構造をしたAPIデータの型定義の方法
実際のインターネット通信では、データがさらに複雑な形をしていることがあります。例えば、ユーザー情報の中に「住所」という項目があり、その住所の中にさらに「郵便番号」や「都道府県名」が入っているような場合です。このように、データの中にさらにデータが含まれている構造をネスト(入れ子構造)と呼びます。
複雑な形をしていても難しく考える必要はありません。小さな設計図をいくつか作り、それを大きな設計図の中で組み合わせることで、きれいに型を定義することができます。次のプログラム例を確認してみましょう。
import axios from 'axios';
interface Address {
zipcode: string;
city: string;
}
interface UserProfile {
id: number;
username: string;
address: Address;
}
axios.get<UserProfile>('https://api.example.com/profile')
.then(response => {
console.log(response.data.username);
console.log(response.data.address.city);
});
この例では、まず住所のための設計図であるAddressを作りました。その後に、ユーザー全体の設計図であるUserProfileの中で、address: Addressという形で住所の設計図を部品として組み込んでいます。
このように部品を組み合わせることで、どんなに複雑なデータがサーバーから送られてきても、迷うことなく正確な型定義を行うことができます。これにより、深い階層にあるデータにアクセスするときも、パソコンが入力の手助けをしてくれるようになります。
7. 非同期処理であるasyncとawaitを使った実践的な通信方法
これまでのコードでは、データを取得した後の処理を.thenという書き方でつないでいました。しかし、最新のプログラミングでは、より人間が読みやすいように、上から下へ順番に処理が進むように見える書き方が好まれます。それが、async(エイシンク)とawait(アウェイト)という仕組みです。
インターネットを介した通信は、一瞬で終わることもあれば、少し時間がかかることもあります。このように、処理の完了を待つ必要がある操作を非同期処理と言います。awaitを使うと、「通信が終わるまでここで少し待ってね」という命令をパソコンに出すことができます。この便利な書き方と、型定義を組み合わせた実践的なコードを見てみましょう。
import axios from 'axios';
interface Item {
code: string;
price: number;
}
async function fetchItemData() {
const response = await axios.get<Item>('https://api.example.com/item');
const item = response.data;
console.log(item.code);
console.log(item.price);
}
このプログラムでは、関数の前にasyncをつけ、通信を行う関数の前にawaitをつけています。そして、axios.get<Item>とすることで、取得した定数itemには、最初から商品の型であるItemがしっかりと適用されます。
この書き方を覚えることで、実際の現場で使われているような、綺麗で読みやすく、そして安全な通信プログラムを書くことができるようになります。型を明示的に定義することは、最初は手間に感じるかもしれませんが、未来の自分や一緒に開発する仲間を助ける大切な作業です。一つずつ丁寧に取り組んでいきましょう。