expressモジュールによるHTTPサーバ(15)テンプレートのレンダリング
目次
この記事は「expressモジュールによるHTTPサーバ」という連載記事の15つ目の記事です。
その他の記事に関しては下を参照してください。
記事一覧
また、HTTP自体について知りたい方は下を参照してください。
HTTPとは?
この記事ではexpress
モジュールを使ってリクエストに対してEJSテンプレートエンジンによるEJSテンプレートファイルのレンダリング結果の送信を行うHTTPサーバを作成する方法について説明します。
EJSテンプレートエンジンとは?
テンプレートエンジン
テンプレートエンジンを利用するにはテンプレートエンジンのモジュールが含まれるパッケージを手動でインストールしなければなりません。
EJSテンプレートエンジンの場合、npm install ejs
によりインストールします。
テンプレートに関する設定項目
テンプレートに関するアプリケーションの設定項目として下の3つがあります。
views
・・・テンプレートが保存されているフォルダのパスを設定します。複数のパスを設定する場合には配列として設定します。デフォルトはprocess.cwd() + '/views'
です。view cache
・・・テンプレートのコンパイル結果をキャッシュするかを真偽値として設定します。デフォルトはenv
設定項目がproduction
である場合にはtrue
であり、そうでない場合にはfalse
です。view engine
・・・テンプレートエンジンを設定します。EJSテンプレートエンジンの場合、ejs
です。この値はテンプレートエンジンのモジュールやテンプレートを読み込む際に使用されます。
なお、express
モジュールに対応している主なテンプレートエンジン(のモジュール名)には下のようなものがあります。
pug
hamljs
ejs
swig
whiskers
テンプレートエンジンの設定
express
モジュールはデフォルトではテンプレートファイルの拡張子に基づいてレンダリングに使用するテンプレートエンジンを決定します。
たとえば、テンプレートファイルの拡張子が.xxx
である場合にはxxx
という名称のモジュールがテンプレートエンジンとして読み込まれます。
しかしながら、テンプレートファイルの拡張子とテンプレートエンジンのモジュール名が一致しない場合などテンプレートファイルの拡張子とテンプレートエンジンを手動で関連付けたい場合にはapp.engine
関数を使用します。
var express = require('express');
var app = express();
app.engine('xxx', function (path, data, callback) {
callback(null, 'yyy');
//or
callback(new Error('aaa'), null);
});
第1引数に拡張子から冒頭の.
を除いたものを指定します。
第2引数にテンプレートをレンダリングする処理を関数として指定します。
この関数の第1引数はテンプレートファイルのパスであり、第2引数はデータであり、第3引数はコールバック関数です。
処理が完了した場合や処理の実行中にエラーが発生した場合には必ずこのコールバック関数を呼び出さなければなりません。
このコールバック関数の第1引数にはエラーオブジェクト(エラーが発生しなかった場合にはnull
)を指定し、第2引数にはレンダリング結果(エラーが発生した場合にはnull
)を指定します。
なお、第2引数の関数を指定する場合にはconsolidate
モジュールが提供しているものを利用すると便利です。consolidate
モジュールは主要なテンプレートエンジン毎に第2引数の関数に指定可能な関数を提供しています。
var consolidate = require('consolidate');
var dust = consolidate.dust;
var swig = consolidate.swig;
var ejs = consolidate.ejs;
var haml = consolidate.haml;
var whiskers = consolidate.whiskers;
var hogan = consolidate.hogan;
var handlebars = consolidate.handlebars;
var pug = consolidate.pug;
var mustache = consolidate.mustache;
var ect = consolidate.ect;
var dot = consolidate.dot;
レンダリング結果の送信
テンプレートエンジンによるレンダリング結果を取得し、HTTPレスポンスボディにレンダリング結果をHTMLドキュメントとして設定してレスポンスの送信を行うにはres.render
関数を使用します。
app.use('xxx', function (req, res, next) {
res.render('xxx', { yyy: 'yyy' }, function (err, result) {
if (err) {
res.end();
}
});
});
第1引数にテンプレートのパスを指定します。このパスは絶対パスかviews
設定項目からの相対パスとします。このパスの拡張子を省略した場合にはview engine
設定項目の冒頭に.
を付加したものが拡張子となります。拡張子を省略しなかった場合にはテンプレートのレンダリングの際に拡張子に対応するテンプレートエンジンが利用されます。
第2引数にデータをオブジェクトとして指定します。この引数は指定しなくても構いません。このオブジェクトのcache
プロパティの値がtrue
である場合にはテンプレートのコンパイル結果がキャッシュされます。
第3引数にコールバック関数を指定します。この引数は指定しなくても構いません。この関数の第1引数はエラーオブジェクトであり、第2引数はレンダリング結果です。この引数を指定した場合にはHTTPレスポンスの送信は行われませんので注意してください。
レンダリング結果の取得
テンプレートエンジンによるレンダリング結果の取得のみを行うにはapp.render
関数を使用します。
app.render('xxx', { yyy: 'yyy' }, function (err, result) {
});
この関数の引数はres.render
関数のものと同じです。
サンプルコード1
クライアントからGETリクエストを受け取ったらEJSテンプレートエンジンによるEJSテンプレートファイルのレンダリング結果を返すHTTPサーバを作成し、起動します。
Enter
キーが押されたらサーバを停止し、プログラムを終了します。
また、EJSテンプレートファイルは3番目のコマンドライン引数として与えられるものとします。また、テンプレートのデータはJSON形式のデータファイルにより与えられるものとし、JSON形式のデータファイルは4番目のコマンドライン引数として与えられるものとします。
express-server-ejs.js
var express = require('express');
var path = require('path');
var http = require('http');
if (process.argv.length < 4) {
console.error('lack argument.');
process.exit(1);
}
var app = express();
app.set('env', 'development');
app.set('x-powered-by', false);
app.set('case sensitive routing', true);
app.set('strict routing', true);
app.set('views', '.');
app.set('view cache', false);
app.set('view engine', 'ejs');
app.get('*', function (req, res) {
res.render(process.argv[2], require(path.isAbsolute(process.argv[3]) ? process.argv[3] : path.join(process.cwd(), process.argv[3])));
});
app.get('*', function (req, res) {
res.status(404);
res.send(http.STATUS_CODES[404] + '\r\n');
});
app.all('*', function (req, res) {
res.status(501);
res.send(http.STATUS_CODES[501] + '\r\n');
});
var server = app.listen(3000, function () {
console.log('http server is running...press enter key to exit.');
process.stdin.on('data', function (data) {
if (data.indexOf('\n') !== -1) {
server.close(function () {
console.log('http server closed.');
process.exit(0);
});
}
});
});
server.on('error', function (err) {
console.error(err);
process.exit(1);
});
使用パッケージ
実行結果
実行結果の確認のためにcURLを使用しています。
cURLのインストール方法
現在のフォルダには下のような内容のtemplate.ejs
という名称のEJSテンプレートファイルが存在しています。
<%
var n = 0;
for (var i = 0; i < vocabulary.length; i++) {
n++;
}
-%>
<h1><%= name %></h1>
<p><%= description %></p>
<p>単語数:<%= n %></p>
<ul>
<% for (var i = 0; i < vocabulary.length; i++) { -%>
<%- "<li>" -%>
<%= vocabulary[i].level -%>
<%= " " -%>
<%= vocabulary[i].word -%>
<%= " " -%>
<% for (var j = 0; j < vocabulary[i].meanings.length; j++) { -%>
<% if (j != 0) { -%>
<%= "、 " -%>
<% } -%>
<%= vocabulary[i].meanings[j] -%>
<% } -%>
<%- "</li>" %>
<% } -%>
</ul>
また、下のような内容のvocabulary.json
という名称のJSON形式のデータが存在しています。
{
"name": "単語帳",
"description": "頑張って覚えましょう。",
"vocabulary": [
{
"word": "stale",
"level": "6",
"meanings": ["新鮮でない"]
},
{
"word": "stylist",
"level": "7",
"meanings": ["名文家"]
},
{
"word": "substitution",
"level": "8",
"meanings": ["代用", "代用品", "代入", "置換"]
},
{
"word": "ventilate",
"level": "9",
"meanings": ["~を換気する"]
},
{
"word": "ventilation",
"level": "10",
"meanings": ["換気(装置)"]
}
]
}
3つ目のコマンドライン引数にtemplate.ejs
を指定し、4つ目のコマンドライン引数にvocabulary.json
を指定してコードを実行するとHTTPサーバが起動します。
C:\work\node>node express-server-ejs.js template.ejs vocabulary.json
http server is running...press enter key to exit.
cURLを使ってサーバに対してGETリクエストを行います。
C:\work\node>curl -v http://localhost:3000/
* Trying ::1...
* Connected to localhost (::1) port 3000 (#0)
> GET / HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.46.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=utf-8
< Content-Length: 309
< ETag: W/"135-0tI32QpE/2iKe3V0zzQ9jg"
< Date: Tue, 19 Jul 2016 10:44:22 GMT
< Connection: keep-alive
<
<h1>単語帳</h1>
<p>頑張って覚えましょう。</p>
<p>単語数:5</p>
<ul>
<li>6 stale 新鮮でない</li>
<li>7 stylist 名文家</li>
<li>8 substitution 代用、 代用品、 代入、 置換</li>
<li>9 ventilate ~を換気する</li>
<li>10 ventilation 換気(装置)</li>
</ul>* Failed writing body (209 != 309)
* Closing connection 0
curl: (23) Failed writing body (209 != 309)
サーバから正しくレスポンスが返っていることが分かります。
Enter
キーを押すとサーバが停止し、プログラムが終了します。
関連
