リンク一覧
- Node.jsとExpressでローカルサーバーを構築する(1) ―Node.jsとnpmの導入―
- Node.jsとExpressでローカルサーバーを構築する(2) ―Expressでルーティング―
- Node.jsとExpressでローカルサーバーを構築する(3) ―JSONを返すスタブAPI―(本記事)
- Node.jsとExpressでローカルサーバーを構築する(4) ―他サーバーから画像を取得する―
最近は、Jsonデータを送りつけたり受け取ったりしてなんやかやするケースが増えてきました。私の極狭い認識の範囲では、フロント側の製作期間中にAPIが完成していないことが多いです。
その為、ローカルサーバーにJSONを返すスタブAPIの機能を実装したいと思います。
概要
この記事の概要
- 目的
- Node.jsとExpressを利用して、PC上にローカルサーバーを立ち上げる
- 本記事のゴール
- GETでリクエストを送ると、JSONデータが返ってくる
- POSTでJSONデータを送ると、200 OK のレスポンスコードが返ってくる
- 対象者
- WEBフロント担当者
- HTML,CSS,JavaScript(es2015含む)の基本的な構文を理解している人
- HTTP通信、GET、POSTなどについて、ある程度理解している人(ざっくりで良いです)
- 黒い画面にコマンドを打ち込むことに抵抗がない方
- 環境・バージョン
- Windows10
- Node.js(推奨版) 10.15.01
- npm 6.4.1
- Express 4.16.4
- Advanced REST client 10.0.12
Chrome拡張ツール:Advanced REST client
GETやPOSTの動作確認を簡単に行うために、Chrome拡張ツールの「Advanced REST client」を利用します。
Advanced REST client
導入方法や利用方法は、下記サイトが詳しいです。分かりやすいUIですので、本記事内でも都度説明します。
「Advanced REST client」の使い方まとめ ~GoogleChromeの拡張ツール
expressでのルーティングの実装
前回のおさらい
Expressを使ったサーバーで、静的コンテンツのルーティングのためにuse
メソッドやexpress.static
メソッドを利用しました。
const express = require('express');
const app = express();
app.listen(8080);
app.use(express.static(path.join(__dirname, 'public')));
use
は、全てのタイプのリクエストで実行されます。
ルーティングの基本
GETリクエストを受け取る
GETリクエストを受け取りたい場合は、get
メソッドを利用します。
// サイトルートへのGETリクエストの場合
app.get('/', (req, res, next)=>{
res.send('ルートだよ!');
});
// /hoge/fugaへのGETリクエストを受け取りたい場合
app.get('/hoge/fuga', (req, res, next)=>{
res.send('ほげふが');
});
POSTリクエストを受け取る
POSTリクエストを受け取りたい場合は、post
メソッドを利用します。
// サイトルートへのPOSTリクエストの場合
app.post('/', (req, res, next)=>{
res.send('ルートだよ!全員集合!');
});
// /hoge/fugaへのPOSTリクエストを受け取りたい場合
app.post('/hoge/fuga', (req, res, next)=>{
res.send('ほげふが');
});
パスの指定
get
とpost
いずれの場合も、第一引数にはピックアップしたいサイト上のパスを指定します。この指定は、ワイルドカードや正規表現などを組み合わせることも可能です。
app.get(/^book/, ()=>{});
上記の例では、/book
、/books
にはマッチしますが、/boo
、/ibook
とはマッチしません。
公式ガイド:Expressでのルーティング
ミドルウェアの基本
get
とpost
いずれの場合も、第二引数はリクエストを受け取った際のコールバック関数を渡します。このコールバック関数は、ミドルウェア(中間処理を行う関数)と呼ばれます。
ミドルウェアは、リクエストreq
・レスポンスres
を表すオブジェクトと、後続のミドルウェアへのバトンの役割を果たす関数next
を受け取ります。
このミドルウェア内でクライアントにレスポンスをするか、明示的にプロセスを終了させるかnext()
を実行して他へ制御を渡すかしないと、応答なしの状態に陥ってしまいます。
app.get(/^book/, (req, res, next)=>{
if(req.query.id){
res.send('OK.');
}else{
next();
}
});
res.send
クライアントへHTTPレスポンスを返すためのメソッドです。
文字列だけでなく、配列やオブジェクトも送信できます。事前に指定しなかった場合、ヘッダーのContentTypeは送信データに応じて自動的に割り当てられます。
res.end
データ送信をせずにレスポンスのプロセスを終了させるためのメソッドです。
実体はNode.jsのコアモジュールhttp
のresponse.end
です。引数にデータを渡せば送信されますが、res.send
などの専用メソッドを利用する方が望ましいです。
送信されたデータを受け取る
GETで送信されたURLパラメータ
GETで送信されたURLパラメータを受け取るには、ミドルウェアに渡されたreq
オブジェクトのquery
プロパティにアクセスします。
/**
* /search?color=red&size=small へのリクエスト
*/
app.get('/search', (req, res, next)=>{
console.log(req.query.color); // "red"
console.log(req.query.size); // "small"
});
POSTで送信されたJOSNデータ
POSTでJSONデータを受け取るには、予めパース処理を行うミドルウェアを設定しておく必要があります。このミドルウェアは、Expressに予め用意されています。
const express = require('express');
const app = express();
app.use(express.json()); //パース用ミドルウェアを設定
app.post((req, res)=>{
console.log(req.body); //パースされたデータを参照
});
Expressの静的メソッドjson
の実行結果をuse
メソッドに渡しています。渡すのはあくまでjson
の実行結果として返されるミドルウェアで、json
メソッドそのものではありません。パースされたデータは、request
オブジェクトのbody
プロパティに格納されます。
JSONデータを送る
オブジェクトをパースして送る
オブジェクトをJSONにパースした上で送信したい場合は、res.json
メソッドを使います。
app.get('/', (req, res, next)=>{
res.json({ message: `This is a pen.`});
});
#### JSONファイルを送る
予め用意したJSONファイルを送信したい場合、res.sendFile
メソッドが便利です。このメソッドは、Expressのバージョン4.8.0以降からサポートされています。
app.get('/', (req, res, next)=>{
res.sendFile(__dirname + '/data.json', (err) => {
if (err) {
res.sendStatus(400);
} else {
console.log('sending completed');
}
});
});
第一引数に送信したいファイルの絶対パスを指定します。
第二引数には、送信完了もしくはエラー発生時に呼び出されるコールバック関数を指定します。
エラー発生時はエラー情報を引数で受け取ります。成功時はundefined
です。
route()でミドルウェアをまとめる
route
メソッドを利用すると、同一パスに対するタイプ別のリクエストに対し、ミドルウェアを見通し良くまとめられます。
app.route('/moimoi')
.get((req, res)=>{
// GET
})
.post((req, res)=>{
// POST
})
.put((req, res)=>{
// PUT
})
.delete((req, res)=>{
// DELETE
});
## Routerでルーティング処理を外部モジュール化する
ルーティング処理を他ファイルで定義して、メインの処理にミドルウェアとして組み込むことが出来ます。
ミドルウェアを定義して公開する
Expressの静的メソッドexpress.Router
を実行してルーティング用のミドルウェアの骨格を生成します。
この骨格に対して、「このパスへのリクエストはこれ返せ」といったルーティング処理を肉付けしていきます。肉付けの方法は、通常のexpress()で取得したオブジェクトと同様に、use、get、post等を利用します。
そして、完成したミドルウェアをエクスポートして公開します。
/**
* /api/index.js
*/
const express = require('express');
const router = express.Router(); //ミドルウェアの準備
router.get('/items', (req, res) => {
res.json({ items: [] });
});
router.post('/registration', (req, res) => {
res.end('Completed');
});
module.exports = router; //エクスポートして公開
公開されたミドルウェアを利用する
公開されたミドルウェアをインポートしてルーティングに適用します。
/**
* /app.js
*/
const express = require('express');
const app = express();
const api = require('./api/'); //ミドルウェア読み込み
app.use('/api', api);
/api
へのリクエストの対応を、/api/index.js
で定義したミドルウェアへ渡しています。
この際、ミドルウェア内のルートパスは/api
です。ミドルウェア内で指定した/items
は、実際は/app/items
へのリクエストです。ミドルウェア内で/app/items
としてしまうと、実際には/app/app/items
を指定したことになってしまいます。
ガイド:express.Router(日本語)
リファレンス:express.Router(英語)
API機能の実装
上記を踏まえて、API機能を実装していきます。
## ファイルとフォルダの準備
API関連のファイルを格納するフォルダapi
を追加します。
このフォルダの配下に、クライアントに送りつけるjsonデータと、ルーティング処理を記述するjsファイルを作成します。
sample/
├ public/
│ ├ css/
│ │ └ sample.css
│ ├ js/
│ │ └ sample.js
│ ├ img/
│ │ └ sample.png
│ └ index.html
├ api/
│ ├ index.js
│ └ data.json
└ app.js
/**
* /app.js
*/
const express = require('express');
const app = express();
const path = require('path');
// /api/index.js で定義されたミドルウェア
const api = require('./api/');
app.listen(8080, () => {
console.log('Running at Port 8080...');
});
// APIルーティング用ミドルウェアを/apiに設定
app.use('/api', api);
app.use(express.static(path.join(__dirname, 'public')));
app.use((req, res) => {
res.sendStatus(404);
});
/**
* /api/index.js
*/
const express = require('express');
const router = express.Router();
// JSONパース
router.use(express.json());
// /api/foo へのGETリクエスト
router.get('/foo', (req, res) => {
// ファイルを転送
res.sendFile(__dirname + '/data.json', (err) => {
if (err) {
res.sendStatus(400);
} else {
console.log('sending completed');
}
});
});
// /api/bar へのGET・POSTリクエスト
router.route('/bar')
.get((req, res) => {
// 受け取ったパラメータをそのままJSONにして送り返している
res.json(req.query);
})
.post((req, res) => {
// 必須のデータ項目を、id,name,address として、受信データをチェックしている
const nameAry = ['id', 'name', 'address'],
failed = nameAry.some(v => !req.body[v]);
if (failed) {
res.sendStatus(400);
} else {
res.sendStatus(200);
}
});
module.exports = router;
/api/data.json
に適当な内容を記述します。
{
"id": "W0001",
"title": "I Love Cats and Dogs",
"price": 3000000000000
}
準備が出来たら、サーバーを起動します。
$ node app.js
「Advanced REST client(ARC)」で送受信テスト
送受信のテストを、Chromeの拡張ツールの「Advanced REST client」で行いたいと思います。
こちらから取得できます。
ホーム > アプリ > Advanced REST client
ARCを起動して、まずはTOPページにアクセスしてみます。
- Methodを「GET」
- RequestURLに「
http://localhost:8080/
」 - 「SEND」をクリック
「200 OK」とHTMLデータが取得できました。
では、続けてAPIのデータを取得します。
GETで「http://localhost:8080/api/foo
」へリクエストを送ると、/api/data.json
が取得できます。
次は、GETで「http://localhost:8080/api/bar?name=pee&address=poo&age=17
」へリクエストを送ります。
URLパラメータの値をJSONで取得で取得できます。
次は、POSTで「http://localhost:8080/api/bar
」へリクエストを送ります。
- 「Parameters>Body>Body content type」を「application/json」
- 「Parameters>Body>Editor view」を「JSON visual editer」
- id, name, address の三つのプロパティを含むJSONデータを定義
「200 OK」が返ってきました。
次は、項目を一つ減らして送信してみると、「400 Bad Request」が返ってきます。
これで、APIの開発が間に合っていなくても何とかなりそうですね!
初心者の拙い記事を読んでいただき、ありがとうございました。
お役に立てていたら幸いです。
JSON Server
この記事を書いている途中で、JSONを返すAPIを簡単に実現する「JSON Server」なるものの存在を知りました。。。
JSON Server使いこなし - モックサーバーの起動とリソース処理 | CodeGrid
公式:GitHub - typicode/json-server