大阪Node学園八時限目
node.jsみちしるべ

expressで作るWebアプリ
2013/10/26
スライド内のリンクはクリックできます
リンクはこの色です
express
expressとは
Webアプリケーションフレームワーク
http://expressjs.com/
sinatraライクなシンプルな構成

現状node.jsでのデファクトスタンダード

デフォルトテンプレートエンジンはjade
最新バージョンは 3.4.2
express 2.x 系とはいろいろ変わってます

大阪Node学園で取り上げるのも4回目になりました
過去の情報を参照する際はバージョンに注意してく さい 私のブログとかヹヹヹ
expressのインスール
1 $ npm install -g express
2
プロジェクトの初期化
expressコボンドでプロジェクトを初期化します
1 $ express handson

expressの依存モジュールをインストール
1 $ cd handson
2 $ npm install

これでexpres...
サーバ側の処理の追加
ブラウザから
サーバ側の処理の追加
Ctrl+C でサーバを停止し、サーバを再起動する。
1 $ node app.js
2

ブラウザで http://localhost:3000/hello にアクセスしてみる。
"hello"と表示されます。
パスとイベントハンドラの追加の仕方
パスの追加
1 app.HTTPメソッ 名('ルー か のURLパス', イベン ハン

イベントハンドラの書き方
1 function(req, res){
//ここでユーザか の入力値を け
2
//ユー...
テンプレートで値を表示
先ほ の app.get('/hello', ...); では直接文字列を返していましたが テンプレ
ートを使ってHTMLを返すように変更してみます。
handson/views/ ディレクトリに hello.jade ...
テンプレートで値を表示
app.js の res.send('Hello', ...); の部分を次のように変更します。
1 app.get('/hello', function (req, res) {
// res.send('Hello'...
アプリケーションの自動リロード
スクリプトを変更するたびに手動でサーバの再起動をしてきました。
開発中は変更後に自動で再起動されたほうが便利なので、ツールを使って自
動化します。
nodemonというモジュールを使います
1 $ npm ins...
入力値の け取り クエリ引数編
ブラウザで http://localhost:3000/hello?greeting=hoge を開きます。
hoge という文字列はま

この hoge という文字列をページに表示してみます。

こにも表示され...
入力値の け取り URLパラメータ編
次に app.get('/hello') を次のように変更します
1 app.get('/hello/:greeting', function (req, res) {
res.locals.message...
入力値の け取り URLパラメータ編
この状態で http://localhost:3000/hello や http://localhost:3000/hello/ に
アクセスするとエラーになるので

空のパラメータも け付けるようにするに...
入力値の け取り POSTデータ編
hello.jade にフォームを追加します
1 form(action="/hello", method="post")
input(type="text", name="greeting")
2
inpu...
入力値の け取り POSTデータ編
app.get('/hello'); は変更せ 、その後に次のように書きます。
1 app.post('/hello', function(req, res){
res.locals.message = re...
GETとPOST
app.get と app.post は同じURLパスでも別の処理として記述します。
GET

POST

データの取得に使われるHTTPメソッド
サーバにデータを送るときに使われるメソッド

HTTPメソッドの種類に関係なく...
jadeでテンプレートを継承する
HTMLタグやHEADタグをすべてのテンプレートファイルに書くのは面倒なの
で
ひとつのファイルに書いた内容を他のファイルでも使うように変更します。
views/layout.jade ファイルがすでにあるので...
jadeでテンプレートを継承する
hello.jade をテキストエディタで開き いったんすべての内容を削除してから、
次のように変更します。
1 extends layout
2

ブラウザをリロードすると
レイアウトデフォルトコンテンツ と...
アプリケーションワイドな値とブルパ
全てのビューで表示する値はあらかじめ設定しておくことができます。
app.js のルート設定の前に次の一行を追加します。
1 app.locals.title = 'アプ ケーションワイ なサイ タイ ル';...
アプリケーションワイドな値とブルパ
app.locals には次のように関数を設定することもできます。
1 app.locals.braced = function(str){
return '[' + str + ']';
2
3 }

設定...
セッション
セッションを使うには app.js に設定を追加します。
20行目の
1 app.use(express.bodyParser());

の後に二行設定を追加します。
1 app.use(express.cookieParser()...
セッション
セッションが使えることを確認するために
ダミーのログイン画面を作ってみましょう。
app.js にログイン画面用のルートを追加します。
1 app.get('/login', function(req, res){
res.rend...
セッション
app.js にダミーのログイン処理を追加します。
1 app.post('/login', function(req, res){
req.session.username = req.body.username;
2
res.r...
セッション
hello.jade にヤーザ名表示を表示します。
1 p としてログインしています。
2

ブラウザで http://localhost:3000/login にアクセスします。

ヤーザ名を入力してログインボタンをクリックすると...
イベントハンドラの分離
これまでにたくさんルートを追加して app.js が少し長くなったので
イベントハンドラを別ファイルに分離してすっきりさせます。
新しいファイル routes/handson.js をつくります。
app.js で今作成...
イベントハンドラの分離
次に app.js と routes/handson.js をつなげるため

いま handson.js に貼りつけたイベントハンドラに名前をつけます。
routes/handson.js

1 exports.inde...
実行時の環境変数
サーバ実行時に環境変数を渡すことができます。
1 $ NODE_ENV=production node app.js

nodemonを使っている場合も同じです。
1 $ NODE_ENV=production nodemon...
入力値のエスケープ
express-validatorというexpress用のミドルウェアがあるのでそれを使います
https://github.com/ctavan/express-validator
インストール
1 $ npm insta...
lessのコンパイル
https://github.com/emberfeather/less.js-middleware
less.js-middlewareをインストールします

npm install less-middleware

a...
データを保存する
今回はMongoDBを使います
MongoDBとは
node.jsでは最初期からモジュールがある
ドキュメント指向データベース

いまやIBM御用達
MongoDB用モジュール
MongoDB用のモジュールは大量に有ります
一番有名なのはmongooseですが、
私には使いにくいので今回はmongo-native-driverを紹 します
非公式モジュールから公式モジュールに格上げされました
mongo-native-driver
https://github.com/mongodb/node-mongodb-native
MongoDBのshellと同じような文法で書ける
多数のライブラリから利用されている

インストール
1 $...
モジュールの読み込みと初期化
MongoDBではDBとコレクション(テーブル)は自動で作成されます。
ファイルの前の方、モジュールのrequireをしている部分に以下のコードを追加
します。
1 var mongoClient = requir...
データの書き込み
/helloにPOSTされたmessageをMongoDBに書き込んでみます。
1 app.post('/hello', function(req, res){
var user_message = req.body.gree...
データの読み出し
/hello/list にアクセスした時に保存されたメッセージをすべて表示します
app.jsに以下のコードを追加します。
1 app.get('/hello/list', function (req, res) {
var ...
asyncを使ったフローコントロール
フロー制御モジュール async

https://github.com/caolan/async
フローコントロールもたくさんモジュールがありますが、asyncが一番有名です。
並列実行、逐次処理、非同期...
asyncのインストール
インストール
1 $ npm install async --save

app.js

他のモジュールと同じように、app.jsの先頭でrequireしておきます。

1 var async = require('a...
asyncの例
MongoDBで登録されたメッセージの総数と一覧を取得してみます。
1 app.get('/hello/list', function (req, res) {
var messages = mongo.collection('...
asyncの例
3行目でasyncのパラレル処理を開始しています

3行目から14行目のparallelメソッドの第一引数がオブジェクトになっていま
す
第一引数はオブジェクトか配列になります
この第一引数に並列処理したい関数を渡します
第一引...
その他のフロー制御の方法
Promiseライブラリを使う方法
Qが有名です(た し遅い)

BlueBirdという速いのが出ている

generatorベースのライブラリを使う方法
node 0.12.xから
第六回のスライドの後半で取り上げま...
Q?
Thank you!

photo by NeilGHamilton from flickr
宣伝
HTML5とJavaScriptによるiPhone/Android両対応アプリ開発ガイド
(DESIGN & WEB TECHNOLOGY)
半年ほ 前に本を書きました
大阪Node学園八時限目 「expressで作るWebアプリ」
大阪Node学園八時限目 「expressで作るWebアプリ」
大阪Node学園八時限目 「expressで作るWebアプリ」
大阪Node学園八時限目 「expressで作るWebアプリ」
Upcoming SlideShare
Loading in...5
×

大阪Node学園八時限目 「expressで作るWebアプリ」

3,378

Published on

大阪Node学園八時限目 「expressで作るWebアプリ」

  1. 1. 大阪Node学園八時限目 node.jsみちしるべ expressで作るWebアプリ 2013/10/26
  2. 2. スライド内のリンクはクリックできます リンクはこの色です
  3. 3. express
  4. 4. expressとは Webアプリケーションフレームワーク http://expressjs.com/ sinatraライクなシンプルな構成 現状node.jsでのデファクトスタンダード デフォルトテンプレートエンジンはjade
  5. 5. 最新バージョンは 3.4.2 express 2.x 系とはいろいろ変わってます 大阪Node学園で取り上げるのも4回目になりました 過去の情報を参照する際はバージョンに注意してく さい 私のブログとかヹヹヹ
  6. 6. expressのインスール 1 $ npm install -g express 2
  7. 7. プロジェクトの初期化 expressコボンドでプロジェクトを初期化します 1 $ express handson expressの依存モジュールをインストール 1 $ cd handson 2 $ npm install これでexpressが立ち上がるようになっているので動かしてみる。 1 $ node app.js ブラウザで http://localhost:3000 にアクセスする。 "Error: listen EADDRINUSE" エラーで動かない場合は p.ecstacy app.jsをテキストエディタで開き 15行目のホート番号を3000な に変 更します。
  8. 8. サーバ側の処理の追加 ブラウザから
  9. 9. サーバ側の処理の追加 Ctrl+C でサーバを停止し、サーバを再起動する。 1 $ node app.js 2 ブラウザで http://localhost:3000/hello にアクセスしてみる。 "hello"と表示されます。
  10. 10. パスとイベントハンドラの追加の仕方 パスの追加 1 app.HTTPメソッ 名('ルー か のURLパス', イベン ハン イベントハンドラの書き方 1 function(req, res){ //ここでユーザか の入力値を け 2 //ユーザに返す ータを作る 3 4 } 5 、 jQueryで 1 $('#top').on('click', function(){ //イベン ハン ング 2 3 }); と書くのと比較すると覚えやすいかと思います。 );
  11. 11. テンプレートで値を表示 先ほ の app.get('/hello', ...); では直接文字列を返していましたが テンプレ ートを使ってHTMLを返すように変更してみます。 handson/views/ ディレクトリに hello.jade という新しいファイルを作って テキ ストエディタで開きます。 内容を次のように書いてく さい。 1 h1 こんにちは 2 p #{message} へようこそ 3 ここで作成したファイルは jade というテンプレートエンジン用のテンプレートファ イルです。
  12. 12. テンプレートで値を表示 app.js の res.send('Hello', ...); の部分を次のように変更します。 1 app.get('/hello', function (req, res) { // res.send('Hello'); この行は削除する 2 res.locals.message = 'expressハンズオン'; 3 res.render('hello'); 4 5 }); 6 こんにちは expressハンズオンへようこそ と表示されます。 サーバを再起動してブラウザを再読み込みします。
  13. 13. アプリケーションの自動リロード スクリプトを変更するたびに手動でサーバの再起動をしてきました。 開発中は変更後に自動で再起動されたほうが便利なので、ツールを使って自 動化します。 nodemonというモジュールを使います 1 $ npm install -g nodemon 2 $ nodemon app.js app.jsファイルを保存し直すと、サーバが自動で再起動されます
  14. 14. 入力値の け取り クエリ引数編 ブラウザで http://localhost:3000/hello?greeting=hoge を開きます。 hoge という文字列はま この hoge という文字列をページに表示してみます。 こにも表示されていません。 app.get('/hello', ...); を次のように変更します。 1 app.get('/hello', function(req, res){ res.locals.message = req.query.greeting; 2 res.render('hello'); 3 4 }); こんにちは hogeへようこそ と表示されます。 サーバを再起動して 再度ブラウザでアクセスします。
  15. 15. 入力値の け取り URLパラメータ編 次に app.get('/hello') を次のように変更します 1 app.get('/hello/:greeting', function (req, res) { res.locals.message = req.params.greeting; 2 res.render('hello'); 3 4 }); 5 http://localhost:3000/hello/fuga サーバを再起動し ブラウザで を開くと fugaへようこそ と と表示されます。
  16. 16. 入力値の け取り URLパラメータ編 この状態で http://localhost:3000/hello や http://localhost:3000/hello/ に アクセスするとエラーになるので 空のパラメータも け付けるようにするには :greeting? のようにパラメータの最 後に?をつけます。 :greeting がないときにデフォルトの値を表示するには 1 res.locals.message = req.params.greeting || ' フォル メッセージ'; 2 のようにします。
  17. 17. 入力値の け取り POSTデータ編 hello.jade にフォームを追加します 1 form(action="/hello", method="post") input(type="text", name="greeting") 2 input(type="submit", value="送信") 3 テキストフィールドに moga と入力して送信ボタンを押します。 ブラウザをリロードするとフォームが表示されるので Cannot POST /hello というエラーになります。
  18. 18. 入力値の け取り POSTデータ編 app.get('/hello'); は変更せ 、その後に次のように書きます。 1 app.post('/hello', function(req, res){ res.locals.message = req.body.greeting; 2 res.render('hello'); 3 4 }); 5 今度はエラーになら に mogaへようこそ 表示されます。 サーバを再起動し 再度 フォームから値を送信してみます。
  19. 19. GETとPOST app.get と app.post は同じURLパスでも別の処理として記述します。 GET POST データの取得に使われるHTTPメソッド サーバにデータを送るときに使われるメソッド HTTPメソッドの種類に関係なく常に処理を実行したい場合は app.all() が使え ます
  20. 20. jadeでテンプレートを継承する HTMLタグやHEADタグをすべてのテンプレートファイルに書くのは面倒なの で ひとつのファイルに書いた内容を他のファイルでも使うように変更します。 views/layout.jade ファイルがすでにあるので これを使ってみます。 テキストエディタで layout.jadeを開き block contentの行の後に一行追加し ます。 1 block content イアウ 2 フォル コンテンツ
  21. 21. jadeでテンプレートを継承する hello.jade をテキストエディタで開き いったんすべての内容を削除してから、 次のように変更します。 1 extends layout 2 ブラウザをリロードすると レイアウトデフォルトコンテンツ と表示されます。 extends layoutのあとに2行追加します 1 extends layout 2 block content h1 helloコンテンツ 3 4 layout.jade にある block content の内容を上書きしています。 ブラウザでアクセスすると helloコンテンツ と表示されます。
  22. 22. アプリケーションワイドな値とブルパ 全てのビューで表示する値はあらかじめ設定しておくことができます。 app.js のルート設定の前に次の一行を追加します。 1 app.locals.title = 'アプ ケーションワイ なサイ タイ ル'; 2 ブラウザをリロードして、ページのタイトルが変わっていることを確認します。 テンプレートで表示はしないが アプリケーション全体で共有したい設定値な は app.set() で設定し app.get() で参照します。 1 app.set('some_setting', 'some value'); 2 app.get('some_setting'); // some value が返る 3
  23. 23. アプリケーションワイドな値とブルパ app.locals には次のように関数を設定することもできます。 1 app.locals.braced = function(str){ return '[' + str + ']'; 2 3 } 設定した関数はテンプレート内でブルパメソッドとして呼び出すことができま す。 hello.jade でこのブルパを使ってみます。 1 p #{braced('カッコつき文字列')} 2
  24. 24. セッション セッションを使うには app.js に設定を追加します。 20行目の 1 app.use(express.bodyParser()); の後に二行設定を追加します。 1 app.use(express.cookieParser()); 2 app.use(express.session({key: 'sess_id', secret: 'salt'})); 3 これでセッションが使えるようになりました。 express.sessionはデフォルトでメモリ上にセッション情報を保存するので実運 用には向きません
  25. 25. セッション セッションが使えることを確認するために ダミーのログイン画面を作ってみましょう。 app.js にログイン画面用のルートを追加します。 1 app.get('/login', function(req, res){ res.render('login'); 2 3 }); 4 views/login.jade を新規作成します。 1 extends layout 2 block content form(action="/login", method="post") 3 label ユーザ名 4 input(type="text", name="username") 5 input(type="submit", value="ログイン") 6
  26. 26. セッション app.js にダミーのログイン処理を追加します。 1 app.post('/login', function(req, res){ req.session.username = req.body.username; 2 res.redirect('/hello'); 3 4 }); 5 http://localhost:3000/hello でログイン名を表示できるようにします。 1 app.get('/hello', function(req, res){ res.locals.username = req.session.username; 2 res.render('hello'); 3 4 }); 5
  27. 27. セッション hello.jade にヤーザ名表示を表示します。 1 p としてログインしています。 2 ブラウザで http://localhost:3000/login にアクセスします。 ヤーザ名を入力してログインボタンをクリックすると /hello にリダイレクトされ 入力したヤーザ名としてログインしています と表示されます。
  28. 28. イベントハンドラの分離 これまでにたくさんルートを追加して app.js が少し長くなったので イベントハンドラを別ファイルに分離してすっきりさせます。 新しいファイル routes/handson.js をつくります。 app.js で今作成したファイルを読み込みます。 場所は app.get('/hello', ...); の前にします。 1 var handson = require('./routes/handson'); 2 app.get('/hello', ...); 3
  29. 29. イベントハンドラの分離 次に app.js と routes/handson.js をつなげるため いま handson.js に貼りつけたイベントハンドラに名前をつけます。 routes/handson.js 1 exports.index = function(req, res){ res.locals.username = req.session.username; 2 res.render('hello'); 3 4 } 5 最後に 今名前をつけた関数を app.js で呼び出します。 app.js 1 app.get('/hello', handson.index);
  30. 30. 実行時の環境変数 サーバ実行時に環境変数を渡すことができます。 1 $ NODE_ENV=production node app.js nodemonを使っている場合も同じです。 1 $ NODE_ENV=production nodemon app.js 2 スクリプト内では process.env で環境変数を参照できます。 app.js の最後に以下の一行を追加してみます。 1 console.log(process.env.NODE_ENV); コンソールの最後にproduction と表示されます。 process.env の代わりに app.get('env') でも同じ結果を得られます。 1 console.log(app.get('env'));
  31. 31. 入力値のエスケープ express-validatorというexpress用のミドルウェアがあるのでそれを使います https://github.com/ctavan/express-validator インストール 1 $ npm install express-validator --save --saveオプションをつけておくとインストールしたパッケージがpackage.jsonに 自動で追加されます app.jsの先頭でモジュールを読み込んで、 ミドルウェアの組み込み bodyParserの後でミドルウェアを有効にします。 1 var validator = require('express-validator'); 2 (略) app.use(express.bodyParser()); 3 app.use(validator()); 4 5 (略)
  32. 32. lessのコンパイル https://github.com/emberfeather/less.js-middleware less.js-middlewareをインストールします npm install less-middleware app.use(express.static)の前に入れる必要があります ミドルウェアを有効にします var lessMiddleware = require('less-middleware'); (略) app.use(lessMiddleware({ dest: __dirname + '/public/css', src: __dirname + '/public/less', //force: true, compress: true })); app.use(express.static(__dirname + '/public')); (略)
  33. 33. データを保存する 今回はMongoDBを使います MongoDBとは node.jsでは最初期からモジュールがある ドキュメント指向データベース いまやIBM御用達
  34. 34. MongoDB用モジュール MongoDB用のモジュールは大量に有ります 一番有名なのはmongooseですが、 私には使いにくいので今回はmongo-native-driverを紹 します 非公式モジュールから公式モジュールに格上げされました
  35. 35. mongo-native-driver https://github.com/mongodb/node-mongodb-native MongoDBのshellと同じような文法で書ける 多数のライブラリから利用されている インストール 1 $ npm install mongodb --save
  36. 36. モジュールの読み込みと初期化 MongoDBではDBとコレクション(テーブル)は自動で作成されます。 ファイルの前の方、モジュールのrequireをしている部分に以下のコードを追加 します。 1 var mongoClient = require('mongodb').MongoClient; 2 var mongo = null; 3 続いて、ミドルウェア内でコネクションを初期化します 1 app.use(function(req, res, next){ mongoClient.connect('mongodb://127.0.0.1:27017/handson', 2 function(err, db) { 3 if(err) throw err; 4 mongo = db; 5 next(); 6 } 7 ); 8 9 });
  37. 37. データの書き込み /helloにPOSTされたmessageをMongoDBに書き込んでみます。 1 app.post('/hello', function(req, res){ var user_message = req.body.greeting; 2 var messages = mongo.collection('messages'); 3 messages.insert({message: user_message}, function (err, doc) { 4 res.locals.message = doc[0].message; 5 res.render('hello'); 6 }); 7 8 }); hello.jade に次の二行を付け足すと、 (入力したメッセージ)が保存されました と表示されます。 if message p が保存されました。
  38. 38. データの読み出し /hello/list にアクセスした時に保存されたメッセージをすべて表示します app.jsに以下のコードを追加します。 1 app.get('/hello/list', function (req, res) { var messages = mongo.collection('messages'); 2 messages.find().toArray(function (err, data) { 3 res.locals.data = data; 4 res.render('hello'); 5 }); 6 7 }); hello.jadeに以下のコードを追加します 1 h2 保存されたメッセージ 2 ul 3 each datum in data li= datum.message 4 ブラウザで http://localhost:3000/hello/list にアクセスすると保存したメッセ ージの一覧が表示されます。
  39. 39. asyncを使ったフローコントロール フロー制御モジュール async https://github.com/caolan/async フローコントロールもたくさんモジュールがありますが、asyncが一番有名です。 並列実行、逐次処理、非同期処理の終了待ちな ができます。 フロー制御のほか、コレクションのイテレーションもできます。
  40. 40. asyncのインストール インストール 1 $ npm install async --save app.js 他のモジュールと同じように、app.jsの先頭でrequireしておきます。 1 var async = require('async');
  41. 41. asyncの例 MongoDBで登録されたメッセージの総数と一覧を取得してみます。 1 app.get('/hello/list', function (req, res) { var messages = mongo.collection('messages'); 2 async.parallel({ 3 total: function (callback) { 4 messages.count(function (err, count) { 5 callback(err, count); 6 }); 7 }, 8 list: function (callback) { 9 messages.find().toArray(function (err, data) { 10 callback(err, data); 11 }); 12 } 13 }, function (err, results) { 14 res.locals.data = results.list; 15 res.locals.total = results.total; 16 res.render('hello'); 17 }); 18 19 });
  42. 42. asyncの例 3行目でasyncのパラレル処理を開始しています 3行目から14行目のparallelメソッドの第一引数がオブジェクトになっていま す 第一引数はオブジェクトか配列になります この第一引数に並列処理したい関数を渡します 第一引数内に置く関数にはデフォルトで関数が渡されます 処理が終了したらこの関数を呼び出して、明示的に終了を知らせます 全ての関数が終了すると14行目から18行目にある関数が呼び出されるの で、ここで結果を け取ります
  43. 43. その他のフロー制御の方法 Promiseライブラリを使う方法 Qが有名です(た し遅い) BlueBirdという速いのが出ている generatorベースのライブラリを使う方法 node 0.12.xから 第六回のスライドの後半で取り上げました
  44. 44. Q?
  45. 45. Thank you! photo by NeilGHamilton from flickr
  46. 46. 宣伝 HTML5とJavaScriptによるiPhone/Android両対応アプリ開発ガイド (DESIGN & WEB TECHNOLOGY) 半年ほ 前に本を書きました
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×