【非同期通信】HTTPリクエストライブラリ「axios」の使い方

2024.07.12

fetchでWordpressのREST APIでデータを取得しようと使い方を調べたところ「axios」というライブラリを見つけました。せっかく使ったので、基本的に使い方をメモしておこうと思います。

axiosがいいなと思ったのはfetchの場合は「response.json()」で取得したデータをJSONにパース(変換)するコードが必要ですが、自動的にパースしてくれるところです。

コードがシンプルになるのでいいですね!

axiosのインストール

axiosはパッケージでインストールします。下記はnpmの記述です。

npm install axios
# または
yarn add axios

基本的な使い方

GETリクエスト

ブラウザ(クライアント)がサーバーからデータを取得する際のコード。APIエンドポイントから取得する際に使うコードですね。

import axios from 'axios';

axios.get('https://api.example.com/data')
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.error('Error fetching data:', error);
  });

POSTリクエスト

ブラウザ(クライアント)がサーバーにデータを送信し、そのデータに基づいてサーバー側で何らかの処理(データの作成、更新など)を行う時に使用するもの。
ユーザーがフォームに入力したデータをサーバーに送信する場合やAPIエンドポイントにデータを送信する場合に使います。

import axios from 'axios';

const postData = {
  name: 'Takashi',
  age: 30
};

axios.post('https://api.example.com/data', postData)
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.error('Error posting data:', error);
  });

オプションの設定

オプションについて。インスタンスの作成は使いそう。

インスタンスの作成

あらかじめ設定しておいて、複数のリクエストに共通して使いまわせます。

import axios from 'axios';

const apiClient = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 1000,
  headers: { 'X-Custom-Header': 'foobar' }
});

apiClient.get('/data')
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.error('Error fetching data:', error);
  });

上の例では、下記のオプションを使っています。

baseURL: ベースとなるURLを設定ができる。
timeout: タイムアウト時間を設定できる(ミリ秒)。
headers: カスタムヘッダーを設定できる。

GETリクエストのオプション例

axios.get('https://api.example.com/data', {
  params: {
    id: 12345
  },
  headers: {
    'Authorization': 'Bearer token'
  },
  timeout: 5000
})
.then(response => {
  console.log(response.data);
})
.catch(error => {
  console.error('Error fetching data:', error);
});

POSTリクエストのオプション

axios.post('https://api.example.com/data', {
  name: 'John Doe',
  age: 30
}, {
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token'
  },
  timeout: 5000
})
.then(response => {
  console.log(response.data);
})
.catch(error => {
  console.error('Error posting data:', error);
});

インターセプト(interceptors)

僕は今まで使うことはなかったのですが、axiosにはHTTPリクエストやレスポンスの処理の前後にカスタムロジックを挟むことができる機能があるようです。

リクエストインターセプト

リクエストがサーバーに送信される前に処理を追加します。ChatGPTに聞いたところ例えば、認証トークンをヘッダーに追加する場合などに使うとのこと。

axios.interceptors.request.use(
  function (config) {
    // リクエスト送信前に何かを行う
    const token = 'your-token';
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  function (error) {
    // リクエストエラーの処理
    return Promise.reject(error);
  }
);

レスポンスインターセプト

レスポンスがアプリケーションに渡される前に処理を追加できます。特定のステータスコードに合わせて処理を行えるのは使い所がありそう。

axios.interceptors.response.use(
  function (response) {
    // レスポンスデータの処理
    return response;
  },
  function (error) {
    // レスポンスエラーの処理
    if (error.response && error.response.status === 401) {
      // 認証エラー処理
    }
    return Promise.reject(error);
  }
);

実際の使用例(WordPress Rest APIの取得)

下記はReactでWordpressのRest APIを取得した際の使用例です。
WordPressのカスタム投稿データを取得して、記事一覧を表示して個別のページに飛ぶためのリンクを作っています。

TypeScriptなので取得して使うデータに対してインターフェイスで型定義を予めしています。

import { useEffect, useState } from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom';

interface EmbeddedMedia {
  media_details: {
    sizes: {
      large?: {
        source_url: string;
      };
      medium?: {
        source_url: string;
      };
      thumbnail?: {
        source_url: string;
      };
    };
  };
}

interface Post {
  id: number;
  title: {
    rendered: string;
  };
  content: {
    rendered: string;
  };
  _embedded: {
    'wp:featuredmedia': EmbeddedMedia[];
  };
}


const WorkList = () => {
  const [posts, setPosts] = useState<Post[]>([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    axios.get('https://xxxxxx.com/wp-json/wp/v2/posttype?_embed')
      .then(response => {
        console.log(response.data);  // 取得したデータをコンソールに出力
        setPosts(response.data);
        setLoading(false);
      })
      .catch(error => {
        console.error('There was an error fetching the posts!', error);
        setLoading(false);
      });
  }, []);

  if (loading) {
    return <p>Loading...</p>;
  }

  return (
    <>
      <h2>Works</h2>
      <ul>
        {posts.map(post => {
          const featuredMedia = post._embedded?.['wp:featuredmedia']?.[0];
          const fullImageUrl = featuredMedia?.media_details?.sizes?.large?.source_url || 
                               featuredMedia?.media_details?.sizes?.medium?.source_url || 
                               featuredMedia?.media_details?.sizes?.thumbnail?.source_url;
          return (
            <li key={post.id}>
              <Link to={`/work/${post.id}`}>
                {fullImageUrl ? (
                  <img src={fullImageUrl} alt={post.title?.rendered} className="w-full h-auto" />
                ) : (
                  <span>画像が見つかりません</span>
                )}
                <h3>{post.title?.rendered}</h2>
                <p>Read more</p>
              </Link>
            </li>
          );
        })}
      </ul>
    </>
  );
};

export default WorkList;

一応こちらのコードを解説します。

読み込まれていない時に「setLoading(false)」を実行することで、ブラウザ上で「Loading…」を表示しています。本当はアニメーションを入れた方がいいですが、シンプルな方がわかりやすいのでとりあえずこれで。

WordPressの管理画面で登録したサムネイル画像のサイズによって保存される画像が異なるので下記のように複数サイズの呼び出しを念の為しています。
大きいサイズがなければ中くらいのサイズ。中くらいのサイズがなければさらに小さいサイズ…というふうに。何か他にいい方法ないかな…

const fullImageUrl = featuredMedia?.media_details?.sizes?.large?.source_url || 
                     eaturedMedia?.media_details?.sizes?.medium?.source_url || 
                     featuredMedia?.media_details?.sizes?.thumbnail?.source_url;

あとはルーティング機能のルートパラメータとWordpressの記事IDを使って、個別記事ページへのリンクをループで作っています。ここをクリックすると記事個別ページへ飛びます。


return (
  <li key={post.id}>
    <Link to={`/work/${post.id}`}>
      {fullImageUrl ? (
        <img src={fullImageUrl} alt={post.title?.rendered} className="w-full h-auto" />
      ) : (
        <span>画像が見つかりません</span>
      )}
      <h3>{post.title?.rendered}</h2>
      <p>Read more</p>
    </Link>
  </li>
);

まとめ

axios実際に使用すると簡単でした。fetchの時とあまり変わらず、コードがシンプルになって使いやすくなりました。

totop Page Top