概要
- MDNのExpressについてのチュートリアルを参考にまとめてみました。
- Nodeのインストールについては、別の記事をみてください。
まずNode.jsについて
- JavaScriptのサーバーサイドのツールかつアプリケーション。
- JavaScriptはブラウザ上で動くイメージがあるが、サーバサイドもかける!!
- ブラウザ用のAPIは取り除き、OS用のAPI(ファイルへのアクセスとか)やHTTP用のAPI群を持っている。
Node.jsのウェブサーバとしての利点
- スループットとスケーラビリティを持っている。
- ブラウザとサーバサイド両方ともJavaScriptで記述できる。
- node package manager (NPM) を利用すれば、優れたパッケージを再利用できる。パッケージの依存関係なども扱える。楽。
簡単なwebサーバのコード例
- 以下で簡単にNodeのHTTPモジュールで、ウェブサーバを起動できる。
// Httpのモジュールの読み込み
var http = require("http");
// 8000番ポートでHTTPサーバ起動
http.createServer(function(request, response) {
// レスポンスで返すHTTP header(with HTTP status Content type)
response.writeHead(200, {'Content-Type': 'text/plain'});
// レスポンスで返すbody
response.end('Hello World\n');
}).listen(8000);
// 起動ログ
console.log('Server running at http://127.0.0.1:8000/');
// サーバプロセス起動
$ node app.js
http://127.0.0.1:8000/
にアクセスすると、HelloWorldのテキストが返されます。
Expressについて
-
ExpressはもっともポピュラーなNodeのウェブフレームワーク。
-
他の有名なNodeのウェブフレームワークの元にもなっている。
-
以下の仕組みを提供する。
- リクエストに対して、異なるURLパスで、HTTP verbsと共にハンドラーを書く。
- "view" というrendering enginesをよく利用する。(GUIを伴う場合)
- テンプレートの場所や、ポートなどの一般的なwebアプリケーションの設定を扱う。
- リクエストを扱う過程で、"middleware"という付加的なリクエスト処理を加えることができる。(middle ware pattern)
-
Expressのmiddlewareとして、たくさんのライブラリが作られている。
- cookies, sessions, user logins, URL parameters, POST data, security headersなどを扱うライブラリ
HelloWorld Express(簡単に使ってみる)
- ExpressでHelloWorld。
const express = require('express');
const app = express();
app.get('/', function(req, res) {
res.send('Hello World!');
});
app.listen(8000, function() {
console.log('Example app listening on port 8000!');
});
-
app(慣例の名前付け)のオブジェクトは、アプリケーションの振る舞いの操作に関するメソッドを持つ。
- HTTPルーティングのメソッド
- middlewareの設定
- viewのレンダリング
- テンプレートエンジンの登録
- アプリケーションの設定変更など
-
app.get()
- 「/」のパスにアクセスされるたびに呼び出されるコールバック関数(functionの部分)を定義する。
- コールバック関数はrequestとresponseを引数として持ち、responseでsend()を呼び出すことで、「Hello World!」を返す。
Node.jsのモジュールについて
-
モジュールはJavaScriptのライブラリで、require()関数でインポート可能。
-
Express自体もモジュールで、ExpressアプリケーションでDBやミドルウェアのライブラリを利用可能。
-
メンテナンスの観点から、自作でモジュールを作りたくなるはず。
-
以下のようにexportsすることでmoduleとして利用できる。
exports.area = function(width) { return width * width; };
exports.perimeter = function(width) { return 4 * width; };
- インポートはこう。
var square = require('./square'); // Here we require() the name of the file without the (optional) .js file extension
console.log('The area of a square with a width of 4 is ' + square.area(4));
- module.exportsを使うことで、一度にオブジェクトとしてexport可能。
module.exports = {
area: function(width) {
return width * width;
},
perimeter: function(width) {
return 4 * width;
}
};
非同期APIについて
- JavaScriptは同期処理APIより非同期処理APIの方がよく利用される。
- Nodeはシングルスレッドで動く。
- シングルスレッドということは全てのサーバへのリクエストを一つのスレッドで捌く。
- これはスピードとルーティングの観点で利点があるが、同期的な関数を実行して、時間がかかるとパフォーマンスに大きく影響する。
- 非同期処理APIの完了通知を受ける方法はいくつかある。
- もっとも一般的な方法は、完了時に呼び出されるコールバック関数を登録すること。
- 時々コールバック地獄(ネストしまくること)にハマるが、減らせる解決方法もあるので調べること。(Promiseとか)
route handlers
-
Hello Worldの例で、ルーティングメソッド(get)でコールバックを実装したが、send()の他にもレスポンス用のメソッドがある。
- res.json()
- res.sendFile()
-
参考: https://expressjs.com/en/guide/routing.html#response-methods
-
もちろんgetの他にもルーティングメソッドが用意されている(HTTP verbsに対応するもの)
- post(), put(), delete() etc
-
app.all()という特別なルーティングメソッドもある
- すべてのHTTP methodのレスポンスで呼ばれる
app.all('/secret', function(req, res, next) {
console.log('Accessing the secret section ...');
next(); // pass control to the next handler
});
- グループルーティングのハンドラーも便利。(express.Router)
- 例: a site with a Wiki might have all wiki-related routes in one file and have them accessed with a route prefix of /wiki/
// wiki.js - Wiki route module
const express = require('express');
const router = express.Router();
// Home page route
router.get('/', function(req, res) {
res.send('Wiki home page');
});
// About page route
router.get('/about', function(req, res) {
res.send('About this wiki');
});
module.exports = router;
- ふたつのrouterができている。
- '/wiki/'
- '/wiki/about/'
const wiki = require('./wiki.js');
const express = require('express');
const app = express();
app.use('/wiki', wiki);
app.listen(8000, () => {
console.log('Example app listening on port 8000');
});
middlewareを使う
-
MiddlewareはExpressアプリの中で多岐に渡り利用される。
- 静的ファイルのサービングや、エラーハンドリングetc
-
route関数はHTTPのリクエストレスポンスのサイクルを、HTTPクライアントになにかしらを返して終わらせるが、middleware関数は大抵リクエスト中、レスポンス中に何かしらの処理を実行し、次の関数(middlewareとかhandlerとか)を呼び出す。
-
middlewareが呼ばれる順番は開発者次第。
-
サイクルを終了させない場合は、next()メソッドを呼んで、次のmiddleware関数にコントロールを渡さなければならない。そのままあとリクエストがhangingするから注意。
-
多くのアプリはthird-partyのmiddlewareを利用するはず。
- できるだけcookieやlogging, sessionなどめんどくさいことは簡潔にしたいから。
-
third-partyのmiddlewareを利用するにはまずNPMでインストール必須。
例: morgan(HTTPリクエストのlogger middleware)
まずインストール
$ npm install morgan
use()を呼ぶことでmiddlewareを追加する
var express = require('express');
var logger = require('morgan');
var app = express();
app.use(logger('dev'));
...
-
(Note): middlewareとrouting関数は宣言された順番に呼ばれる。
- middlewareの中には呼ばれる順番が重要なものがあるので注意。
- session middleware はcokie middlewareに依存する→cookie middlewareを先に呼ばなければならない
- middlewareの中には呼ばれる順番が重要なものがあるので注意。
-
自分でmiddlewareを作成できる。
-
middleware functionとroute handler callbackの違いは、middlewareは3つ目の引数nextを持つ。
-
app.use()もしくはapp.add()で連鎖的にmiddlewareを追加できる。
- 追加の仕方は、「middlewareをすべてのレスポンスに適用したいか」もしくは「特定のHTTPverb(GET,POST etc)のレスポンスに適用したいか」で変わってくる
- どちらの場合でも、app.use()を呼ぶ際にroutesを明示する必要がある。routeはオプションだけど。
const express = require('express');
const app = express();
// middleware functionの例
const a_middleware_function = function(req, res, next) {
// ... ここで何かしらの処理
console.log('a_middleware_functionが呼ばれた');
next();
}
// Function added with use() for all routes and verbs
app.use(a_middleware_function);
// Function added with use() for a specific route
app.use('/someroute', a_middleware_function);
// A middleware function added for a specific HTTP verb and route
app.get('/', a_middleware_function);
app.listen(8000);
- より詳しい参考
databasesの利用
- ExpressはNodeが使えるdatabaseなら利用可能。
- PostgreSQL, MySQL, Redis, SQLite, MongoDB, etc.
- npmでdriverを入れる必要がある。
$ npm install mongodb