初心者でもシンプルに扱えるモックAPIツールを作ってみた

この記事は[LIFULL Advent Calendar 2021](https://qiita.com/advent-calendar/2021/lifull)の23日目の記事です。

# はじめに
こんにちは。株式会社LIFULLで、LIFULL HOME'SのiOS版の開発を担当している山手です。
入社からある程度年数も経ち、最近はチームメンバーの育成なども任せていただけるようになりました。
今回は、そんな中で感じた「負」を改善するために作ったオレオレツールを作ったお話です。

# 背景
エンジニア志望で入社してくる新卒エンジニアも各々のベースのスキルに大きな差があります。
学生時代からネイティブアプリをバリバリ開発してきた方からWeb系はやってたけどネイティブアプリの開発は初めてといった方まで様々な経験と期待と不安を持ってネイティブアプリ開発を**業務**としてスタートすることになります。
私がメンターとして受け持つ時に、メンティーにまず最初にネイティブアプリエンジニアとして習得してもらいたい知識・経験として「APIからのレスポンスを非同期で受け取って、レスポンスをもとに画面表示できる」ネイティブアプリケーションの作成を課題として出します。
意図としては、どんな形であれ自分で手を動かして0からネイティブアプリを構築したという経験を持って欲しいということと、API連携を行うネイティブアプリ開発は通常業務で必ず触れることになるためこの課題としています。
もちろんメンティーに課題だけ丸投げすることはなく、メンターがサポートしつつ設計から実装、コードレビューを通して一定の品質を目指していきます。

そんな課題を進める中で、ハードルとなるのは「API連携」の部分でした。
課題用のAPIなどが社内にはなく、課題用に用意する必要があります。
開発環境のAPIを利用するにも業務知識がまだ備わっていない新人エンジニアにはクエリが複雑です。
フリーで公開されているAPIを使うに理解の時間も必要で、API連携部分の開発を進めるよりも理解に時間を割かないといけなくなるため、もう少しお手軽にAPI連携の課題を実現できないかなと考えるシーンが出てきたのが今回の発端です。
(もちろんAPI自体への理解度を深める経験も必要ですが、ここではAPIとのやりとり部の実装に専念してほしいのです)

# 解決したい課題
- APIの用意の遅れで、クライアント開発が止まる
    - 環境用意などの手間も出来ればないと良い

APIの作業遅れで、クライアント側の開発が遅れることは実務でもよくありますね...
そんな時は、仕様書で定められた期待値をダミーデータとして与えてクライアントの開発を進められる限り進めるという選択を取ることが多いと思います。
今回も同様にダミーデータをクライアントで受け取れば開発を進めることができますが、APIへのリクエスト部分の実装は挑戦してほしいのでローカル環境にモックAPIサーバーを立ち上げれば課題は解決できるのではないかと考えました。

## 既存のモックAPIツール
既存のモックAPIツールを調べると下記のようなツールがよくヒットします。
- [GitHub - typicode/json-server](https://github.com/typicode/json-server)
- [Postman](https://www.postman.com/downloads/)
など

PostmanなんかはGUIでモック作成やリクエストなどまで全部盛りで、API開発の時にはよくお世話になりました。
json-serverは、モックデータを単一のjsonに記述してモックAPIを立ち上げることができ、データ取得以外にも追加、更新、削除なども行えるモックAPIツールです。

## json-serverが使えそう...
PostmanなどのGUIツールだと初期導入コストが少し高いので、元データのjsonを作ればすぐに立ち上げることができるjson-server今回の課題解決に使えそうでした。
json-serverでは``db.json``などモックレスポンスを記述するjsonファイルを用意する必要があります。

```db.json
{
  "posts": [
    { "id": 1, "title": "json-server", "author": "typicode" }
  ],
  "comments": [
    { "id": 1, "body": "some comment", "postId": 1 }
  ],
  "profile": { "name": "typicode" }
}
```
※公式ドキュメントより引用

このモックレスポンス用のjsonファイルは1つしか扱うことが出来ないので、エンドポイントが増えるとjsonファイルがどんどん肥大化していく問題を抱えています。

調べる中で、独自のスクリプトを組まれて複数のjsonファイルをマージして利用されているケースなどもありました。
[json-serverでエンドポイント毎にjsonファイルを分割する](https://qiita.com/nouka/items/47f26eecfd40712875e1)

## もう少しシンプルにモックAPIを立てたい
json-serverは、フィルター機能やデータの追加、削除なども備えておりモックAPIを手軽に立てるには十分な機能を備えています。
ただし、モックレスポンスを1つのjsonで管理すると肥大化しますし、いくらモックとは言っても仕様変更などで手を入れる時の手間は減らしたいものです。
クライアントの開発を進める上では、一旦期待するレスポンスを受け取れれば事が足りますのでそこまでの機能は不要かなと思いました。

今回の発端とはズレますが、もし業務などでAPI側の仕様が詰め切れておらず途中で仕様変更などが発生したときに既存の使用でモックAPIをもし作り込んでいたりしたらモック側も修正が必要になるので無駄な作業が生まれてしまいます。その修正をするならば、API側の作業に加わってAPIの実装を急いだ方が良いでしょう。

クライアントの開発を先に進めるには最低限、特定のエンドポイントを叩いた時に期待するレスポンス、任意のステータスコードを返却することができるモックAPIがあれば事が足りるなと考えました。
レスポンスを返却するだけなら静的ファイルを公開して、エンドポイントと対応するファイルを返却するだけで良いですが、ステータスコードを元に処理を変更するなんてことも場面によってはあります。
なので、任意のレスポンスボディーと任意のステータスコードを指定しやすいモックAPIツールがあればいいな...と思ったんですが、調べた中ではそんなツールはなく割とリッチな機能を持っているツールしかありませんでした。
無いなら作ればいいんじゃないですかね...

(簡単に作れるので、ツール化までされていないのが現状だと思います。)

# MockJsonAPI
はい、前置きが長くなりましたが今回の成果物です。
下記の個人リポジトリで公開しています。

[GitHub - MasamiYamate/MockJsonAPI](https://github.com/MasamiYamate/MockJsonAPI)

## 機能

- エンドポイントと紐づくjsonをAPIレスポンスとして返却する

以上です。非常にシンプルです。
ただ、特徴としてはエンドポイントの階層構造がレスポンスデータの階層構造とリンクしていることです。
httpサーバーで静的ファイルを配置するようなイメージと思っていただければと思います。

**【モックレスポンスのディレクトリへの配置構成】**

``` 
MockJsonAPI/
└ data/
    ├ driverlist.json
    └ drivers/
        └ license.json
```

**【対応するエンドポイント】**

```
http://localhost:3000/driverlist
http://localhost:3000/drivers/license
```
Postmanで``http://localhost:3000/driverlist``を呼び出してみた場合下記のようになります。
![スクリーンショット 2021-12-15 0.09.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114168/c4ab95df-5a5e-2a60-7422-d546b18d903c.png)

## 使い方
### Step1 レスポンス値を作りましょう
どのエンドポイントを叩いた時に、どのような期待値が返却されるかという仕様を決めましょう。
仕様が決まった or 仕様が既にあれば、仕様に則ったレスポンス値のjsonを作成します。
レスポンス値のjsonファイルは、第一階層は下記のようにします。

```
{
    "statusCode": 200,
    "body": {
        "list": [
            {
                "name": "hogehoge"
            },
            {
                "name": "fugafuga"
            }
        ]
    }
}
```
``statusCode``のValue値がレスポンスのHTTPステータスコードに割り当てられます。
``body``のValue値がレスポンス値として採用されます。


### Step2 リポジトリをクローンします
下記コマンドを実行してリポジトリを取得します。

```sh
$ git@github.com:MasamiYamate/MockJsonAPI.git
```

### Step3 依存パッケージを取得する
下記コマンドを実行して依存パッケージの取得を行います。
※前提としてnode.jsの実行環境が設定済みとします。

```sh
$ npm install
```

### Step3 モックレスポンスのjsonファイルを配置する
クローンした``MockJsonAPI``のディレクトリ配下に``data``ディレクトリがあるので、``data``ディレクトリ配下にモックレスポンスのjsonファイルを配置します。
エンドポイントの階層を作る場合は、階層ごとにディレクトリを作成します

```
MockJsonAPI/
└ data/
    ├ driverlist.json
    └ drivers/
        └ license.json
```
### Step4 実行
下記コマンドを実行します

```sh
$ npm start                    

> mock-json-api@1.0.0 start /Users/hoge/Documents/workspace/MockJsonAPI
> node index.js

Launch up prot 3000
```

実行後、3000番のポート番号で実行されます。
※実行するポート番号を変更する場合は、コードを弄ってください。

実行後、curlコマンドを叩くと下記のようなレスポンスになります。

```sh
MockJsonAPI % curl 'http://localhost:3000/driverlist' 
{"list":[{"name":"hogehoge"},{"name":"fugafuga"}]}%                             
MockJsonAPI % curl -LI 'http://localhost:3000/driverlist' -o /dev/null -w '%{http_code}\n' -s
200
MockJsonAPI % 
```

もし、リクエストしたエンドポイントに対応するjsonがない場合は404エラーで下記レスポンスが返却されます。

```sh
MockJsonAPI % curl 'http://localhost:3000/hogehoge'                                     
Not found path               
MockJsonAPI % curl -LI 'http://localhost:3000/hogehoge' -o /dev/null -w '%{http_code}\n' -s
404
MockJsonAPI % 
```

# 終わりに
今回作ったものは実装コードも非常にシンプルで、正直誰でも作れるレベルのものかと思います。
ただ、ディレクトリ階層とエンドポイントの階層がリンクしてjsonファイルを置くだけで扱えるので、機能の制約はありつつも``json-server``よりも気軽にモックAPIを立ち上げるツールを作る事が出来たと感じています。

開発経験が浅いエンジニアでも直感的に扱うことができるため、バックエンド側の知見がなくてもとりあえずモックAPIをより簡単に立ち上げることができます。
これを使ってAPI連携のアプリを作れても業務レベルで一人でバリバリ開発するにはまだまだ遠くHTTPの基礎知識など学ぶことは多々あると思いますが、自分の手で一歩踏み込んだネイティブアプリを作るという経験は得られると考えています。
まず駆け出しのタイミングで、難しいと感じて躓かずにものづくりの楽しさをより体感してもらえるようなサポートになればいいなと思います。

今回のように小さな発端からでも自分の手を動かして何かしら作ってみるのは続けていきたいですね。
最後までお読みいただきありがとうございました！