- 2015/10/29
- 株式会社フレクト
- テクニカルスペシャリスト
- 小川 充
-
フロントエンドエンジニア
- Javascript, HTML, CSS, Node.js, API設計とか認証とか
-
2015/5月入社(約半年)
-
API開発でnodeを使いたい。そのためにはnodeを使える人を増やす必要がある!!
- JavaでAPI開発はもういやや。。。
あくまで「俺が考える最強のexpress実践入門」です。
初学者がexpressを攻略する上でのつまづくポイントと、中規模開発をターゲットにしたベストプラクティスを経験ベースでお話します。
おそらく、〜初級者向けの内容です。
- express初心者
- 初学者向けチュートリアル(dotinstallとか)のお供に
- express経験者
- ご自身のコードの見直しに
- 他の言語の経験者
- 他の言語の「あれ」は、node.jsでは「これ」のマッピングに
(※)中で紹介するコードは抜粋したものであり、そのままでは動作しない場合があります。ご注意ください。
(※)versionはnode v4.2.0, express v4.13.1です。
expressとはなにか?expressの初め方について
(ググったらすぐ出てくる内容ですよ〜)
Fast, unopinionated, minimalist web framework for Node.js
- Fast - 高速
- unopinionated - オープン
- minimalist - 軽量
Node.jsのための、高速で軽量でオープンなWebフレームワーク。
- ほぼデファクトの地位
- 豊富な情報量、サンプル
- 豊富な拡張機能(middleware)
- Pure node.jsで作成した場合、アプリを仕上げていく過程で「
そもそもexpressで良かったのでは?」となることが多かった(経験談)
(※)ただし、3系と4系の違いに注意。世の中のサンプルは3系で書かれているものが多く、動作しないことがある。
他のWebフレームワーク
- hapi.js - A rich framework for building applications and services
- Koa - next generation web framework for node.js
Node.jsをインストールして、、、
ほぼ一発。
mkdir myapp && myapp
npm init
npm install express
サーバー側のコード(app.js)
var express = require('express');
var app = express();
// HTTPリクエストを受け取る部分
app.get('/', function (req, res) {
res.send('Hello World!');
});
// サーバーを起動する部分
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});サーバーを起動して、http://localhost:3000にアクセス
node app.js
curl http://localhost:3000 -> Hello World!
通常はこちらの方をよく使います。Express application generator
(sudo)npm install express-generator -g
// expressコマンドでアプリのひな形を生成します
express myapp
create : myapp
create : myapp/package.json
create : myapp/app.js
...
create : myapp/bin
create : myapp/bin/www
cd myapp
// 依存モジュールをインストールします
npm install
// サーバーを起動します
node bin/www // or npm run start
基本最小構成。後ほどオレ色に染め上げて行きます。
.
├── app.js // expressサーバーの設定
├── bin
│ └── www // サーバーの起動
├── package.json
├── public // 静的ファイル置き場
│ ├── images
│ ├── javascripts
│ └── stylesheets
│ └── style.css
├── routes // サーバー側のコントローラ
│ ├── index.js
│ └── users.js
└── views // サーバー側で画面を作成する際のテンプレート
├── error.jade
├── index.jade
└── layout.jade
expressのここを理解すればOK!
expressを理解する上での最小構成要素。
- routing
- middleware
以上2つ
「図」
- routing
- 外部からのHTTP(S)リクエストに対して、内部のロジックをマッピングすること。
- middleware
- routingの過程で何らかの処理を差し込む仕組み。
- 共通処理(認証、エラーハンドリング、リクエストデータの加工、etc)を本来のロジックから分離して、コードベースを健全に保つ。
HTTPメソッド、Path、マッピングする内部ロジックを指定する方式。
var app = express();
// GET http://localhost:3000/
app.get('/', (req, res) => {});
// POST http://localhost:3000/books
app.post('/books', (req, res) => {});
// PUT http://localhost:3000/books/1
app.put('/books/:id', (req, res) => {});
// DELETE http://localhost:3000/books/1
app.delete('/books/:id', (req, res) => {});routing用のmiddlewareを作る仕組み。 routing部分をモジュール化(別ファイル化)することが多いため、こちらの方をよく利用します。
routingをモジュール化(router.js)
var app = express();
var router = express.Router();
router.get('/:id', (req, res) => {
// 何かの処理
});
module.exports = router;モジュールを利用する。(app.js)
var router = require('./router');
...
app.use('/books', router);
「http://localhost:3000/books/1」のroutingが有効になる
よく利用するもの
router.get('/', (req, res) => {
// 何かの処理
});- req.body
- request bodyのkey-valueペア(body-parser middlewareが必要)
- req.cookies
- cookieのkey-valueペア(cookie-parser middlewareが必要)
- req.params
/books/:idで/books/1の場合req.params.id=> 1- url pathパラメータのkey-valueペア
- req.query
/books?order=ascの場合req.query.order=> asc- リクエストパラメータのkey-valueペア
- req.get
- HTTPヘッダーの値を取得する
よく利用するもの
router.get('/', (req, res) => {
// 何かの処理
});- res.cookie
- cookieを付与
- res.set
- HTTPヘッダーを付与
- res.redirect
- 指定したPathへリダイレクト
- res.render
- テンプレートエンジンを利用して画面を生成して返却
- res.sendStatus
- ステータスコードを返却(401, 404, 500, etc...)
- ex)
res.sendStatus(401).json({...})
- res.json
- jsonを返却(200)
middlewareのhandler(実体)の基本I/Fの形 (ただし、エラーハンドラを除く)
function(req, res, next) {
// middlewareの処理
next();
}
middlewareは1つのroutingに対して複数連結して処理されるため、次のmiddlewareへ移動するためにnextを利用する。
middlewareの実行順序は宣言したもの順。エラーハンドラが最後にあるのは、それなりの理由がある。
middlewareは3種類ある
- Application-level
- Router-level
- Error-handling
var app = express();
// '/'に対するmiddleware
app.use(function (req, res, next) {
next();
});
// 'GET books/:id'に対するmiddleware
app.get('books/:id', function (req, res, next) {
next();
});var router = express.Router();
// '/'に対するmiddleware
router.use(function (req, res, next) {
next();
});
// 'GET books/:id'に対するmiddleware
router.get('books/:id', function (req, res, next) {
next();
});Application-level middlewareとRouter-level middlewareの違いについて、利用者レベルでは正直良くわからない。
使い分け方針(TPO)
- アプリ全体
- Application-level middleware
app.use()
- 特定のrouting
- Router-level middleware
router.get('/:id', someMiddleware, businessLogic)
(後述) エラーハンドリングの部分で紹介します。
** Webアプリケーションを作成するために必要なこと
- プロジェクトストラクチャ
- api
- view
- Jade
- handlebars
- mongoose
- sequalize
- エラーハンドリング
- ほぼ、node.jsの認証モジュールでデファクト
- 様々な認証に対応可能(Strategy)
- 下手に独自で認証を実装するくらいなら、Passportの使い方を習得したほうが後々潰しが効く(経験談)
対応例)
- passport-local - Username and password
- passport-twitter - Twitter
- passport-facebook - Facebook
- passport-google-oauth - Google
- and more 307 Strategies
config
app.js - passportの初期化
passport.js - sessionのserialize/deserialize、利用するStrategyの設定
passport/ - Strategyごとの認証ロジック
local.js - Username and password用
twitter.js - twitter認証用
middlewares
authorization.js - routingで利用する認証フィルタ
Session用のmiddlewareを設定する。
app.js
var passport = require('passport');
// passportモジュールをLoad
require('./passport')(app);
// session用のmiddlewaresを有効化
app.use(passport.initialize());
app.use(passport.session());Session利用のための設定(続き)&利用するStrategyを設定する
config/passport.js
module.exports = () => {
// sessionにユーザー(のキー)情報を格納する処理
passport.serializeUser((user, done) => {
done(null, user.id);
});
// sessionからユーザー情報を復元する処理
passport.deserializeUser((id, done) => {
// DBのUserテーブルからユーザーを取得する処理
User.findById(id).exec((err, user) => {
done(err, user)
});
});
// 利用するstrategyを設定
passport.use(require('./passport/local'));
passport.use(require('./passport/twitter'));
...
}Strategyの個別設定を行う
config/passport/local.js
// Strategyをロードする
var LocalStrategy = require('passport-local').Strategy;
// Strategyことの認証ロジックを追加する
module.exports = new LocalStrategy({
// 認証ロジック
});(ログインなど)特定のrouting時に認証を行うようにする。
app.post('/login',
passport.authenticate('local', { failureRedirect: '/login' }),
function(req, res) {
res.redirect('/');
});passportの作者が作ったものがある。
connect-ensure-login
予めmiddleware化しておく。 config/middlewares/authorization.js
// 認証フィルタに引っかかると`/badLoginRedirectPath`にリダイレクト
exports.authorize = require('connect-ensure-login').ensureLoggedIn('/badLoginRedirectPath');routingでmiddlewareを設定する
var auth = require('middlewares/authorization');
app.use('/some', auth.authorize, (req, res) => {
// 何かの処理
});- 動作環境ごとで異なる情報(DB接続設定、APIKey、Secret)
- production環境の設定はリポジトリにCommitせず、動作環境の環境変数から取得する
node.jsでの環境変数の取得方法
prosess.env.SOME_KEY
- セッション
- ロギング
- デプロイ(Heroku)
- 起動、監視
レスポンスのx-powered-byヘッダーを消す。
app.set('x-powered-by', false);

Uh oh!
There was an error while loading. Please reload this page.