LoginSignup
2
3
記事投稿キャンペーン 「2024年!初アウトプットをしよう」

Axiosをコンポーネント化して使いやすくしたい(TypeScript)

Last updated at Posted at 2024-01-08

APIをクライアントと結合するときによくAxiosを利用します。
今回Axiosを利用するにあたって共通化できるものは無いか考えました。
コピペで使えますので是非活用してみてください。

インストール

axiosのインストールが済んでい場合は実行してください。

コマンドプロンプト
$ npm install axios

ディレクトリ構成

今回解説するディレクトリです。必要に応じて変更して下さい。

ディレクトリ構成
---src
    |
    |---component 
    |      |---Apicomponent.tsx
    |
    |------api 
    |       |---Api.tsx
    |       
    |------screens
    |       |---App.tsx
    |
    |------Types
    |       |--Types.tsx

コンポーネント

コンポーネント部分を作っていきましょう。
AxiosRequestConfiginterfaceを見ると分かります。必要に応じて追加しましょう。

Apicomponent.tsx

import axios, { AxiosResponse, AxiosError, AxiosRequestConfig, AxiosInstance, Method } from 'axios'

const API_BASE_URL = 'http://localhost:xxxx' //繋ぎたいサーバに変更する

export const ApiComponent = async <T, R = AxiosResponse<T>>(
    method: Method, // 必須項目。get,delete,post,putなど利用可能
    url: string, //必須項目
    data?: any,  //BODY部分。送りたいデータを引数で渡す  
    headers?: Map<string, string>, //必要に応じて追加する
    ...requestConfig: any
): Promise<R> => {

    const config: AxiosRequestConfig = {
        ...requestConfig,
        baseURL: API_BASE_URL,
        url: url,
        method: method,
        data,
        timeout: 5000,
        headers: {
            'Content-Type': 'application/json',
            Authorization: '',
            ...headers,
        },
    }

    const axiosInstance: AxiosInstance = axios.create()

    axiosInstance.interceptors.response.use(
        (res: AxiosResponse<T>) => res,

        //AxiosErrorはここで処理を行う
        async (error: AxiosError) => {
            console.error('error:', error)
            
            if (error.response?.data) {
                return error.response?.data
            }
            
            throw Error('AxiosError');
        }
    )

    //ステータスコードによって処理を分岐可能にする
    switch ((await axiosInstance.request(config)).status) {
        //成功時はデータを返す
        case 200: return (await axiosInstance.request(config)).data

        //失敗時はエラーを出してあげる
        default:
            if (await axiosInstance.request(config) != null) {
                const err: { message: string } | null | undefined = await axiosInstance.request(config)
                if (err?.message) {
                    throw Error(err.message)
                }
            }
            throw Error('UNHANDLED_ERROR');
    }
}

Componentのコード解説

少しだけコード解説します。

今回利用しているのはinterceptorです。
説明は割愛しますがAxiosの使い方は複数あります。
下記を参考にして頂くと分かりやすいと思います。

APIの成功時は、axiosInstance.request(config)).dataに必要なデータが格納されるようにカスタマイズしました。

AxiosError

AxiosErrorは何故必要なのか?

例えば、サーバに繋がらない時にAxiosErrorが起きます。AxiosErrorを指定すると通常では分からないエラーも確認出来るようになります。

image.png

AxiosErrorについてQiitaに記事投稿されていました。参考にしてみてください。

コンポーネント参考記事

参考にした上記コードは下記記事になります。少しだけ改良させていただきました。

APIを一元管理したい

次にAPIのpathを一元管理出来るようにやってみます。
APIのコンポーネントの引数は第一引数にmethodと第二引数のurlは必須です。

Api.tsx

import { ApiComponent } from '../component/ApiComponent';
import { LoginData } from '../types/Types';

//第一引数と第二引数は必須 
export function Api() {
    return ApiComponent("get", "/")
}

//受け渡したいデータの型をコンポーネントの引数に渡すことも可能
export function LoginApi(loginData: LoginData) {
    return ApiComponent("post", "/login", loginData)
}

//ユーザAPI URLを繋げて利用もOK
export function UserApi(userID: string, loginData: LoginData) {
    return ApiComponent("post", "/user/" + userID ,loginData)
}


上記のやり方をすることで、APIの仕様が変わってもURLを変更するだけで済んだり、型の管理が分かりやすくなったと思います。

interface

interfaceの一例です。

Api.tsx

//型の例
export interface LoginData {
    userId: string
    passWord: string
}

メインの処理コード

メインの処理コードです。必要に応じて変更して下さい。

App.tsx

import React, { useEffect, useState } from 'react';
import { LoginApi } from '../api/Api';
import { LoginData } from '../types/Types';

const App = () => {

    const [loginData, setLoginData] = useState<LoginData>(
        {
            userId: "",
            passWord: ""
        }
    );


    const button = () => {

        //API実行処理部分
        //rejectは必要に応じて使ってください
        new Promise((resolve, reject) => {
            resolve(LoginApi(loginData)); //API実行
        })
            .then((res) => {
                //成功処理を書く
                console.log("resolve:", res)
            })
            .catch((res) => {
                //失敗処理を書く
                console.error("reject:", res)

                //AxiosErrorが表示出来る。
                if (res == "Error: AxiosError") {
                    if (res.data != null) {
                        console.error("AxiosError:", res.data)
                    } else {
                        console.error("AxiosError:", res)
                    }
                    return
                }

                console.error("Error:", res)

            });

    };

};

//---その他処理------//

APIの実行はresolveに引数を指定してthenとcatchで処理を分岐させてみました。
他にも方法はありますので、メインの処理は必要に応じて変えてみて下さい。

Promise.resolve()については下記ページを参考にしてみてください。

最後に

Axiosについて少し詳しくなりました。エラーを一つ出すのもやり方があり、勉強になりました。
また、Axiosはキャンセル処理も出来たりします。コンポーネント部分はまだまだ改良出来そうですね。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3