TypeScriptでAxiosを使ったAPI通信の基本と型の付け方を徹底解説!初心者向け完全ガイド
生徒
「インターネットからデータを引っ張ってくるプログラムを作りたいのですが、TypeScriptではどうやるんですか?」
先生
「それにはAPI通信という仕組みを使います。Axiosという便利な道具とTypeScriptの型を組み合わせると、安全にデータを取得できますよ。」
生徒
「型をつけると、どんな良いことがあるんですか?」
先生
「中身が何かわからない箱に、あらかじめ名前のついたラベルを貼るようなものです。それでは、基本的な使い方を順番に見ていきましょう!」
1. API通信とAxiosの基本を知ろう
パソコンを触ったことがない方のために、まずはAPI通信という言葉から説明します。API通信とは、あなたのパソコンやスマートフォンから、インターネットの向こう側にある別の大きなコンピューター(サーバーと呼びます)に「このデータをください」とお願いをして、データを送ってもらう仕組みのことです。身近な例でいうと、スマートフォンの天気予報アプリを開いたときに、最新の天気情報が画面に表示されるのも、このAPI通信のおかげです。
プログラムの世界では、このようにお願いすることを「リクエスト」、返ってくるデータのことを「レスポンス」と呼びます。そして、このやり取りを劇的に簡単にしてくれる便利な道具がAxios(アクシオス)というプログラムの部品です。Axiosを使うことで、初心者でも短い命令を書くだけで、世界中のサーバーと通信をすることができるようになります。
2. なぜTypeScriptで通信に型をつけるのか
JavaScriptという言葉を聞いたことがあるかもしれませんが、TypeScriptはそのJavaScriptの親戚であり、最大の特徴は型(かた)という仕組みがあることです。型とは、プログラムの中で扱うデータが「数字なのか」「文字なのか」「それとも複雑な情報の集まりなのか」を、あらかじめきっちりと決めておくルールのことです。
インターネットから届くデータは、そのままでは中身が何であるかプログラムにはわかりません。中身がわからないまま処理を進めると、後から「文字だと思っていたのに数字だった」というような勘違いが起きて、プログラムが突然動かなくなってしまう原因になります。あらかじめ「こういう形式のデータが届きますよ」という型を定義してAxiosに教えてあげることで、パソコンが中身をチェックしてくれるようになり、間違いを未然に防ぐことができます。これが安全なプログラム作りの第一歩です。
3. Axiosを準備して一番簡単な通信をしてみよう
まずは、実際にAxiosを使ってデータを取得する最もシンプルなプログラムを見てみましょう。ここでは、インターネット上にあるテスト用のサーバーから、ユーザーの情報を1人分だけもらってくる処理を書きます。まだ型のことは深く考えず、どのように通信が行われるかの流れを掴んでください。
import axios from "axios";
function getBasicData() {
axios.get("https://jsonplaceholder.typicode.com/users/1")
.then(response => {
console.log(response.data);
});
}
getBasicData();
このプログラムを実行すると、画面に以下のような結果が出力されます。これがサーバーから届いた生の情報です。
{
id: 1,
name: "Leanne Graham",
username: "Bret",
email: "Sincere@april.biz"
}
プログラムの解説をします。最初に書かれているimportというのは、Axiosという道具箱をプログラムの中に持ってくるための宣言です。そしてaxios.getという命令を使って、指定したインターネットの住所(URL)にデータをくださいとお願いしています。データが無事に届くと、thenという部分が動き出し、届いた中身を画面に表示します。これがすべてのAPI通信の基本形になります。
4. 届くデータに型を定義する方法
先ほどのプログラムでは、届いたデータの中に「名前(name)」や「メールアドレス(email)」が入っていることが、画面に表示されるまでわかりませんでした。これでは困るので、あらかじめ「このようなデータが返ってきます」という設計図を作ります。この設計図のことをTypeScriptではインターフェース(interface)と呼びます。
初心者の方向けに例えると、これは書類のフォーマットを作る作業に似ています。名前を書く欄は文字で、番号を書く欄は数字、というように枠組みをあらかじめ決めておくのです。それでは、ユーザー情報の型を定義してみましょう。
interface User {
id: number;
name: string;
username: string;
email: string;
}
ここで使われているnumberは「数字のデータが入ります」という意味で、stringは「文字のデータが入ります」という意味です。このように、それぞれの項目にどんな種類のデータが入るかを指定してあげることで、プログラムが非常に分かりやすくなり、入力ミスを防ぐことができます。
5. Axiosに型を設定して安全にデータを取得する
作成した設計図(型)を、実際にAxiosの通信プログラムに組み込んでみましょう。Axiosでは、axios.getのすぐ後ろに、小なり記号と大なり記号を使って<User>のように型を書き加えることで、通信結果に型をあてはめることができます。これを専門用語でジェネリクスと言いますが、今は「型を当てはめるための目印」と覚えておけば大丈夫です。
import axios from "axios";
interface User {
id: number;
name: string;
username: string;
email: string;
}
function getUserWithType() {
axios.get<User>("https://jsonplaceholder.typicode.com/users/1")
.then(response => {
const user = response.data;
console.log("ユーザーの名前は " + user.name + " です。");
console.log("メールアドレスは " + user.email + " です。");
});
}
getUserWithType();
このプログラムを実行すると、以下のように整理された結果が画面に表示されます。
ユーザーの名前は Leanne Graham です。
メールアドレスは Sincere@april.biz です。
型をつけたことによって、変数userの直後にドットを打ち込むだけで、パソコンが「nameやemailが使えますよ」と教えてくれるようになります。もし存在しない項目を間違えて書いてしまった場合は、実行する前にパソコンが赤線を引いて間違いを指摘してくれるため、開発がとてもスムーズになります。
6. 複数のデータが詰まった配列の型付け
ここまでは1人分のデータを取得してきましたが、実際のアプリ開発では、何十人分ものデータをまとめて一度に取得することの方が多いです。このように、複数の同じ種類のデータが縦一列に並んだものを、プログラミングでは配列(はいれつ)と呼びます。
TypeScriptで配列の型を表すときは、先ほど作った型の後ろに四角いカッコを二つ並べてUser[]と書きます。これは「ユーザー情報の書類が複数枚集まった束」という意味になります。全員分の名前を一覧で表示するプログラムを見てみましょう。
import axios from "axios";
interface User {
id: number;
name: string;
username: string;
email: string;
}
function getUserList() {
axios.get<User[]>("https://jsonplaceholder.typicode.com/users")
.then(response => {
const users = response.data;
users.forEach(user => {
console.log("会員番号: " + user.id + ", 会員名: " + user.name);
});
});
}
getUserList();
このプログラムを実行すると、複数のデータが順番に処理されて、全員分の情報が一覧で出力されます。
会員番号: 1, 会員名: Leanne Graham
会員番号: 2, 会員名: Ervin Howell
会員番号: 3, 会員名: Clementine Bauch
forEachというのは、配列の中身を最初から最後まで一つずつ取り出して、同じ処理を繰り返すための命令です。ここでも型がしっかりと効いているため、取り出されたuserの一つひとつに対して安全にアクセスすることができます。
7. 通信が失敗したときのことを考えよう
インターネットの通信は、いつも必ず成功するとは限りません。パソコンの電波が切れてしまったり、相手のサーバーが故障して止まっていたり、指定したURLが間違っていたりすると、通信は失敗してしまいます。プログラミングでは、この失敗のことをエラー(例外)と呼びます。
エラーが発生したときに何も対策をしていないと、プログラムが途中で完全に固まってしまい、使っている人が困ってしまいます。そのため、通信が失敗したときの受け皿を用意しておく必要があります。Axiosでは、成功したときのthenの後ろに繋げる形で、catchという命令を書くことでエラーを捕まえることができます。
import axios from "axios";
function getWithErrorHandling() {
axios.get("https://jsonplaceholder.typicode.com/invalid-url")
.then(response => {
console.log("成功しました", response.data);
})
.catch(error => {
console.log("通信に失敗しました。原因を確認してください。");
if (axios.isAxiosError(error)) {
console.log("エラーの状態コード: " + error.response?.status);
}
});
}
getWithErrorHandling();
わざと間違ったURLを指定しているため、このプログラムを実行すると安全にエラーが処理され、画面には以下のように表示されます。
通信に失敗しました。原因を確認してください。
エラーの状態コード: 404
axios.isAxiosErrorという命令は、発生したエラーが「Axiosの通信によるものなのかどうか」を正しく見極めるためのTypeScriptの便利な機能です。これを使うことで、エラーの原因がネットワークの問題なのか、それ以外のプログラムのミスなのかを明確に区別して、原因追究を早く行うことができるようになります。
8. モダンで読みやすいasyncとawaitを使った書き方
最後に、より新しくて見やすい通信の書き方を紹介します。これまではthenやcatchを使って、数珠つなぎのようにプログラムを書いてきましたが、通信が複雑になるとだんだんと右側にプログラムがずれていき、読みづらくなってしまう欠点がありました。そこで登場したのが、async(エイシンク)とawait(アウェイト)という仕組みです。
これらを使うと、インターネット通信という「少し時間がかかる処理」があるにもかかわらず、上から下へ普通のプログラムと同じようにすっきりと流れるようにコードを書くことができます。現在のアプリ開発では、こちらの手法が主流になっています。
import axios from "axios";
interface Todo {
userId: number;
id: number;
title: string;
completed: boolean;
}
async function fetchTodoData() {
try {
const response = await axios.get<Todo>("https://jsonplaceholder.typicode.com/todos/1");
const todo = response.data;
console.log("タスク名: " + todo.title);
console.log("完了状態: " + todo.completed);
} catch (error) {
console.log("データの取得中に問題が発生しました。");
}
}
fetchTodoData();
このプログラムを実行すると、新しく定義したToDoタスクの型に従って、以下のような結果が出力されます。
タスク名: delectus aut autem
完了状態: false
書き方のポイントは、関数の前にasyncと書き、Axiosの通信命令の前にawaitと書くことです。これによって、通信が終わるまでその行でプログラムが優しく待機してくれるようになります。また、エラーの対策にはtryとcatchという枠組みを使い、成功するはずの処理をtryの部屋に、失敗したときの処理をcatchの部屋に分けて書くため、見た目が非常に整理されて初心者にも読みやすい綺麗なコードになります。