Web API を操作してみよう


データ送受信のフォーマット

Web API でのデータのやり取りでは、ほとんどの場合、JSON (JavaScript Object Notation) という軽量なデータ交換フォーマットが使われます。

JSON の例

{
  "id": 1,
  "title": "Vue 3 入門",
  "author": "山田 花子",
  "tags": ["frontend", "web"],
  "published": true
}

JSON は JavaScript のオブジェクトに似た構造をしており、人間にとっても読みやすく、プログラムにとっても扱いやすいという特徴があります。


Web API によるデータ取得例

Vue 3 の Composition API での例を見て行きましょう。

Vue 3 の Composition API では リアクティブな状態を管理するために ref を、コンポーネントが初期化されたときにアクションを実行するために onMounted を使用するのが一般的です。

また、データの型安全性を確保するために TypeScript を積極的に活用します。

fetch API でデータ取得

ここでは、簡単な例として、公開サイト (仮に example.com とします) から投稿データを取得する処理を書いてみます。

なお fetch API は 非同期処理 を行います。これは、APIからの応答を待つ間に、他の処理をブロックせずに実行できることを意味します。

<template>
  <h1>投稿一覧</h1>

  <div v-if="isLoading">
    <p>データを読み込み中...</p>
  </div>
  <div v-else-if="error">
    <p style="color: red;">エラー: {{ error }}</p>
  </div>
  <div v-else>
    <div v-for="post in posts" :key="post.id" class="post-item">
      <h3>{{ post.title }}</h3>
      <p>{{ post.body }}</p>
      <small>User ID: {{ post.userId }}</small>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'

// 取得する投稿データの型定義
interface Post {
  userId: number;
  id: number;
  title: string;
  body: string;
}

// ref() を使ったリアクティブな変数群を定義
// 投稿データを保持する配列。Post型の配列であることを明示
const posts = ref<Post[]>([])
// データ取得中かどうかを示すフラグ。true を初期値にセットすることで boolean 型と推論される
const isLoading = ref(true)
// エラーメッセージ。string または null 型であることを明示
const error = ref<string | null>(null)

// 投稿データを取得する関数
const fetchPosts = async () => {
  // 取得開始時にローディングフラグを立てる
  isLoading.value = true
  // 以前のエラーをクリア
  error.value = null

  try {
    // Web API を呼び出し
    const response = await fetch('https://example.com/posts')
    
    // HTTP ステータスコードが 200 番台 (成功) 以外の場合
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`)
    }

    // 応答を JSON としてパース。Post 型の配列として型付け 
    const data: Post[] = await response.json()
    // 取得したデータをリアクティブな ref に代入 (最初の 5 件のみ表示)
    posts.value = data.slice(0, 5)
  
  // エラーが発生した場合
  } catch (e: any) {
    error.value = `データの取得に失敗しました: ${e.message}`
    console.error("Fetch error: ", e)
  
  // 成功 or 失敗 (エラー) に関わらず実行される
  } finally {
    // ローディングフラグを下げる
    isLoading.value = false
  }
}

// コンポーネントがマウントされたときに fetchPosts を呼び出す
onMounted(() => {
  fetchPosts()
})
</script>

<style>
  .post-item {
    border: 1px solid #ccc;
    padding: 10px;
    margin-bottom: 10px;
    border-radius: 5px;
  }
</style>

コードの解説

  1. テンプレートでのディレクティブ:
    • v-if, v-else-if, v-else: これらのディレクティブは条件付きレンダリングに使用され、isLoadingerror の状態に応じて、読み込み中メッセージ、エラーメッセージ、または実際の投稿データを表示します。
    • v-for="post in posts" :key="post.id": このディレクティブはリストレンダリングに使用され、posts 配列を反復処理して各投稿を表示します。:key="post.id" は、Vueがリストアイテムを効率的に追跡するために非常に重要です。
  2. <script setup lang="ts">: これは Vue 3 の <script setup> 構文です。Composition API の使用を簡素化し、lang="ts" によって TypeScript を使用することを示します。
  3. import { ref, onMounted } from 'vue': リアクティブな変数を作成するための ref と、コンポーネントのライフサイクルイベント (マウント時) をフックするための onMounted をインポートしています。
  4. interface Post: 取得する投稿データの構造を TypeScript の interface で定義しています。これにより、データの型が明確になり、コードの安全性が高まります。
  5. const posts = ref<Post[]>([]): 取得した投稿データを格納するための リアクティブな変数 postsref を使って定義しています。<Post[]> とすることで、Post 型の配列であることを明示しています。ref で作成された変数の値にアクセスしたり変更したりするには、.value を使用することに注意してください (例: posts.value = ...)。isLoadingerror も同様にリアクティブな状態として管理します。
  6. const fetchPosts = async () => { ... }: API 呼び出しを処理する 非同期関数 です。
    • await fetch(...): 指定された URL に対して HTTP GET リクエストを送信し、応答を待ちます。await キーワードは、非同期処理が完了するまで次の行の実行を一時停止します。
    • response.ok: HTTP ステータスコードが 200 番台 (成功) かどうかをチェックします。
    • await response.json(): 応答のボディを JSON としてパースします。これも非同期処理なので await が必要です。
    • try...catch...finally: エラーハンドリングのための構文です。ネットワークエラーや API からのエラー応答など、問題が発生した場合に適切に処理します。
  7. onMounted(() => { fetchPosts() }): これは Composition API の ライフサイクルフック です。onMounted 内の関数は コンポーネントがマウントされたとき (つまり DOM に追加された時) に一度だけ 実行されます。これは初期データを取得するのに理想的な場所です。

重要なポイント

  • JavaScript と TypeScript で違いはあるか - Web API の呼び出し方: fetch API の基本的な呼び出し方 (fetch('URL')response.json()) は、プレーンな JavaScript でも TypeScript でも変わりません。
    • TypeScript を使うことで、取得するデータの構造を型で定義し、より安全で保守性の高いコードを書けるようになるというメリットがあります。
  • エラーハンドリング: 実際のアプリでは、ネットワークエラー、サーバーエラー、データの形式が不正な場合など、様々なエラーが発生する可能性があります。
    • try...catch ブロックを使って、これらのエラーに適切に対応することが重要です。
  • 非同期処理: Web API との通信は時間が掛かります。これを同期処理すると、画面が固まってしまい、ユーザー体験が悪くなります。そこで Web API は通常、非同期で処理されます。
    • async/await 構文は、非同期処理を同期的なコードのように読みやすく書くための強力なツールです。

Web API との連携は、 Web アプリ開発において不可欠なスキルです。この章で学んだことを活かして、様々な外部サービスと連携するアプリの構築に挑戦してみましょう !


Comments or feedbacks are welcomed and appreciated.