#Expressとは?
Node.jsは言わずとしれたサーバーサイドJavascriptの実行環境。
ExpressはそのNode.jsでの王道的な開発をスピードアップするためのフレームワークです。
Expressを使った開発効率向上の具体例としてREST APIの開発があります。REST APIを提供するWebサービスを開発する場合、URIやBodyを解析してリクエストの内容とデータを識別する必要があります。
例えば写真共有サービスを開発していて、とある写真を返すREST APIを提供する必要があるとします。このAPIが下記のようなフォーマットになるとします。
https://your.hostname.com/api/photo/YOUR_PHOTO_ID
このAPIを提供するサーバーは上記URIから下記のようにリクエストの内容を解析する必要があります。
- このリクエストは1枚の写真を要求している。
- リクエストしている写真のIDはYOUR_PHOTO_ID。
これは例えば正規表現などのパターンマッチングを使ってURIを解析することでも実現できますが、Expressを使うと下記のシンプルなコードで実現できます。
// 任意の写真を提供するAPI
app.get("/api/photo/:photoId", function(req, res, next){
// req.params.photoIdでユーザーが指定した写真IDを識別できる
console.log(req.params.photoId);
});
ゴリゴリとURI解析のコードを自前で書いたことのある人であれば、このシンプルな記述方法にグッとくるのではないでしょうか。
では実際にExpress + Node.jsの環境を整えていきましょう。
今回の環境
- OS: Mac OS X El Capitan
- Node.js: 5.3.0
- Express: 4.13.3
Expressをセットアップする
Node.jsは下記サイトからダウンロードしてインストーラーで簡単にインストールできます。このインストールによってNode.js本体およびパッケージマネージャーのNPMがインストールされます。
次にターミナルを起動し、新規プロジェクト用に空のディレクトリ作成し、そのディレクトリでnpm initコマンドを実行してプロジェクトを初期化します。npm initコマンドはいくつかの質問をおこない、ユーザーの回答に応じてpackage.jsonファイルを生成します。
$ mkdir new_project
$ cd new_project/
$ npm init
# プロンプトに回答していく
$ ls
package.json
package.jsonはこのプロジェクトの名前、概要、そして特にパッケージの依存関係を定義する設定ファイルです。
次にExpressをインストールします。ExpressはNPMパッケージとして提供されており、npm installコマンドでインストールできます。
$ npm install express --save
ここでpackage.jsonファイルを確認すると依存関係にExpressが追加されていることがわかります。先のnpm install時に--saveオプションを指定するとこのように依存関係を自動的に記録してくれます。
{
"name": "new_project",
"version": "1.0.0",
"description": "New Project",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Kazuki Nakajima",
"license": "MIT",
"dependencies": {
"express": "^4.13.3"
}
}
APIを作成する
最低限必要な環境が整ったので、次にサーバーサイドの処理を作成していきましょう。今回は具体例として冒頭に説明したような写真共有サービスを想定した処理を作成します。
Expressの基本的な使い方は下記の通りです。
- モジュールをロードしてインスタンス化。
- ポート番号を指定して待ち受け開始。
- アプリケーションの処理を記述。
これを踏まえてメインとなるファイルを作成します。ここではapp.jsとしておきます。
/* 1. expressモジュールをロードし、インスタンス化してappに代入。*/
var express = require("express");
var app = express();
/* 2. listen()メソッドを実行して3000番ポートで待ち受け。*/
var server = app.listen(3000, function(){
console.log("Node.js is listening to PORT:" + server.address().port);
});
/* 3. 以後、アプリケーション固有の処理 */
// 写真のサンプルデータ
var photoList = [
{
id: "001",
name: "photo001.jpg",
type: "jpg",
dataUrl: "http://localhost:3000/data/photo001.jpg"
},{
id: "002",
name: "photo002.jpg",
type: "jpg",
dataUrl: "http://localhost:3000/data/photo002.jpg"
}
]
// 写真リストを取得するAPI
app.get("/api/photo/list", function(req, res, next){
res.json(photoList);
});
今回は3000番ポートで待ち受けしています。受け付けするIPアドレスを指定することもできますが、省略するとすべてのIPアドレスでのアクセスを受け付けます。
あとは用途に応じてリクエストに対する処理を記述していきます。
上の例では写真リストを提供するAPIを記述しています。下記URLでアクセスした場合に写真のサンプルデータすべてをJSON形式で返す仕様になっています。
コードの詳細について少し見ておきましょう。
appオブジェクトのgetメソッドでは、任意のURIへGETリクエストがおこなわれた際の処理を記述できます。今回は上記のURLへGETリクエストしたら、res.json(photoList)を実行するようになっています。
resはレスポンスに関する機能がまとまったオブジェクトです。今回利用しているjson()メソッドではデータをJSONフォーマットでクライアントに送信することができます。REST APIのレスポンスは往々にしてJSONフォーマットが利用されているので、APIを作成する際には重宝するメソッドですね。
resが提供する他のメソッドについては下記のExpress公式ドキュメントで確認できます。
http://expressjs.com/en/4x/api.html#res
サーバープロセスを起動する
さて、これでサーバーを起動する準備が完了しました。サーバープロセスを起動するにはnodeコマンドの引数に今作成したapp.jsファイルを指定して実行するだけです。
$ node app.js
Node.js is listening to PORT:3000
ブラウザを起動して前述のURLにアクセスすれば、JSON形式でサンプルデータが表示されるはずです。
この結果が返ってくればあとはクライアント側のJavascriptで好きに料理できますね。
動的なAPIを作成する
先ほどはURIが完全に固定されているAPIを作成しました。次にクライアントが任意の写真を指定してその情報を取得することができるAPIを作成してみます。下記のコードをapp.jsの末尾に追加します。
app.get("/api/photo/:photoId", function(req, res, next){
var photo;
for (i = 0; i < photoList.length; i++){
if (photoList[i].id == req.params.photoId){
var photo = photoList[i];
}
}
res.json(photo);
});
今回もGETリクエストを受け付けるAPIですが、URIにセミコロン付きの:photoIdという文字列が含まれています。この部分は変数として扱われ、クライアントが指定したphotoIdをサーバー側ではreq.params.photoIdとして参照できます。
実際の処理ではphotoListの中からクライアントが指定したphotoIdのデータを検索し、ヒットしたデータをクライアントに送信しています。
このようにreqオブジェクトにはクライアントからのリクエストを処理する機能が含まれています。その他の機能については下記のExpress公式ドキュメントを参照してみてください。
http://expressjs.com/en/4x/api.html#req
UIを作成する
Webサービスのバックエンドだけを開発する場合は前述のサーバー側の処理をどんどん充実させればOKですが、クライアント側のUIも提供する場合はExpressのView Engine(テンプレートエンジン)を使って開発することができます。
ExpressではテンプレートエンジンをJadeやEJSといったモジュールから選択することができるようになっています。
今回はHTMLがそのまま利用できるEJSを選択します。EJSもNPMパッケージとして提供されているのでnpm installコマンドでインストールできます。
$ npm install ejs --save
次に実際のUIを構成するファイルを作成します。EJSを利用する場合は拡張子を.ejsとしてファイルを作成します。デフォルトではこの.ejsファイルはviewsディレクトリに置くことになっています。したがってまずviewsディレクトリをプロジェクト直下に作成します。
$ mkdir views
このviewsディレクトリ直下にindex.ejsとしてファイルを作成します。このファイルはクライアントが http://localhost:3000/ にアクセスしたときに表示されるコンテンツとします。
<html>
<body>
<h1>New Project</h1>
</body>
</html>
次にサーバー側でapp.jsを編集して2つほど設定をおこないます。ひとつはView EngineにEJSを指定する設定です。そしてもうひとつは http://localhost:3000/ へのGETリクエストで先ほど作成したindex.ejsを表示する設定です。この設定のために下記のコードをapp.jsの末尾に追加します。
// View EngineにEJSを指定。
app.set('view engine', 'ejs');
// "/"へのGETリクエストでindex.ejsを表示する。拡張子(.ejs)は省略されていることに注意。
app.get("/", function(req, res, next){
res.render("index", {});
});
先ほどまではres.json()メソッドを利用していましたが、今回はres.render()メソッドを利用しています。これは任意のテンプレートを表示するためのメソッドです。今回は先ほど作成したindex.ejsを指定しています。2番目の引数ではテンプレートエンジンに渡すオブジェクトをセットできますが今回は特に必要ないため空のオブジェクトをセットしています。
これでapp.jsの変更を反映させるためにサーバープロセスを再起動します。再起動するには先ほど実行したnode app.jsプロセスを終了してもう一度実行します。
サーバープロセスを再起動したら下記URLにアクセスしてみてください。先ほど作成したindex.ejsが表示されるはずです。
これでクライアント側の仕組みもできました。最後にクライアント側のJavascriptからサーバー側のAPIをコールするようにすれば基本的な構成ができあがります。
クライアントからのAPIコール
この部分はExpress, Node.jsに特化した仕組みはありません。UIを構成するindex.ejsにAPIコールをおこなうJavascriptコードを入れてあげればよいだけです。
<html>
<body>
<h1>New Project</h1>
<script>
var xhr = new XMLHttpRequest();
xhr.open("GET","/api/photo/list");
xhr.addEventListener("load", function(e){
var photoList = JSON.parse(xhr.responseText);
console.log(photoList);
});
xhr.send();
</script>
</body>
</html>
先ほどと同様にブラウザで http://localhost:3000/にアクセスし、Javascriptコンソールなどで結果を確認すると下図のようになり、APIから写真リストのデータを取得していうのがわかります。
まとめ
今回はゼロからスタートということであくまでも必要最小限のコードでまとめてみました。Githubで今回紹介したソースコードを公開しています。
本格的にアプリを書いていくと、app.jsがどんどん肥大化するんだけどどうするんだこれ?とか、クライアント側のjsライブラリはどうやって管理するんだ?とか、画像ファイルとか静的ファイルはどこに置くんだ?などいろんな疑問が出てきます。
後ほどこのあたりをまとめていこうと思います。