😸

# 5.4 axios 入門(API 呼び出しの基本)

に公開

前回は Vue の基本文法を ToDo リストで学び、さらに Vuetify を使うと UI を統一的に作れることを確認した。
今回はいよいよ API 呼び出し に進み、Vue から Django REST Framework の API を叩いてデータを表示する。


1. プロジェクト構成(Vue 側)

今回も .env.* を含めたフル構成を前提に進める。

my-vue-app/
 ├─ .env.development       # 開発用環境変数
 ├─ .env.production        # 本番用環境変数
 ├─ index.html
 ├─ package.json
 ├─ vite.config.js
 └─ src/
     ├─ main.js
     ├─ App.vue
     ├─ router/
     │   └─ index.js
     ├─ plugins/
     │   └─ axios.js      # axios 共通設定
     ├─ views/
     │   ├─ OrderList.vue # API 呼び出し画面
     │   └─ Todo.vue      # 前回作った ToDo 画面
     ├─ store/
     │   └─ auth.js       # 次回以降で使う Pinia ストア
     └─ assets/

👉 今回の主役は views/OrderList.vue
ここで axios を使って API を呼び出し、Vuetify のテーブルに表示する。


2. axios とは?

Vue から API を叩く方法はいくつかあるが、業務システムでは axios をよく使う。

  • fetch API より簡単に書ける
  • 共通設定(baseURL, 認証ヘッダなど)をまとめやすい
  • レスポンスを JSON に変換する処理が不要

👉 つまり「業務システムに向いた実用的な HTTP クライアント」が axios。


3. API 接続先を .env に設定する

環境によって接続先は変わるため、.env.* にまとめておく。

  • .env.development
VITE_API_BASE_URL=http://localhost:8000/api
  • .env.production
VITE_API_BASE_URL=https://example.com/api

.env がどうやって読み込まれるのか?

Vue 3 (Vite) では、起動時に .env.* ファイルを自動で読み込み、
VITE_ で始まる変数だけimport.meta.env から参照できる。

  • npm run dev.env.development が読み込まれる
  • npm run build.env.production が読み込まれる
console.log(import.meta.env.VITE_API_BASE_URL);
// => http://localhost:8000/api (開発環境)
// => https://example.com/api (本番環境)

👉 なぜ VITE_ が必要か?
セキュリティ上、任意の環境変数をフロントに露出させないため。
Vite は「VITE_ で始まる変数だけ公開する」ルールで安全性を担保している。


4. axios 共通設定

// src/plugins/axios.js
import axios from "axios";

const apiClient = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  withCredentials: true, // Cookie 認証を使う場合
});

// 共通エラーハンドリング
apiClient.interceptors.response.use(
  (res) => res,
  (err) => {
    console.error("API Error:", err.response?.data || err.message);
    return Promise.reject(err);
  }
);

export default apiClient;

axios 共通設定の解説

4.1. なぜ共通設定が必要か?

業務システムでは API 呼び出しが大量に発生する。
そのたびに baseURL やエラーハンドリングを書くとコードが散らばる。

👉 axios インスタンスを作って共通設定をまとめれば、どのコンポーネントからでも統一ルールで通信できる。

4.2. 設定内容の解説

const apiClient = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL, // API の接続先を .env から参照
  withCredentials: true,                      // Cookie 認証を使う場合に必須
});
  • baseURL

    • API の共通プレフィックス
    • /orders/ を呼ぶとき最終的に http://localhost:8000/api/orders/ になる
    • .env で切替可能
  • withCredentials

    • Cookie 認証やセッショントークンをサーバーとやり取りするときに必要
    • DRF の SessionAuthentication を使う場合は必須
    • JWT のみなら不要

4.3. 共通エラーハンドリング

apiClient.interceptors.response.use(
  (res) => res,
  (err) => {
    console.error("API Error:", err.response?.data || err.message);
    return Promise.reject(err);
  }
);
  • interceptors で全レスポンスにフックできる
  • 今回は失敗時にログ出力のみ
  • 後で「401 → ログイン画面へ」などの処理を追加可能

4.4. 利用方法

共通設定した apiClient を使えば末尾だけ指定で呼び出せる。

import apiClient from "@/plugins/axios";

const res = await apiClient.get("/orders/");
// 実際には http://localhost:8000/api/orders/ を叩く

👉 これでコードの重複が減り、保守性が高まる。


5. API 呼び出し例(Vuetify テーブル)

Django 側の「受注一覧 API」を例に、axios で取得して Vuetify のテーブルに表示する。

src/views/OrderList.vue

<template>
  <v-container>
    <h2>受注一覧</h2>

    <!-- ローディング中 -->
    <v-progress-linear v-if="loading" indeterminate color="primary" />

    <!-- エラー -->
    <v-alert v-if="error" type="error">{{ error }}</v-alert>

    <!-- 一覧表示 -->
    <v-data-table
      v-if="!loading && !error"
      :items="orders"
      :headers="headers"
      class="elevation-1"
    />
  </v-container>
</template>

<script setup>

import { ref, onMounted } from "vue";
import apiClient from "@/plugins/axios";

const orders = ref([]);
const loading = ref(false);
const error = ref("");

const headers = [
  { title: "受注番号", key: "order_no" },
  { title: "顧客名", key: "customer_name" },
  { title: "金額", key: "amount" },
];

const fetchOrders = async () => {
  loading.value = true;
  error.value = "";
  try {
    const res = await apiClient.get("/orders/");
    orders.value = res.data.results;
  } catch {
    error.value = "データ取得に失敗しました";
  } finally {
    loading.value = false;
  }
};

onMounted(fetchOrders);

👉 ページ全体をリロードせず、API データが差し替わる。
👉 「SPA が動いている」感覚を実際に体験できる。


6. 実務的なポイント

  • ローディング表示
    → API 呼び出し中はスピナーやプログレスバーを出すと UX が良い

  • エラー表示
    → サーバーエラーやネットワークエラーをユーザーに伝える

  • ページネーション
    → DRF の標準レスポンス(results, count, next, previous)に対応


💡 AI 活用のポイント

  • 共通の API 呼び出しを使わせること
    axios の共通設定を作っていても、AI にコード生成を依頼すると 普通の相対パスで axios.get("/orders/") と書かれる ことがある。
    👉 「必ず共通の apiClient を使って」とプロンプトで明示するのが大事。

  • Vuetify のテーブルは万能ではない
    v-data-table は便利だが、幅調整がしづらい。基幹システムのようにカラム数が多い場合は適さないこともある。
    👉 そういうときは Vuetify に固執せず、共通のスタイルシートでテーブルを定義した方がやりやすい。

  • バージョン違いに注意
    Vuetify のテーブルヘッダ定義は Vue 3 だと title、Vue 2 系だと text
    👉 AI は古いバージョンのコードを返すことがあるので、自分の環境に合った書き方を指示する必要がある。

  • 前提(Django REST Framework)を忘れられることがある
    今回は DRF を前提にしているが、AI が忘れてしまい、ページネーション(results, count, next, previous)なしのレスポンスを想定したコードを出してくることがある。
    👉 「DRF 標準のページネーションレスポンスを前提に」と指示して、食い違いを防ぐことが重要。


まとめ

  • axios を導入し、Vue から Django REST API を呼び出せるようにした
  • .env で baseURL を環境ごとに管理
  • axios 共通設定で通信処理を統一化
  • Vuetify の v-data-table を使って一覧表示をリッチに表現
  • SPA は「API でデータを取得し、Vue が即時描画する」仕組み

👉 次回は Pinia(状態管理) を扱い、認証情報や一覧データをストアに保持して複数コンポーネントで共有する仕組みを学ぶ。

Discussion