React + TypeScriptでモックAPIを叩いてみる　〜axios-mockのAPIで固定値を取得〜

# はじめに
みなさま、はじめまして！
かっきーと申します。

普段は業務でReact + TypeScriptで開発をしているフロントエンドエンジニアです！
（歴1年半で修行中の身です。）

私が携わってきた案件は、バックエンドとの結合ができていなくてもフロントエンドとしての実装を確認できる、モックデータとモックAPIが実装されている状態でした。
私自身の理解を深めるため、React + TypeScriptでモックデータの作り方・使い方を1から実践していこうと思います！

# 読者対象
- フロントエンド初学者
- React、TypeScript学習者
- フロントエンドやReact、TypeScriptに興味のある方 

# モックAPI、モックデータ
**※モックの前置き、説明が不要な方は飛ばしてください🙇‍♀️**

フロントエンドエンジニアは、その名の通り主に画面を作ります。
例えばエンドユーザに「家づくりにどのくらいの費用がかかるか」を伝える見積システム開発があるとします。
当然ですが、ユーザが見積内容を確認するために見積内容や金額、詳細を画面に表示する必要があります。

ただし、表示する金額は、フロントエンド側で計算をせずにバックエンドから取得した値を表示します。
（案件やシステムにもよりけりだとは思いますが、、）

イメージは以下です。
![スクリーンショット 2023-04-09 14.49.17.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1833388/bf0eb3e7-f71e-af59-a6d5-465a38170b2e.jpeg)
ただし上記図1は、フロントエンドとバックエンドの通り道ができており、結合が完了している状態です。

いざフロントエンド側として実装を始め画面を完成させたとしても、バックエンドの実装が完了し、結合しない限り画面に表示する値を受け取ることはできません。
![スクリーンショット 2023-04-09 14.49.44.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1833388/a2745af6-251d-759e-afdc-8e0ecaf92c8d.jpeg)
そこで、**モックデータ**を作成し**モックAPI**を使用することで、フロントエンドだけで図1の流れを実現することができます。

# 開発環境
- node v16.18.0
- React v17.0.1
- TypeScript v4.4.2

# 前提
フロントエンドの実装として、レイアウトは全て実装完了しているものとします。
実際に作ってみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1833388/bdbb8fd9-165a-b5eb-0061-2fca6fcf87ef.png)
また、バックエンドとのインターフェースも決まっており実装済みですが、前述した通りバックエンドは未実装という想定です。

# 準備
モックAPIを使うために必要なライブラリをインストールします。
```typescript
yarn add --dev axios-mock-adapter 
```

# モックデータの作成・使い方（基本）
見積金額取得APIで取得するデータを作成します。
```typescript:mock/dummydata.ts
export const dataAmount = {
  totalAmount: "50,000",
};
```

モックAPIを作成し、先ほど作成したモックデータをレスポンスとして受け取れるようにします。
```typescript:mock/api.ts
import MockAdapter from "axios-mock-adapter";
import { dataAmount } from "./dummydata";

export const mockStart = () => {
  const mockAxios = new MockAdapter(axios);

  // 基本パターン
  mockAxios.onGet("test/amount").reply(200, dataAmount);
};
```

上記モックは、どの選択肢の組み合わせでも固定値"5,000"を取得するようになっています。

実際に「見積る！」ボタンを押下し、5,000円を表示することができました。
また、取得API送信後、レスポンスデータをconsole.logに出力したところ、モックデータの応答が返ってきていることを確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1833388/959d67c1-f2bc-8169-771c-30c556c9addc.png)

# モックAPIの色々な書き方
### 選択肢によってモックデータを変更（制御）する
モックデータの作成・使い方（基本）の書き方は、どの選択肢でも必ず"5,000"が返ってくるようになっていました。
しかし、```reply```の中にモックデータ制御の処理を書き、データの出し分けや計算をすることも可能です。

```typescript:api.ts
import MockAdapter from "axios-mock-adapter";
import { dataAmount } from "./dummydata";

export const mockStart = () => {
  const mockAxios = new MockAdapter(axios);

  mockAxios.onGet("test/amount").reply((config) => {
    console.log("config", config);
    return [200, dataAmount];
  });
};
```

引数```config```の中身を確認すると、paramsに選択された値が入っています。
そのため、paramsを参照し選択された値に応じてreturn値を制御することが可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1833388/f5c3b44b-f023-fc81-74cf-eb8b257cf512.png)

以下制御コードです。
```typescript:mock/dummydata.ts
export const dataAmount = {
  totalAmount: "5,000",
};

export const osakaDataAmount = {
  totalAmount: "10,000",
};

export const hyogoDataAmount = {
  totalAmount: "8,000",
};
```

```typescript:mock/api.ts
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
import { dataAmount, osakaDataAmount, hyogoDataAmount } from "./dummydata";

mockAxios.onGet("test/amount").reply((config) => {
    if (config.params.place === "大阪" && config.params.age === "新築") {
      return [200, osakaDataAmount];
    } else if (
      config.params.place === "兵庫" &&
      config.params.area === "指定なし" &&
      config.params.age === "指定なし"
    ) {
      return [200, hyogoDataAmount];
    } else {
      return [200, dataAmount];
    }
  });
```
大阪、新築を選んだ場合、10,000円が表示されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1833388/e515841a-856e-c916-4bc0-4d7daf4b9f84.png)

### レスポンスエラーを発生させる
return値のステータスコードをエラーコードにすることで、エラーを発生させることができます。
paramsを参照し、場所を指定なしで選択した場合のみ、エラーメッセージを返すモックデータを作成しました。

```typescript:api.ts
import MockAdapter from "axios-mock-adapter";
import { dataAmount } from "./dummydata";

export const mockStart = () => {
  const mockAxios = new MockAdapter(axios);

  mockAxios.onGet("test/amount").reply((config) => {
    if (config.params.place === "指定なし") {
      return [400, { message: "場所を指定してください" }];
    }
    return [200, dataAmount];
  });
};
```
API送信側は以下のように実装しています。
```typescript:App.ts
  // 見積金額取得API
  const result = async () => {
    try {
      const response = await axios.get("test/amount", {
        params: inputDatas,
      });

      // 見積金額を設定
      setTotalAmount(response.data.totalAmount);
      // エラーメッセージ初期化
      setErrorMessage("");
    } catch (err) {
      if (axios.isAxiosError(err)) {
        // エラーメッセージを設定
        setErrorMessage(err.response?.data.message);
      }

      // 見積金額初期化
      setTotalAmount("ー");
    }
  };
```
受け取ったエラーメッセージをそのまま出力することができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1833388/1e67d59c-6169-6ee8-9e87-7df802df893d.png)

# 最後に
今回は1つのAPIと簡単なモックデータを実装しましたが、実際のシステムだとパラメータが何十個もあったり、複数のAPIを使用していると思います。

このAPIは結合ができているけど、こっちのAPIは未結合...というシチュエーションや、このパラメータ名は決まっているけどこっちのパラメータ名はT.B.D...というシチュエーションでも、暫定としてモックデータを実装することで画面表示を確認できるため、フロントエンドとしては完成させることができます。

APIに関しては、実装してみないとイメージしづらい部分だと思います。（私はいまだに慣れず苦手意識があります、、）
実際に自分で実装してみるとだいぶイメージが定着すると思うので、モックデータを触ったことがない方、バックエンド側と並行して開発しているためAPIを呼び出せない方、DBを直接触れる環境ではない方などがいらっしゃったら是非挑戦してみてください！

# 参考文献
https://www.npmjs.com/package/axios-mock-adapter

# 本記事のサンプルコード
https://github.com/MCArakaki/axios-mock-sample