JSON Serverを使ってダミーのAPIを用意して、フロントの実装を行ってみます。
設定方法
ターミナルでプロジェクトディレクトリに移動後、package.jsonを作成します。
npm init
プロジェクトディレクトリにJSON Serverをインストールします。
npm install json-server --save-dev
グローバルにインストールする場合は下記コマンドになります。
npm install -g json-server
プロジェクトディレクトリにdb.jsonというファイルを作成して、以下のような内容にします。
{
  "posts": [
    { "id": 1, "title": "記事A", "author": "suzuki" },
    { "id": 2, "title": "記事B", "author": "suzuki" }
  ],
  "comments": [
    { "id": 1, "body": "some comment", "postId": 1 }
  ],
  "profile": { "name": "suzuki" }
}
JSON Serverを起動します。
npx json-server db.json
グローバルにインストールした場合は下記になります。
json-server db.json
以下のように表示されたらOKです。
  \{^_^}/ 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...
例えばブラウザで http://localhost:3000/posts にアクセスすると、以下のようなjsonが表示されるのが確認できます。
[
  {
    "id": 1,
    "title": "記事A",
    "author": "suzuki"
  },
  {
    "id": 2,
    "title": "記事B",
    "author": "suzuki"
  }
]
http://localhost:3000/posts/1 のように末尾にIDを指定することで、個別の値も取得できます。
{
  "id": 1,
  "title": "記事A",
  "author": "suzuki"
}
オプション
JSON Server起動時に設定できるオプションをいくつか試してみます。
db.jsonの監視
オプションでdb.jsonの監視を設定していないと、db.jsonを変更してもAPI側に反映されません。
監視の設定をしたい場合、起動時に–watchのオプションを追加します。
npx json-server --watch db.json
これでdb.jsonを変更した時にAPI側に反映されます。
静的ファイルの設置
JSON ServerはHTMLやCSS、jsなどの静的ファイルを設置することもできます。
プロジェクトディレクトリにpublicという名前のディレクトリを作成して、その中にindex.htmlを作成します。
JSON Serverを再起動して http://localhost:3000 にアクセスすると、public/index.htmlの内容が表示されます。
public以外のディレクトリ名にすることもできます。
例えばhtdocsディレクトリにしたい場合、JSON Serverの再起動時に指定を追加します。
npx json-server db.json --static ./htdocs
これでhtdocsディレクトリ内が静的ファイルとして使用できるようになります。
ルーティングの設定変更
現状ではdb.json内で設定した値に応じて「/posts」や「/posts/1」などのURLからAPIを使用できますが、このルールを変更することもできます。
プロジェクトディレクトリにroutes.jsonというファイルを作成して、例として以下のような内容にしてみます。
{
  "/api/*": "/$1",
  "/:resource/:id/show": "/:resource/:id",
  "/articles\\?id=:id": "/posts/:id"
}
ルートの設定は「/」で開始する必要があるのでご注意ください。
routes.jsonの設定を適用するため、以下コマンドで再起動します。
npx json-server db.json --routes routes.json
これで「/api/posts」にアクセスした場合には「/posts」と同じ内容が、「/api/posts/1」や「/posts/1/show」、「/api/posts/1/show」、「/articles?id=1」にアクセスした場合は「/posts/1」と同じ内容が表示されるようになりました。
設定ファイル
ここまで設定したwatchやstatic、routesなどのオプションをまとめて設定することもできます。
プロジェクトディレクトリにjson-server.jsonというファイルを作成して、今までの設定をまとめてみます。
{
  "watch": true,
  "static": "./htdocs",
  "routes": "routes.json"
}
これでJSON Serverの起動時にオプションを追記しなくてもよくなりました。
以下コマンドで再起動を行い、設定が反映されていればOKです。
npx json-server db.json
フロントの実装
Fetch APIを使って、実際にAPIを使用する実装を試してみます。
GET
GETでpostsの一覧を取得してみます。
fetch('http://localhost:3000/posts', {
  method: 'GET'
})
.then(response => {
  return response.json();
})
.then(data => {
  console.log(data);
});
先ほどブラウザで試したように、「/posts/1」の形で個別の値も取得することもできます。
GETのデモページ
POST
POSTでpostsに追加してみます。
var data = {
  "title": "記事C",
  "author": "suzuki"
}
fetch('http://localhost:3000/posts', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(data)
})
.then(response => {
  return response.json();
})
.then(data => {
  console.log(data);
});
idは自動で付与されるようです。
POSTのデモページ
PUT
PUTで既存の内容を更新してみます。
var data = {
  "title": "記事A-PUT",
  "author": "suzuki"
}
fetch('http://localhost:3000/posts/1', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(data)
})
.then(response => {
  return response.json();
})
.then(data => {
  console.log(data);
});
PUTは「/posts/1」のように個別の値に対して行います。
PUTのデモページ
PATCH
PATCHで既存の内容を部分的に更新してみます。
var data = {
  "title": "記事A-PATCH"
}
fetch('http://localhost:3000/posts/1', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(data)
})
.then(response => {
  return response.json();
})
.then(data => {
  console.log(data);
});
DELETE
DELETEで既存の内容を削除してみます。
fetch('http://localhost:3000/posts/1', {
  method: 'DELETE'
})
.then(response => {
  return response.json();
})
.then(data => {
  console.log(data);
});
DELETEもPUTやPATCHと同様に、「/posts/1」のようにして個別の値に対して行います。
DELETEのデモページ
パラメータ
GETパラメータで使用できる項目をいくつか試してみます。
db.jsonを変更します。
{
  "posts": [
    { "id": 1, "title": "記事A", "author": "suzuki" },
    { "id": 2, "title": "記事B", "author": "suzuki" },
    { "id": 3, "title": "記事C", "author": "suzuki" },
    〜 略 〜
    { "id": 19, "title": "記事S", "author": "suzuki" },
    { "id": 20, "title": "記事T", "author": "suzuki" }
  ],
  "comments": [
    { "id": 1, "body": "some comment", "postId": 1 }
  ],
  "profile": { "name": "suzuki" }
}
Filter
項目名と値を指定して、一致する内容を出力します。
http://localhost:3000/posts?title=記事A
この場合、titleが記事Aの内容のみ出力されます。
[
  {
    "id": 1,
    "title": "記事A",
    "author": "suzuki"
  }
]
同じ項目を複数指定することもできます。
http://localhost:3000/posts?id=1&id=2
この場合、idが1か2の内容のみ出力されます。
[
  {
    "id": 1,
    "title": "記事A",
    "author": "suzuki"
  },
  {
    "id": 2,
    "title": "記事B",
    "author": "suzuki"
  }
]
Paginate
_pageと_limitでページ分割ができます。
http://localhost:3000/posts?_page=2&_limit=5
この場合、1ページあたり5件の分割で2ページ目なので、全体の6〜10件目の内容が出力されます。
[
  {
    "id": 6,
    "title": "記事F",
    "author": "suzuki"
  },
  {
    "id": 7,
    "title": "記事G",
    "author": "suzuki"
  },
  {
    "id": 8,
    "title": "記事H",
    "author": "suzuki"
  },
  {
    "id": 9,
    "title": "記事I",
    "author": "suzuki"
  },
  {
    "id": 10,
    "title": "記事J",
    "author": "suzuki"
  }
]
Sort
_sortと_orderで並び替えができます。
http://localhost:3000/posts?_sort=id&_order=desc
この場合、idの値を降順に並び替えて出力します。
[
  {
    "id": 20,
    "title": "記事T",
    "author": "suzuki"
  },
  {
    "id": 19,
    "title": "記事S",
    "author": "suzuki"
  },
  {
    "id": 18,
    "title": "記事R",
    "author": "suzuki"
  },
〜 略 〜
  {
    "id": 2,
    "title": "記事B",
    "author": "suzuki"
  },
  {
    "id": 1,
    "title": "記事A",
    "author": "suzuki"
  }
]
Slice
_startと_endで開始位置と終了位置(インデックス番号)を指定して、指定範囲のスライスができます。
http://localhost:3000/posts?_start=1&_end=3
この場合、2〜3件目の内容を出力します。
[
  {
    "id": 2,
    "title": "記事B",
    "author": "suzuki"
  },
  {
    "id": 3,
    "title": "記事C",
    "author": "suzuki"
  }
]
_limitで終了位置ではなく出力件数の指定もできます。
http://localhost:3000/posts?_start=2&_limit=3
この場合、3番目から3件分の内容を出力します。
[
  {
    "id": 3,
    "title": "記事C",
    "author": "suzuki"
  },
  {
    "id": 4,
    "title": "記事D",
    "author": "suzuki"
  },
  {
    "id": 5,
    "title": "記事E",
    "author": "suzuki"
  }
]
Full-text search
qで全文検索ができます。
http://localhost:3000/posts?q=F
この場合、「F」で検索した内容が出力されます。
[
  {
    "id": 6,
    "title": "記事F",
    "author": "suzuki"
  }
]
POSTで投稿日時を自動で追加する
カスタマイズの例として、POST時に投稿日時を自動で追加するようにしてみます。
プロジェクトディレクトリにserver.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(jsonServer.bodyParser)
server.use((req, res, next) => {
  if (req.method === 'POST') {
    req.body.createdAt = Date.now()
  }
  next()
})
// routes.jsonの内容
server.use(jsonServer.rewriter({
  "/api/*": "/$1",
  "/:resource/:id/show": "/:resource/:id",
  "/articles\\?id=:id": "/posts/:id"
}))
server.use(router)
server.listen(3000, () => {
  console.log('JSON Server is running')
})
10〜12行目部分でPOST時の内容にcreatedAtという項目名で投稿日時を追加しています。
16〜21行目はroutes.jsonを設定したい場合に適宜追記ください。
これで準備ができましたので、JSON Serverを再起動します。
その際、server.jsを使用するため下記コマンドを実行して起動します。
node server.js
これでPOSTを試してみたところ、投稿日時をタイムスタンプの形で追加することができました。
POSTをGETとして扱う
ダミーのAPIとして使用する際、POST時にデータの追加ではなく取得(GET)として動作させたいということがあったので、先ほどの例を変更してみます。
server.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(jsonServer.bodyParser)
server.use((req, res, next) => {
  if (req.method === 'POST') {
    req.method = 'GET';
  }
  next()
})
// routes.jsonの内容
server.use(jsonServer.rewriter({
  "/api/*": "/$1",
  "/:resource/:id/show": "/:resource/:id",
  "/articles\\?id=:id": "/posts/:id"
}))
 
server.use(router)
server.listen(3000, () => {
  console.log('JSON Server is running');
})
変更点は10〜12行目部分のみで、methodがPOSTだった場合にGETに置き換えています。
JSON Serverを再起動してPOSTを試してみたところ、データの追加ではなく取得することができました。
他にも設定できる項目が色々ありますので、詳しくは公式のドキュメントをご確認ください。

コメントが承認されるまで時間がかかります。