2017/06/22

json-serverでREST APIモックサーバを立てテスト駆動開発する

フロントエンドの開発をやっているとAPIはできてないけど実装しなければならない、という状況が少なからずある。そんなときに便利なのがjson-serverというライブラリだ。

GitHubの説明にも「30秒以内にゼロコーディングでREST APIのモックサーバを立てる(いやマジで)」と書かれているとおり、jsonファイルを用意するだけでAPIサーバを立てられるというものだ。

当記事の目標は、json-serverの使い方を覚えて、Node.jsのテスト駆動開発をできるようにする。(もちろんフロントエンドでも使える)

json-serverの基本操作


インストール 〜 実行

まずはnpmでjson-serverをインストールする。
$ npm i -D json-server

あとは、エンドポイントとなる部分をjsonファイルに定義して、json-serverを起動する。
ここで定義したtasksがエンドポイントになる。
{
  "tasks": [
    { "id": 1, "title": "task01" },
    { "id": 2, "title": "task02" }
  ]
}

# json-serverをグローバルにインストールしている場合(--global or -gを付けてインストールした場合)
$ json-server --watch api.json

# プロジェクトディレクトリにインストールしている場合
$ ./node_modules/json-server/bin/index.js --watch api.json


これでAPIサーバが立ち上がった。
試しにtasksをGETしてみる。
$ curl localhost:3000/tasks
[
  { "id": 1, "title": "task01" },
  { "id": 2, "title": "task02" }
]


CRUD(GET, POST, PUT, DELETE)をする

全件取得は先ほどやったので、次はID指定でGETする。
$ curl localhost:3000/tasks/1
{
  "id": 1,
  "title": "task01"
}

このように、jsonファイルでidを指定しておくとendpoint/:idで取得することができる。

また、クエリストリングを使えば他のキーで検索することもできる。
$ curl localhost:3000/tasks?title=task02
[
  {
    "id": 2,
    "title": "task02"
  }
]


次にPOSTでレコードを登録する。
$curl -X POST localhost:3000/tasks -d title=task03
{
  "title": "task03",
  "id": 3
}

$ curl localhost:3000/tasks
[
  {
    "id": 1,
    "title": "task01"
  },
  {
    "id": 2,
    "title": "task02"
  },
  {
    "title": "task03",
    "id": 3
  }
]
レコードの登録ができた。このレコードは、先ほど作成したapi.jsonファイルに追記されている。


次にPUTでレコードを更新する。
$ curl -X PUT localhost:3000/tasks/2 -d title=task02-update
{
  "title": "task02-update",
  "id": 2
}

$ curl localhost:3000/taskse
[
  {
    "id": 1,
    "title": "task01"
  },
  {
    "title": "task02-update",
    "id": 2
  },
  {
    "title": "task03",
    "id": 3
  }
]


最後にDELETEでレコードを削除する。
$ curl -X DELETE localhost:3000/tasks/3
{}

$ curl localhost:3000/tasks
[
  {
    "id": 1,
    "title": "task01"
  },
  {
    "title": "task02-update",
    "id": 2
  }
]


これで基本的な操作をひと通り紹介した。

ただ、このままだとテストスクリプトを実行するときに「Type s + enter at any time to create a snapshot of the database」というメッセージで止まってしまう。
これは、json-serverをモジュールとして読み込んで使うことで回避できる。



テスト駆動開発できるようにする


以下のディレクトリ構成で話をすすめる。db.jsonはエンドポイントの定義、test.jsにmochaなどを使ったテスト、api.jsをエントリーポイントとする。
.
└── test
    ├── db.json
    ├── test.js
    └── api.js

{
  "tasks": [
    {
      "id": 1,
      "title": "task01"
    },
    {
      "id": 2,
      "title": "task02"
    }
  ],
  "users": [
    {
      "id": 1,
      "name": "taro"
    },
    {
      "id": 2,
      "name": "jiro"
    }
  ]
}
// 何かテキトーなテスト
function test() {
    describe('テストケース', () => {
        it('テスト内容', done => {
            (async () => {
                const res = await Request('localhost:3000/tasks');
                expect('テスト').to.be.true;
                done();
            })();
        });
    });
}

module.exports = test;
const path = require('path')
const jsonServer = require('json-server');
const test = require('./test');

const server = jsonServer.create();
const router = jsonServer.router(path.join(__dirname, './api/api.json'));
const middlewares = jsonServer.defaults();

server.use(middlewares);
server.use(router);
server.use(jsonServer.bodyParser);

server.listen(3000, () => {
    // この中でテストを実行する
    test();
});


setver.listenの中でテストを実行することで、テスト終了時にjson-serverのプロセスも落としてくれる。これでjson-serverを使ったテスト駆動開発ができるだろう。



おまけ: エンドポイントごとにyamlファイルを分割する


jsonを書くのは結構面倒くさい。また、仕様上1つのjsonファイルに複数のエンドポイントを定義するためファイルが大きくなりすぎてしまう。

そこで、yamlを使って、さらにエンドポイントごとにファイルを分割する方法を紹介する。
※ GETのみ実行可能。POSTやPUTなどはうまく実行できない
※ 対処方法がわかったら追記します


以降紹介する内容は、以下のようなディレクトリ構成を前提とする。
tasksとusersの2つのエンドポイントを用意する。
.
└── test
    ├── api
    │   ├── tasks.yml
    │   └── users.yml
    └── api.js

tasks:
  - id: 1
    title: 'task01'
  - id: 2
    title: 'task02'
users:
  - id: 1
    name: 'taro'
  - id: 2
    name 'jiro'


次に、yamlを読み込むためにjs-yamlをインストールする。
$ npm i -D js-yaml


そして、Node.jsで./test/api/*.ymlを読み込んで、json-serverが利用できる形式にするため、1つのオブジェクトにまとめる。
const fs = require('fs');
const path = require('path');
const yaml = require('js-yaml');

// ./test/api
const root = path.resolve('./test', 'api');

// ./test/api配下にあるyamlファイルの名前をエンドポイントとして読み込む
const api = fs.readdirSync(root).reduce((api, file) => {
    const endpoint = path.basename(file, path.extname(file));
    api[endpoint] = yaml.safeLoad(fs.readFileSync(root + '/' + file, 'utf-8'));

    return api;
}, {});

module.exports = () => api;


これで準備完了。あとはjson-serverを起動してうまく表示されるか確認する。
$ node ./test/api.js
  GET /tasks
GET /tasks 200 8.279 ms - 115
    ✓ タスク一覧を取得できる (40ms)


  1 passing (52ms)



参考サイト





以上

written by @bc_rikko

0 件のコメント :

コメントを投稿