json-serverの使い方まとめ【解説】

# json-serverとは

json-serverは、簡単にREST APIを構築できるツールです。

ローカルマシン上にJSONファイルを置くだけで、RESTfulなAPIを作成し、GET、POST、PUT、DELETEなどのHTTPリクエストを使用してデータの取得、作成、更新、削除を行うことができます。

json-serverを使用すると、サーバーサイドのプログラミング言語やデータベースを必要とせず、フロントエンドの開発者がAPIの動作をテストしたり、簡単なデモアプリケーションを作成するのに便利です。

また、json-serverは簡単に拡張することができ、ルーティングの設定やフック機能を利用することで、より高度なAPIを作成することもできます。

## json-serverのユースケース

json-serverは、以下のようなタイミングで使用することができます。

1. `モックサーバー`：json-serverを使用することで、バックエンドの開発者がまだ実装されていないAPIにアクセスすることができます。これにより、フロントエンドの開発者はアプリケーションの開発を進めることができます。

2. `テスト`：json-serverを使用することで、実際のデータを使用してテストを行うことができます。これにより、APIの動作をテストすることができ、エラーや問題がある場合には、早期に発見することができます。

3. `データの共有`：json-serverを使用することで、複数の開発者が同じデータを共有し、実際にデータを取得、作成、更新、削除することができます。これにより、APIの動作をテストすることができ、開発の進行状況を共有することができます。

# json-serverの使い方

## 事前準備

以下の事前準備が必要です。

1. `Node.jsのインストール`：json-serverはNode.jsで動作するので、Node.jsをインストールする必要があります。
    - [【Windows/Mac/Linux（Ubuntu）】Node.jsインストール方法](https://qiita.com/ryome/items/eec08b28aff294e8c3d6)
2. `Node.jsプロジェクト作成`：`npm init --yes` コマンドを実行して、Node.jsプロジェクトを作成する。
3. `json-serverのインストール`：`npm install json-server` コマンドまたは `npm install --save-dev json-server` コマンドを実行して、json-serverをインストールします。

## JSONファイル作成

以下のJSONファイル（`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-server起動

`json-server` を起動するには、以下のコマンドを実行します。

```
json-server --watch <jsonファイル名> -p <ポート番号>
```

例えば、`json-server --watch db.json` コマンドを実行して、json-serverを起動します。

- コマンド
```
npx json-server --watch db.json -p 3000
```
- 実行例
```
$ npx json-server --watch db.json -p 3000

  \{^_^}/ hi!

  Loading db.json
  Done

  Resources
  http://localhost:3000/posts
  http://localhost:3000/comments
  http://localhost:3000/profile

  Home
  http://localhost:3000

  Type s + enter at any time to create a snapshot of the database
  Watching...
```

これで、`json-server` が [http://localhost:3000](http://localhost:3000) で起動し、`db.json` ファイルの内容が `/posts`, `/comments`, `/profile` でアクセス可能になります。

以下は確認の例です。

- 登録（POST）
```
$ curl -H "Content-Type: application/json" -d '{"title":"test"}' -X POST http://localhost:3000/posts
{
  "title": "test",
  "id": 2
}
```

- 更新（PUT）
```
$ curl -H "Content-Type: application/json" -d '{"title":"test update"}' -X PUT http://localhost:3000/posts/1 
{
  "title": "test update",
  "id": 1
}
```

- 削除（DELETE）
```
$ curl -H "Content-Type: application/json" -X DELETE http://localhost:3000/posts/1
{}
```

- 取得（GET）
```
$ curl -X GET http://localhost:3000/posts
[
  {
    "title": "test",
    "id": 2
  }
]
```

## データのフィルタリング、ソーティング、ページング

### データのフィルタリング

キーワードに一致するレコードを検索する場合は、`q` クエリパラメータを使用します。

例えば、`GET /posts?q=lorem` のようにリクエストを送信すると、`title` または `body` フィールドに `lorem` を含む全ての投稿が返されます。

`db.json` ファイルを以下のように修正します。

```
{
  "posts": [
    {
      "title": "lorem",
      "id": 1
    },
    {
      "title": "testlorem",
      "id": 2
    },
    {
      "title": "test2",
      "id": 3
    }
  ],
  "comments": [],
  "profile": {
    "name": "typicode"
  }
}
```

- コマンド
```
curl -X GET http://localhost:3000/posts?q=lorem
```

- 実行例
```
$ curl -X GET http://localhost:3000/posts?q=lorem
[
  {
    "title": "lorem",
    "id": 1
  },
  {
    "title": "testlorem",
    "id": 2
  }
]
```

### データのソーティング

データのソートには、`_sort` と `_order` クエリパラメータを使用します。

`_sort` クエリパラメータには、ソートするフィールドを指定し、`_order` クエリパラメータには、ソートの順序（asc または desc）を指定します。

例えば、以下のようにリクエストを送信すると、 `id` フィールドで昇順にソートされた全てのレコードが返されます。

`db.json` ファイルを以下のように修正します。

```
{
  "posts": [
    {
      "title": "lorem",
      "score": 50,
      "id": 1
    },
    {
      "title": "testlorem",
      "score": 80,
      "id": 2
    },
    {
      "title": "test2",
      "score": 10,
      "id": 3
    }
  ],
  "comments": [],
  "profile": {
    "name": "typicode"
  }
}
```

- コマンド
```
curl -X GET 'http://localhost:3000/posts?_sort=id&_order=asc'
```

- 昇順取得の実行例
```
$ curl -X GET 'http://localhost:3000/posts?_sort=score&_order=asc'
[
  {
    "title": "test2",
    "score": 10,
    "id": 3
  },
  {
    "title": "lorem",
    "score": 50,
    "id": 1
  },
  {
    "title": "testlorem",
    "score": 80,
    "id": 2
  }
]
```

- コマンド
```
curl -X GET 'http://localhost:3000/posts?_sort=id&_order=desc'
```

- 降順取得の実行例
```
$ curl -X GET 'http://localhost:3000/posts?_sort=id&_order=desc'
[
  {
    "title": "test2",
    "score": 10,
    "id": 3
  },
  {
    "title": "testlorem",
    "score": 80,
    "id": 2
  },
  {
    "title": "lorem",
    "score": 50,
    "id": 1
  }
]
```

### データのページング

データのページングには、`_start` と `_limit` クエリパラメータを使用します。

`_start` クエリパラメータには、ページの開始位置を指定し、`_limit` クエリパラメータには、1 ページあたりのレコード数を指定します。

例えば、以下のようにリクエストを送信すると、2 番目のページの全ての投稿が返されます。

`db.json` ファイルを以下のように修正します。

```
{
  "posts": [
    {
      "title": "lorem",
      "score": 50,
      "id": 1
    },
    {
      "title": "testlorem",
      "score": 80,
      "id": 2
    },
    {
      "title": "test2",
      "score": 10,
      "id": 3
    },
    {
      "title": "test3",
      "score": 10,
      "id": 4
    },
    {
      "title": "test4",
      "score": 99,
      "id": 5
    }
  ],
  "comments": [],
  "profile": {
    "name": "typicode"
  }
}
```

- コマンド
```
curl -X GET 'http://localhost:3000/posts?_start=2&_limit=2'
```

- 実行例
```
$ curl -X GET 'http://localhost:3000/posts?_sort=id&_order=desc'
[
  {
    "title": "test2",
    "score": 10,
    "id": 3
  },
  {
    "title": "test3",
    "score": 10,
    "id": 4
  }
]
```

## json-serverのルーティングを設定

`json-server` には、 `--routes` オプションがあります。

`--routes` オプションを使用すると、APIのエンドポイントを変更したり、新しいエンドポイントを追加することができます。

以下の `routes.json` ファイルを作成します。

```
{
  "/api/*": "/$1",
  "/posts/:text/q": "/posts?q=:text"
}
```

上記の例では、APIのエンドポイントを変更しています。

例えば、`/api/posts` は、 `/posts` にマッピングされます。

`json-server` をルーティングを設定して起動するには、以下のコマンドを実行します。

```
json-server --watch <jsonファイル名> -p <ポート番号> --routes <jsonファイル名>
```

`--routes` オプションを指定して以下のように `json-server` を起動します。

- コマンド
```
npx json-server --watch db.json -p 3000 --routes routes.json
```

- 実行例
```
$ npx json-server --watch db.json -p 3000 --routes routes.json

  \{^_^}/ hi!

  Loading db.json
  Loading routes.json
  Done

  Resources
  http://localhost:3000/posts
  http://localhost:3000/comments
  http://localhost:3000/profile

  Other routes
  /api/* -> /$1
  /posts/:text/q -> /posts?q=:text

  Home
  http://localhost:3000

  Type s + enter at any time to create a snapshot of the database
  Watching...
```

`/api/posts` にリクエストを送ると、 `/posts` が実行され、レスポンスを返します。

- コマンド
```
curl -X GET 'http://localhost:3000/api/posts'
```

- 実行例
```
$ curl -X GET 'http://localhost:3000/api/posts'
[
  {
    "title": "lorem",
    "score": 50,
    "id": 1
  },
  {
    "title": "testlorem",
    "score": 80,
    "id": 2
  },
  {
    "title": "test2",
    "score": 10,
    "id": 3
  },
  {
    "title": "test3",
    "score": 10,
    "id": 4
  },
  {
    "title": "test4",
    "score": 99,
    "id": 5
  }
]
```

`/posts/test/q` にリクエストを送ると、 `/posts?q=test` （「test」が含まれたレコードのみ返す） が実行され、レスポンスを返します。

- コマンド
```
curl -X GET 'http://localhost:3000/posts/test/q'
```

- 実行例
```
$ curl -X GET 'http://localhost:3000/posts/test/q'
[
  {
    "title": "testlorem",
    "score": 80,
    "id": 2
  },
  {
    "title": "test2",
    "score": 10,
    "id": 3
  },
  {
    "title": "test3",
    "score": 10,
    "id": 4
  },
  {
    "title": "test4",
    "score": 99,
    "id": 5
  }
]
```

# json-serverをjsで起動

## index.jsファイル作成

以下のindex.jsファイルを作成します。

```js:index.js
const jsonServer = require('json-server')
const server = jsonServer.create()
const router = jsonServer.router('db.json')
const middlewares = jsonServer.defaults()

server.use(middlewares)
server.use(router)
server.listen(8000, () => {
  console.log('JSON Server is running')
})
```

上記のコードでは、 json-server の `createメソッド` を使用してサーバーを作成し、 `routerメソッド` を使用して `db.json` ファイルをルーティングします。
`defaultsメソッド` を使用して、標準のミドルウェアを設定し、 `listenメソッド` を使用して、 `ポート番号8000` でサーバーを起動します。

## json-serverをjsで起動する

以下のコマンドを実行して、`json-server` を起動します。

- コマンド
```
node index.js
```
- 実行例
```
$ node index.js
JSON Server is running
```

これで、`json-server` が [http://localhost:8000](http://localhost:8000) で起動し、`db.json` ファイルの内容が `/posts`, `/comments`, `/profile` でアクセス可能になります。

## json-serverをモック化

`json-server` は、 `Express.js` に基づいており、リクエストの前後にカスタム処理を実行したり、認証を実装したりすることができます。

以下のコードは、 `GET` , `PUT` , `POST` , `DELETE` のHTTPメソッドに対応したモックサーバを作成する例です。

リクエストのHTTPメソッドに応じて、リクエストのbodyをそのままレスポンスとして返す処理が実装されています。

```js:index.js
const jsonServer = require('json-server');
const server = jsonServer.create();
const middlewares = jsonServer.defaults();

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

server.get('*', (req, res) => {
    res.status(200).json(req.query);
  });
  
  server.post('*', (req, res) => {
    res.status(201).json(req.body);
  });
  
  server.put('*', (req, res) => {
    res.status(200).json(req.body);
  });
  
  server.delete('*', (req, res) => {
    res.status(204).end();
  });

server.listen(8000, () => {
  console.log('JSON Server is running');
});
```

上記の例では、*を使用して全てのパスに対応させています。

`GET` メソッドの場合、リクエストの `queryオブジェクト` をレスポンスとして返します。

`PUT` , `POST` メソッドの場合、リクエストの `bodyオブジェクト` をレスポンスとして返します。

`DELETE` メソッドの場合、 レスポンスにbodyが必要ないため、`end()メソッド` を使用しています。

以下は、curlコマンドを使用して、上記のモックサーバにリクエストを送信し、レスポンスを確認する例です。

- GET
```
$ curl -X GET 'http://localhost:8000/test?test=123'
{
  "test": "123"
}
```

- POST
```
$ curl -H "Content-Type: application/json" -d '{"title":"test"}' -X POST http://localhost:8000/posts
{
  "title": "test"
}
```

- PUT
```
$ curl -H "Content-Type: application/json" -d '{"title":"test update"}' -X PUT http://localhost:8000/posts/1
{
  "title": "test update"
}
```

- DELETE
```
$ curl -H "Content-Type: application/json" -X DELETE http://localhost:8000/posts/1

```

## json-serverのバリデーションチェック

`json-server` では、ミドルウェア関数を定義し、 `server.use` で使用することで、リクエストが送信された際にバリデーションチェックを行うようにすることができます。

以下は、リクエストが送られた際にバリデーションチェックを行う例です。

```js:index.js
const jsonServer = require('json-server');
const server = jsonServer.create();
const middlewares = jsonServer.defaults();

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

const validateRequest = (req, res, next) => {
  if (req.method === 'POST' && !req.body.name) {
    return res.status(400).json({ error: 'name is required' });
  }
  if (req.method === 'PUT' && !req.body.id) {
    return res.status(400).json({ error: 'id is required' });
  }
  next();
};

server.use(validateRequest);

server.get('*', (req, res) => {
    res.status(200).json(req.query);
  });
  
  server.post('*', (req, res) => {
    res.status(201).json(req.body);
  });
  
  server.put('*', (req, res) => {
    res.status(200).json(req.body);
  });
  
  server.delete('*', (req, res) => {
    res.status(204).end();
  });

server.listen(8000, () => {
  console.log('JSON Server is running');
});
```

上記のコードでは、 `validateRequest` というミドルウェア関数を定義し、 `server.use` で使用することで、リクエストが送信された際にバリデーションチェックを行うようにしています。

`validateRequest` 関数では、リクエストのHTTPメソッドに応じたバリデーションチェックを実装しています。

例えば、POSTメソッドの場合は、`req.body.name` が存在するかどうかをチェックし、存在しない場合は400エラーを返すようにしています。

また、`validateRequest` 関数内でバリデーションエラーが発生した場合は、`next()` を呼び出さずに `resオブジェクト` を使用してエラーレスポンスを返すようにしています。

以下は、curlコマンドを使用して、上記のモックサーバにリクエストを送信し、バリデーションチェックを確認する例です。

- POST（正常）
```
curl -X POST -H "Content-Type: application/json" -d '{"name": "John", "age": 30}' "http://localhost:8000/test"
{
  "name": "John",
  "age": 30
}
```

- POST（異常）
```
$ curl -X POST -H "Content-Type: application/json" -d '{"age": 30}' "http://localhost:8000/test"
{
  "error": "name is required"
}
```

- PUT（正常）
```
$ curl -X PUT -H "Content-Type: application/json" -d '{"id": 1, "name": "John", "age": 30}' "http://localhost:8000/test"
{
  "id": 1,
  "name": "John",
  "age": 30
}
```

- PUT（異常）
```
$ curl -X PUT -H "Content-Type: application/json" -d '{"name": "John", "age": 30}' "http://localhost:8000/test"
{
  "error": "id is required"
}
```

# まとめ

- json-serverはREST APIを簡単に構築できるツールである。
- ローカルマシン上のJSONファイルを使用してRESTfulなAPIを作成し、HTTPリクエストを使用してデータの取得、作成、更新、削除ができる。
- json-serverを使用すると、サーバーサイドのプログラミング言語やデータベースを必要とせず、フロントエンドの開発者がAPIの動作をテストしたり、簡単なデモアプリケーションを作成することができる。
- json-serverは簡単に拡張することができ、ルーティングの設定やフック機能を利用することで、より高度なAPIを作成することもできる。

## GitHub

GitHubにソースコードを公開しています。

https://github.com/ryomeblog/qiita/tree/master/json-server%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9%E3%81%BE%E3%81%A8%E3%82%81%E3%80%90%E8%A7%A3%E8%AA%AC%E3%80%91