91
EWD 3 トトトトトト トトト #31 ewd-xpress ト Web トトト REST トトトトトトト M/Gateway Developments Ltd. Rob Tweed ト : トトトトトトトトトトトトト ト トト GT.M トトト : トト ト ※ トトトトトトトト Cache’ トトトトトトト

EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

Embed Size (px)

Citation preview

Page 1: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

EWD 3トレーニング・コース  #31

ewd-xpress で Web および REST

サービスを作るM/Gateway Developments Ltd.

Rob Tweed訳 : 日本ダイナシステム株式会社 嶋 芳成

GT.M 版編集 : 澤田 潔

※ 本稿オリジナルは Cache’ 向けとして編纂

Page 2: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

2

REST のための EWD 3 バックエンド

• 2つのアプローチが可能• EWD 3 モジュールを用いて自分の REST を構築

する• ewd-xpress を拡張する

2016/9/9 EWD 3 トレーニング・コース #31

Page 3: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

3

REST のための EWD 3 バックエンド

• EWD 3 モジュールを用いて独自の REST を構築する• 例えば  ewd-qoper8-vistapc がどのように作ら

れたか• 利点

• EWD 3 の部品の内、本当に必要なものだけを利用し、構造を最適化することができます

• 互換性の問題を考えずに、サード・パーティのモジュールを容易に加えることができます

• 欠点• EWD 3 の部品のインターフェースや統合方法について、

十分に理解している必要があります

2016/9/9 EWD 3 トレーニング・コース #31

Page 4: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

4

REST のための EWD 3 バックエンド

• ewd-xpress を拡張する• 利点

• 既に必要なものはすべてインストールされ、正しくインターフェースされ構成されているのでそれを利用できます

• 実際には、他のサード・パーティのモジュールは、非互換性の恐れをあまり考えずに追加することができます

• 単一のバックエンドで、 Web / REST サービスと対話的なアプリケーションを同時にサポートできます

• 欠点• REST / Web サービスのみが必要の場合、対話的なアプ

リケーション用のコードは利用されません ... しかしこれは大したことではないでしょう!

2016/9/9 EWD 3 トレーニング・コース #31

Page 5: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

5

REST サービスのための ewd-xpress• 従って、ほとんどの場合、 REST / Web サー

ビスを作るには ewd-xpress を用いるのが最善です

2016/9/9 EWD 3 トレーニング・コース #31

Page 6: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

6

ewd-xpress の起動ファイルの例var config = { managementPassword: 'keepThisSecret!', serverName: 'My EWD Server', port: 8080, poolSize: 2, database: { type: ‘gtm', params: { // snip } }};var ewdXpress = require('ewd-xpress').master;ewdXpress.start(config)

2016/9/9 EWD 3 トレーニング・コース #31

Page 7: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

7

Express ミドルウェアを利用する必要性

• REST / Web サービスをサポートする要点は、ミドルウェアの Express を追加することです• REST / Web サービスは HTTP(S) 要求と応答を

用います• Express は特定の URL パスの前方部分を監視す

る必要があります• 対応する要求が来たときには、それを処理するた

めワーカー・プロセスに渡す必要があります

2016/9/9 EWD 3 トレーニング・コース #31

Page 8: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

8

Express ミドルウェアを利用する必要性

• EWD 3 にはそのようなモジュールが既に用意してあります• ewd-qoper8-express• これは ewd-qoper8 を統合する組み込みのルー

タを含みます

• ewd-xpress はそれを含んでおり、 Ajaxメッセージのためにそれを用いています• REST / Web サービスにおいて直接それを利

用することはありません• しかし、直接利用することもできます

2016/9/9 EWD 3 トレーニング・コース #31

Page 9: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

9

ewd-xpress の起動ファイルvar config = { managementPassword: 'keepThisSecret!', serverName: 'My EWD Server', port: 8080, poolSize: 2, database: { type: ‘gtm', params: { // snip } }};var ewdXpress = require('ewd-xpress').master;var exprss = ewdXpress.intercept();

ewdXpress.start(config)

2016/9/9 EWD 3 トレーニング・コース #31

Page 10: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

10

ewd-xpress の起動ファイルvar config = { managementPassword: 'keepThisSecret!', serverName: 'My EWD Server', port: 8080, poolSize: 2, database: { type: ‘gtm', params: { // snip } }};var ewdXpress = require('ewd-xpress').master;var exprss = ewdXpress.intercept();

// これで、次のものにアクセスできるようになります// ewd-qoper8 object: exprss.q// ewd-qoper8-xpress: exprss.qx// Express middleware: exprss.app

ewdXpress.start(config)

2016/9/9 EWD 3 トレーニング・コース #31

Page 11: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

11

単純な Web サービスvar config = { managementPassword: 'keepThisSecret!', serverName: 'My EWD Server', port: 8080, poolSize: 2, database: { type: ‘gtm', params: { // snip } }};var ewdXpress = require('ewd-xpress').master;var exprss = ewdXpress.intercept();

exprss.app.use('/testWebService', exprss.qx.router());

ewdXpress.start(config)

2016/9/9 EWD 3 トレーニング・コース #31

Page 12: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

12

単純な Web サービスvar config = { managementPassword: 'keepThisSecret!', serverName: 'My EWD Server', port: 8080, poolSize: 2, database: { type: ‘gtm', params: { // snip } }};var ewdXpress = require('ewd-xpress').master;var exprss = ewdXpress.intercept();exprss.app.use('/testWebService', exprss.qx.router());

// 「 /testWebService 」 で始まる URL のリクエストを受信すると、それをワーカーに渡し// 「 testWebService 」 という名前のモジュールで処理します

ewdXpress.start(config)

2016/9/9 EWD 3 トレーニング・コース #31

Page 13: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

13

試してみましょう

2016/9/9 EWD 3 トレーニング・コース #31

Page 14: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

14

適切な HTTP クライアントを利用する• ブラウザは、 GET 要求をテストすることしか

できません• POST や他の要求 ( 例えば DELETE 、 PUT) を

テストする必要もあります

• Web サービスや REST のクライアントが利用できます• Postman• 私は Chrome の Advanced REST Client

(ARC)  を用いています

2016/9/9 EWD 3 トレーニング・コース #31

Page 15: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

15

試してみましょう

2016/9/9 EWD 3 トレーニング・コース #31

Page 16: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

16

エラーを修正する

• もちろん、要求を処理するバックエンド・モジュールをまだ作っていません• モジュール名は URL パスと同じ名前です• ~/ewd3/node_modules/testWebService.js

2016/9/9 EWD 3 トレーニング・コース #31

Page 17: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

17

REST を処理するモジュール

• ewd-xpress のメッセージを処理するモジュールに極めて似ています

2016/9/9 EWD 3 トレーニング・コース #31

Page 18: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

18

REST を処理するモジュールmodule.exports = {

restModule: true,

handlers: { // 要求の type 毎に異なるハンドラ関数 }};

2016/9/9 EWD 3 トレーニング・コース #31

Page 19: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

19

REST を処理するモジュールmodule.exports = {

restModule: true, // ewd-xpress にこれは REST ハンドラだと教えています

handlers: { // 要求の type 毎に異なるハンドラ関数 }};

REST だけでなく、すべての Web サービス要求

2016/9/9 EWD 3 トレーニング・コース #31

Page 20: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

20

REST を処理するモジュールmodule.exports = {

restModule: true,

handlers: {

{type}: function(messageObj, finished) { // 受信したこの type の要求に対するハンドラ }

}};

2016/9/9 EWD 3 トレーニング・コース #31

Page 21: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

21

REST を処理するモジュールmodule.exports = {

restModule: true,

handlers: {

myType: function(messageObj, finished) { // 受信した myType 要求に対するハンドラ }

}};

2016/9/9 EWD 3 トレーニング・コース #31

Page 22: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

22

REST を処理するモジュール~/ewd3/node_modules/testWebService.js

module.exports = {

restModule: true,

handlers: {

myType: function(messageObj, finished) { // 受信した myType 要求に対するハンドラ }

}};

http://192.168.1.100:8080/testWebService/myType

2016/9/9 EWD 3 トレーニング・コース #31

Page 23: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

23

REST を処理するモジュール~/ewd3/node_modules/testWebService.js

module.exports = {

restModule: true,

handlers: {

myType: function(messageObj, finished) { // 受信した myType 要求に対するハンドラ // URL の残りの部分は、 messageObj.properties でアクセス可能 }

}};

http://192.168.1.100:8080/testWebService/myType/xyz?a=245&b=rob

2016/9/9 EWD 3 トレーニング・コース #31

Page 24: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

24

REST を処理するモジュール~/ewd3/node_modules/testWebService.js

module.exports = {

restModule: true,

handlers: {

myType: function(messageObj, finished) { // 受信したメッセージ・オブジェクトを処理し、応答オブジェクトを生成 // finished() 関数を呼び出して終了しなくてはなりません // - 応答オブジェクトをクライアントに送信 // - ワーカー・プロセスを利用可能なプールに戻す finished(responseObject); }

}};

http://192.168.1.100:8080/testWebService/myType

2016/9/9 EWD 3 トレーニング・コース #31

Page 25: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

25

REST を処理するモジュール~/ewd3/node_modules/testWebService.js

module.exports = {

restModule: true,

handlers: {

myType: function(messageObj, finished) { console.log("*** myType messageObj: " + JSON.stringify(messageObj)); finished({ test: 'finished ok' }); } }};

http://192.168.1.100:8080/testWebService/myType

2016/9/9 EWD 3 トレーニング・コース #31

Page 26: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

26

試してみましょう

2016/9/9 EWD 3 トレーニング・コース #31

Page 27: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

27

ewd-xpress のログをみてみる*** myType messageObj: { "type":"ewd-qoper8-xpress", "path":"/testWebService/myType", "method":"GET", "headers":{ "host":"192.168.1.183:8080", "content-type":"application/json" }, "params":{ "type":"myType" }, "query":{}, "application":"testWebService", "expressType":"myType"}

2016/9/9 EWD 3 トレーニング・コース #31

Page 28: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

28

ewd-xpress のログをみてみる*** myType messageObj: { "type":"ewd-qoper8-xpress", "path":"/testWebService/myType", "method":"GET", "headers":{ "host":"192.168.1.183:8080", "content-type":"application/json" }, "params":{ "type":"myType" }, "query":{}, "application":"testWebService", "expressType":"myType"}

2016/9/9 EWD 3 トレーニング・コース #31

受信した HTTP 要求のすべての要素は分解されて、受信したメッセージ・オブジェクトの中で利用可能です

これは ewd-qoper8-express のルータが行っていることです

Page 29: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

29

簡単な Web サービスvar config = { managementPassword: 'keepThisSecret!', serverName: 'My EWD Server', port: 8080, poolSize: 2, database: { type: ‘gtm', params: { // snip } }};

var ewdXpress = require('ewd-xpress').master;var xprss = ewdXpress.intercept();exprss.app.use('/testWebService', express.qx.router());

ewdXpress.start(config);

2016/9/9 EWD 3 トレーニング・コース #31

Page 30: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

30

ewd-xpress のログをみてみる*** myType messageObj: { "type":"ewd-qoper8-xpress", "path":"/testWebService/myType", "method":"GET", "headers":{ "host":"192.168.1.183:8080", "content-type":"application/json" }, "params":{ "type":"myType" }, "query":{}, "application":"testWebService", "expressType":"myType"}

2016/9/9 EWD 3 トレーニング・コース #31

REST の type は、 expressType というプロパティの中に定義されていますtype プロパティではないことに注意

Page 31: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

31

ewd-xpress のログをみてみる*** myType messageObj: { "type":"ewd-qoper8-xpress", "path":"/testWebService/myType", "method":"GET", "headers":{ "host":"192.168.1.183:8080", "content-type":"application/json" }, "params":{ "type":"myType" }, "query":{}, "application":"testWebService", "expressType":"myType"}

2016/9/9 EWD 3 トレーニング・コース #31

REST の type は、 expressType というプロパティの中に定義されていますtype プロパティではないことに注意

しかし、 params.type 経由でも利用可能です

Page 32: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

32

ewd-xpress のログをみてみる*** myType messageObj: { "type":"ewd-qoper8-xpress", "path":"/testWebService/myType", "method":"GET", "headers":{ "host":"192.168.1.183:8080", "content-type":"application/json" }, "params":{ "type":"myType" }, "query":{}, "application":"testWebService", "expressType":"myType"}

2016/9/9 EWD 3 トレーニング・コース #31

メソッドを知りたいということがしばしばあります例えば、 GET か POST か

Page 33: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

33

ewd-xpress のログをみてみる*** myType messageObj: { "type":"ewd-qoper8-xpress", "path":"/testWebService/myType", "method":"GET", "headers":{ "host":"192.168.1.183:8080", "content-type":"application/json" }, "params":{ "type":"myType" }, "query":{}, "application":"testWebService", "expressType":"myType"}

2016/9/9 EWD 3 トレーニング・コース #31

また、ヘッダーの情報を使いたい場合もあります特に、セキュリティの処理などに使う場合です

Page 34: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

34

REST を処理するモジュール~/ewd3/node_modules/testWebService.js

module.exports = {

restModule: true,

handlers: {

myType: function(messageObj, finished) { // 受信した myType 要求に対するハンドラ // URL の残りの部分は、 messageObj.properties でアクセス可能 }

}};

http://192.168.1.100:8080/testWebService/myType/xyz?a=245&b=rob

2016/9/9 EWD 3 トレーニング・コース #31

Page 35: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

35

試してみましょう

2016/9/9 EWD 3 トレーニング・コース #31

Page 36: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

36

ewd-xpress のログをみてみる*** myType messageObj: { "type":"ewd-qoper8-xpress", "path":"/testWebService/myType/xyz?a=245&b=rob", "method":"GET", "headers":{ "host":"192.168.1.183:8080", "content-type":"application/json" }, "params":{ "0":"xyz", "type":"myType" }, "query":{ "a":"245", "b":"rob" }, "application":"testWebService", "expressType":"myType"}

2016/9/9 EWD 3 トレーニング・コース #31

Page 37: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

37

ewd-xpress のログをみてみる*** myType messageObj: { "type":"ewd-qoper8-xpress", "path":"/testWebService/myType/xyz?a=245&b=rob", "method":"GET", "headers":{ "host":"192.168.1.183:8080", "content-type":"application/json" }, "params":{ "0":"xyz", "type":"myType" }, "query":{ "a":"245", "b":"rob" }, "application":"testWebService", "expressType":"myType"}

2016/9/9 EWD 3 トレーニング・コース #31

完全なパスを得ることができます

Page 38: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

38

ewd-xpress のログをみてみる*** myType messageObj: { "type":"ewd-qoper8-xpress", "path":"/testWebService/myType/xyz?a=245&b=rob", "method":"GET", "headers":{ "host":"192.168.1.183:8080", "content-type":"application/json" }, "params":{ "0":"xyz", "type":"myType" }, "query":{ "a":"245", "b":"rob" }, "application":"testWebService", "expressType":"myType"}

2016/9/9 EWD 3 トレーニング・コース #31

URL パスの 3 番目の部分は、 params['0'] に入っています

Page 39: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

39

ewd-xpress のログをみてみる*** myType messageObj: { "type":"ewd-qoper8-xpress", "path":"/testWebService/myType/xyz?a=245&b=rob", "method":"GET", "headers":{ "host":"192.168.1.183:8080", "content-type":"application/json" }, "params":{ "0":"xyz", "type":"myType" }, "query":{ "a":"245", "b":"rob" }, "application":"testWebService", "expressType":"myType"}

2016/9/9 EWD 3 トレーニング・コース #31

URL の問い合わせ文字列の名前 /値のペアは、パースされて query オブジェクトに入ります

   query.a query.b

Page 40: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

40

さらに長い URL の場合は?

2016/9/9 EWD 3 トレーニング・コース #31

Page 41: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

41

試してみましょう

2016/9/9 EWD 3 トレーニング・コース #31

Page 42: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

42

ewd-xpress のログをみてみる*** myType messageObj: { "type":"ewd-qoper8-xpress", "path":"/testWebService/myType/how/about/this?a=245&b=rob", "method":"GET", "headers":{ "host":"192.168.1.183:8080", "content-type":"application/json" }, "params":{ "0":"how/about/this", "type":"myType" }, "query":{ "a":"245", "b":"rob" }, "application":"testWebService", "expressType":"myType"}

2016/9/9 EWD 3 トレーニング・コース #31

URL の追加部分は、すべてひとつにして params['0'] の中に入っています

Page 43: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

43

ewd-xpress のログをみてみる*** myType messageObj: { "type":"ewd-qoper8-xpress", "path":"/testWebService/myType/how/about/this?a=245&b=rob", "method":"GET", "headers":{ "host":"192.168.1.183:8080", "content-type":"application/json" }, "params":{ "0":"how/about/this", "type":"myType" }, "query":{ "a":"245", "b":"rob" }, "application":"testWebService", "expressType":"myType"}

2016/9/9 EWD 3 トレーニング・コース #31

URL の追加部分は、すべてひとつにして params['0'] の中に入っています

var pathArr =params['0'].split('/');でパースすることができます

Page 44: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

44

POST + 搭載物 (ペイロード ) の処理•搭載物 (ペイロード ) /本体 を送る他の

HTTP メソッドにも次のことが適用されます

2016/9/9 EWD 3 トレーニング・コース #31

Page 45: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

45

POST + 搭載物 (ペイロード ) の処理• ewd-xpress はもともと JSONベースの

REST / Web サービスのために設計されました• 搭載物 (ペイロード ) /本体 は JSON でなくては

なりません

• ewd-xpress は実際には、どのような content-type でも処理することができます• しかし、他のバックエンドの NPM モジュールを

追加して構成する必要があります

• ここでは、 application/json のコンテンツに焦点を絞ります

2016/9/9 EWD 3 トレーニング・コース #31

Page 46: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

46

試してみましょう

2016/9/9 EWD 3 トレーニング・コース #31

POST メソッド

コンテント・タイプに注意

JSON のペイロード注意 : これは適切な JSON

書式でなくてはならず、 JavaScript の文字列フォーマットではいけません

即ち、名前も値も「 " 」で囲みます

Page 47: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

47

試してみましょう

2016/9/9 EWD 3 トレーニング・コース #31

成功した結果

Page 48: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

48

ewd-xpress のログでは*** myType messageObj: { "type":"ewd-qoper8-xpress", "path":"/testWebService/myType/", "method":"POST", "headers":{ "host":"192.168.1.183:8080", "content-type":"application/json", "content-length":"30" }, "params":{ "type":"myType" }, "query":{}, "application":"testWebService", "expressType":"myType"}

2016/9/9 EWD 3 トレーニング・コース #31

コンテンツがあったと記録されています

Page 49: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

49

ewd-xpress のログでは*** myType messageObj: { "type":"ewd-qoper8-xpress", "path":"/testWebService/myType/", "method":"POST", "headers":{ "host":"192.168.1.183:8080", "content-type":"application/json", "content-length":"30" }, "params":{ "type":"myType" }, "query":{}, "application":"testWebService", "expressType":"myType"}

2016/9/9 EWD 3 トレーニング・コース #31

しかし、本体/ペイロードはどこに?

Page 50: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

50

Express のコンテントのパーシング• Express では、搭載物 (ペイロード ) /本体

の中の JSON をパースするには、そのように明確に指示しなくてはなりません• ミドルウェアはそのためにあるのです !

• body-parser という名前の NPM モジュールがあります

• これをインストールしなくてはなりません• 実際には、 ewd-xpress をインストールしたときに、

これは自動的にインストールされています• ~/ewd3/node_modules/body-parser を見てください• しかし、これをロードして利用するには、 ewd-xpress

のスタート・アップファイル内で明確に指定しなくてはなりません

2016/9/9 EWD 3 トレーニング・コース #31

Page 51: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

51

ewd-xpress の起動ファイルを編集する

var config = { managementPassword: 'keepThisSecret!', serverName: 'My EWD Server', port: 8080, poolSize: 2, database: { type: ‘gtm', params: { // snip } }};var ewdXpress = require('ewd-xpress').master;var exprss = ewdXpress.intercept();var bodyParser = require('body-parser');exprss.app.use(bodyParser.json());express.app.use('/testWebService', express.qx.router());

ewdXpress.start(config)

2016/9/9 EWD 3 トレーニング・コース #31

Page 52: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

52

ewd-xpress を再起動して再試行

2016/9/9 EWD 3 トレーニング・コース #31

Page 53: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

53

ewd-xpress のログでは*** myType messageObj: { "type":"ewd-qoper8-xpress", "path":"/testWebService/myType/", "method":"POST", "headers":{ "host":"192.168.1.183:8080", "content-type":"application/json", "content-length":"30" }, "params":{ "type":"myType" }, "query":{}, "body":{ "c":"hello", "d":"world" }, "application":"testWebService", "expressType":"myType"}

2016/9/9 EWD 3 トレーニング・コース #31

本体 (body) の内容は、パースされて、messageObj.body の中で利用できます

Page 54: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

54

本体 + 名前/値 のペア?

• POST された HTTP 要求に、本体/搭載物(ペイロード ) だけでなく• もっと URL パスの長いもの• 追加的な 名前/値のペア の問い合わせ文字列

 をもつことはできるでしょうか?

2016/9/9 EWD 3 トレーニング・コース #31

Page 55: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

55

試してみましょう

2016/9/9 EWD 3 トレーニング・コース #31

試す URL はココ

ペイロードを組み合わせる

正常に稼働している

Page 56: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

56

また ewd-xpress のログをチェック*** myType messageObj: { "type":"ewd-qoper8-xpress", "path":"/testWebService/myType/how/about/this?a=123&b=rob", "method":"POST", "headers":{ "host":"192.168.1.183:8080", "content-type":"application/json", "content-length":"30" }, "params":{ "0":"how/about/this", "type":"myType" }, "query":{ "a":"123" "b":"rob" }, "body":{ "c":"hello", "d":"world" }, "application":"testWebService", "expressType":"myType"}

2016/9/9 EWD 3 トレーニング・コース #31

長い URL パスはこちら

Page 57: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

57

また ewd-xpress のログをチェック*** myType messageObj: { "type":"ewd-qoper8-xpress", "path":"/testWebService/myType/how/about/this?a=123&b=rob", "method":"POST", "headers":{ "host":"192.168.1.183:8080", "content-type":"application/json", "content-length":"30" }, "params":{ "0":"how/about/this", "type":"myType" }, "query":{ "a":"123" "b":"rob" }, "body":{ "c":"hello", "d":"world" }, "application":"testWebService", "expressType":"myType"}

2016/9/9 EWD 3 トレーニング・コース #31

URL の残りの部分はパースされてここに

Page 58: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

58

また ewd-xpress のログをチェック*** myType messageObj: { "type":"ewd-qoper8-xpress", "path":"/testWebService/myType/how/about/this?a=123&b=rob", "method":"POST", "headers":{ "host":"192.168.1.183:8080", "content-type":"application/json", "content-length":"30" }, "params":{ "0":"how/about/this", "type":"myType" }, "query":{ "a":"123" "b":"rob" }, "body":{ "c":"hello", "d":"world" }, "application":"testWebService", "expressType":"myType"}

2016/9/9 EWD 3 トレーニング・コース #31

問い合わせ文字列の 名前/値 のペアを保持する query オブジェクトはここに

Page 59: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

59

また ewd-xpress のログをチェック*** myType messageObj: { "type":"ewd-qoper8-xpress", "path":"/testWebService/myType/how/about/this?a=123&b=rob", "method":"POST", "headers":{ "host":"192.168.1.183:8080", "content-type":"application/json", "content-length":"30" }, "params":{ "0":"how/about/this", "type":"myType" }, "query":{ "a":"123" "b":"rob" }, "body":{ "c":"hello", "d":"world" }, "application":"testWebService", "expressType":"myType"}

2016/9/9 EWD 3 トレーニング・コース #31

POST された搭載物 (ペイロード ) を含む body オブジェクトがここに

Page 60: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

60

バックエンドの REST type ハンドラ• これで、バックエンドの type ハンドラ関数

には、受信した REST および Web サービスへの要求の処理必要な情報がすべて渡されました• これをどのように処理するかはあなた次第で

す•データベースへは次の方法でアクセスできま

す• this.db

• 例えば this.db.function() で従来の MUMPS コードを呼び出す

• this.documentStore2016/9/9 EWD 3 トレーニング・コース #31

Page 61: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

61

例えば• ~/ewd3/node_modules/testWebService.js

module.exports = { restModule: true, handlers: { myType: function(messageObj, finished) { console.log('*** myType messageObj: ' + JSON.stringify(messageObj)); console.log(this.db.version()); var doc = new this.documentStore.DocumentNode('myDoc'); var myObj = { hello: 'world' } doc.setDocument(myObj); finished({ test: 'finished ok' }); } }};

2016/9/9 EWD 3 トレーニング・コース #31

Page 62: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

62

バックエンド・モジュールの違いの要点• 次の2つの違い• 対話型アプリケーションにおけるメッセージの処

理に使われるもの• REST / Web サービスの要求の処理に使われるも

2016/9/9 EWD 3 トレーニング・コース #31

Page 63: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

63

バックエンド・モジュールの違いの要点• ~/ewd3/node_modules/testWebService.js

module.exports = { restModule: true, handlers: { myType: function(messageObj, finished) { console.log('*** myType messageObj: ' + JSON.stringify(messageObj)); finished({ test: 'finished ok' }); } }};

2016/9/9 EWD 3 トレーニング・コース #31

send() 関数なし

EWD セッションなし

Page 64: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

64

send 関数がない?

• REST と Web サービスは、 HTTPベース• ひとつの要求がひとつの応答を生成します

• 従って、中間メッセージは不適切です

2016/9/9 EWD 3 トレーニング・コース #31

Page 65: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

65

send 関数がない?

• REST と Web サービスは、 HTTPベース• ひとつの要求がひとつの応答を生成します

• 従って、中間メッセージは不適切です• それがあっても良いですが、しかし、ある/すべ

てのブラウザにメッセージを送るハンドラ関数は、web-socket 経由です !

2016/9/9 EWD 3 トレーニング・コース #31

Page 66: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

66

EWD セッションがない?

• REST と Web サービスは、ステート (状態 )レスです• アプリケーションにはリンクしません•暗黙的な EWD セッションは不適切です

2016/9/9 EWD 3 トレーニング・コース #31

Page 67: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

67

EWD セッションがない?

• REST と Web サービスは、ステート (状態 )レスです• アプリケーションにはリンクしません•暗黙的な EWD セッションは不適切です

• しかし、独自のハンドラで EWD セッションを生成し維持することは可能です• このために ewd-session モジュールを使うこと

ができます• this.sessions

• これが何かというこを知っている必要はあります2016/9/9 EWD 3 トレーニング・コース #31

Page 68: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

68

REST / Web サービスでセッションを使う• ログイン要求のハンドラを作ります• セキュリティのためには、 POST 要求である

べきでしょう•ユーザー名、パスワードは本体の搭載物 (ペ

イロード ) 内に定義されるべきです

2016/9/9 EWD 3 トレーニング・コース #31

Page 69: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

69

REST / Web サービスでセッションを使うfunction checkLogin(username,password) { if (username !== 'rob') return {error: 'Invalid username'}; if (password !== 'secret') return {error: 'Invalid password'}; return {ok: true}};module.exports = { restModule: true, handlers: { login: function(messageObj, finished) { if (messageObj.method !== 'POST') { finished({error: 'login message must use POST method'}); return; } var username = messageObj.body.username; if (!username || username === '') { finished({error: 'You must provide a username'}); return; } var password = messageObj.body.password; if (!password || password === '') { finished({error: 'You must provide a password'}); return; } var status = checkLogin(username, password); if (status.error) { finished(status); return; } var session = this.sessios.create('testWebService', 3600); session.authenticated = true; finished({token: session.token}); } }}

2016/9/9 EWD 3 トレーニング・コース #31

Page 70: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

70

REST / Web サービスでセッションを使うfunction checkLogin(username,password) { if (username !== 'rob') return {error: 'Invalid username'}; if (password !== 'secret') return {error: 'Invalid password'}; return {ok: true}};module.exports = { restModule: true, handlers: { login: function(messageObj, finished) { if (messageObj.method !== 'POST') { finished({error: 'login message must use POST method'}); return; } var username = messageObj.body.username; if (!username || username === '') { finished({error: 'You must provide a username'}); return; } var password = messageObj.body.password; if (!password || password === '') { finished({error: 'You must provide a password'}); return; } var status = checkLogin(username, password); if (status.error) { finished(status); return; } var session = this.sessios.create('testWebService', 3600); session.authenticated = true; finished({token: session.token}); } }}

2016/9/9 EWD 3 トレーニング・コース #31

セキュリティ上の理由で、 POST要求でなくてはなりません

Page 71: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

71

REST / Web サービスでセッションを使うfunction checkLogin(username,password) { if (username !== 'rob') return {error: 'Invalid username'}; if (password !== 'secret') return {error: 'Invalid password'}; return {ok: true}};module.exports = { restModule: true, handlers: { login: function(messageObj, finished) { if (messageObj.method !== 'POST') { finished({error: 'login message must use POST method'}); return; } var username = messageObj.body.username; if (!username || username === '') { finished({error: 'You must provide a username'}); return; } var password = messageObj.body.password; if (!password || password === '') { finished({error: 'You must provide a password'}); return; } var status = checkLogin(username, password); if (status.error) { finished(status); return; } var session = this.sessios.create('testWebService', 3600); session.authenticated = true; finished({token: session.token}); } }}

2016/9/9 EWD 3 トレーニング・コース #31

ユーザ名とパスワードは、要求の本体 (body) から得られます

Page 72: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

72

REST / Web サービスでセッションを使うfunction checkLogin(username,password) { if (username !== 'rob') return {error: 'Invalid username'}; if (password !== 'secret') return {error: 'Invalid password'}; return {ok: true}};module.exports = { restModule: true, handlers: { login: function(messageObj, finished) { if (messageObj.method !== 'POST') { finished({error: 'login message must use POST method'}); return; } var username = messageObj.body.username; if (!username || username === '') { finished({error: 'You must provide a username'}); return; } var password = messageObj.body.password; if (!password || password === '') { finished({error: 'You must provide a password'}); return; } var status = checkLogin(username, password); if (status.error) { finished(status); return; } var session = this.sessios.create('testWebService', 3600); session.authenticated = true; finished({token: session.token}); } }}

2016/9/9 EWD 3 トレーニング・コース #31

ユーザ名とパスワードの検証

もし正しくなければエラー応答を返す

Page 73: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

73

REST / Web サービスでセッションを使うfunction checkLogin(username,password) { if (username !== 'rob') return {error: 'Invalid username'}; if (password !== 'secret') return {error: 'Invalid password'}; return {ok: true}};module.exports = { restModule: true, handlers: { login: function(messageObj, finished) { if (messageObj.method !== 'POST') { finished({error: 'login message must use POST method'}); return; } var username = messageObj.body.username; if (!username || username === '') { finished({error: 'You must provide a username'}); return; } var password = messageObj.body.password; if (!password || password === '') { finished({error: 'You must provide a password'}); return; } var status = checkLogin(username, password); if (status.error) { finished(status); return; } var session = this.sessios.create('testWebService', 3600); session.authenticated = true; finished({token: session.token}); } }}

2016/9/9 EWD 3 トレーニング・コース #31

認証が正しければ、 testWebService という名前のアプリケーション用に、新しい EWD セッションを作ります

このセッションの有効期限は 1 時間です

Page 74: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

74

REST / Web サービスでセッションを使うfunction checkLogin(username,password) { if (username !== 'rob') return {error: 'Invalid username'}; if (password !== 'secret') return {error: 'Invalid password'}; return {ok: true}};module.exports = { restModule: true, handlers: { login: function(messageObj, finished) { if (messageObj.method !== 'POST') { finished({error: 'login message must use POST method'}); return; } var username = messageObj.body.username; if (!username || username === '') { finished({error: 'You must provide a username'}); return; } var password = messageObj.body.password; if (!password || password === '') { finished({error: 'You must provide a password'}); return; } var status = checkLogin(username, password); if (status.error) { finished(status); return; } var session = this.sessios.create('testWebService', 3600); session.authenticated = true; finished({token: session.token}); } }}

2016/9/9 EWD 3 トレーニング・コース #31

このセッションは認証済というフラグ

Page 75: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

75

REST / Web サービスでセッションを使うfunction checkLogin(username,password) { if (username !== 'rob') return {error: 'Invalid username'}; if (password !== 'secret') return {error: 'Invalid password'}; return {ok: true}};module.exports = { restModule: true, handlers: { login: function(messageObj, finished) { if (messageObj.method !== 'POST') { finished({error: 'login message must use POST method'}); return; } var username = messageObj.body.username; if (!username || username === '') { finished({error: 'You must provide a username'}); return; } var password = messageObj.body.password; if (!password || password === '') { finished({error: 'You must provide a password'}); return; } var status = checkLogin(username, password); if (status.error) { finished(status); return; } var session = this.sessios.create('testWebService', 3600); session.authenticated = true; finished({token: session.token}); } }}

2016/9/9 EWD 3 トレーニング・コース #31

最後に、 /login の応答として、セッション・トークンを返します

Page 76: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

76

試してみましょう

2016/9/9 EWD 3 トレーニング・コース #31

ログイン URL

間違ったパスワードを JSON のペイロードと

して POST する

エラー応答

Page 77: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

77

試してみましょう

2016/9/9 EWD 3 トレーニング・コース #31

ログイン URL

エラー応答

GET を用い、問い合わせ文字列にユーザ名とパスワードを指定す

Page 78: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

78

試してみましょう

2016/9/9 EWD 3 トレーニング・コース #31

今回はセッション・トークンが

返される

正しいユーザ名とパスワードを POST のペイ

ロードとして渡す

Page 79: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

79

次は何?

• 次に続く要求は、通常ヘッダ内に、セッション・トークンを返します• 例えば、権限付与ヘッダー

• バックエンドの要求ハンドラは、要求を認証しなくてはなりません• トークンが正しく、期限切れでないことをチェッ

クします

• するとハンドラーは、ユーザーが続けている会話の一時データのためにセッションを用いることができます

2016/9/9 EWD 3 トレーニング・コース #31

Page 80: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

80

REST / Web サービスでセッションを用いるmodule.exports = { restModule: true, handlers: { login: function(messageObj, finished) { // 以前に示した通り }, doSomethingNext: function(messageObj, finished) { var token = messageOgj.headers.authorization; if (!token || token === '') { finished({error: 'Missing authorization token'}); return; } var status = this.sessions.authenticate(token); if (status.error) { finished(status); return; } var session = status.session; // ユーザの要求の認証に成功した // ユーザーのセッションを適切に用いるためのアクセス権を持っています

// ここで要求のコンテンツ/ペイロードを用いて、すべきことを何でもすることができます // 最後に応答オブジェクト (responseObj) を作ります finished(responseObj); }}

2016/9/9 EWD 3 トレーニング・コース #31

Page 81: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

81

REST / Web サービスでセッションを用いるmodule.exports = { restModule: true, handlers: { login: function(messageObj, finished) { // 以前に示した通り }, doSomethingNext: function(messageObj, finished) { var token = messageOgj.headers.authorization; if (!token || token === '') { finished({error: 'Missing authorization token'}); return; } var status = this.sessions.authenticate(token); if (status.error) { finished(status); return; } var session = status.session; // ユーザの要求の認証に成功した // ユーザーのセッションを適切に用いるためのアクセス権を持っています

// ここで要求のコンテンツ/ペイロードを用いて、すべきことを何でもすることができます // 最後に応答オブジェクト (responseObj) を作ります finished(responseObj); }}

2016/9/9 EWD 3 トレーニング・コース #31

要求に権限認証ヘッダが付いていることを確認する

Page 82: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

82

REST / Web サービスでセッションを用いるmodule.exports = { restModule: true, handlers: { login: function(messageObj, finished) { // 以前に示した通り }, doSomethingNext: function(messageObj, finished) { var token = messageOgj.headers.authorization; if (!token || token === '') { finished({error: 'Missing authorization token'}); return; } var status = this.sessions.authenticate(token); if (status.error) { finished(status); return; } var session = status.session; // ユーザの要求の認証に成功した // ユーザーのセッションを適切に用いるためのアクセス権を持っています

// ここで要求のコンテンツ/ペイロードを用いて、すべきことを何でもすることができます // 最後に応答オブジェクト (responseObj) を作ります finished(responseObj); }}

2016/9/9 EWD 3 トレーニング・コース #31

セッション・トークンを認証する

Page 83: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

83

REST / Web サービスでセッションを用いるmodule.exports = { restModule: true, handlers: { login: function(messageObj, finished) { // 以前に示した通り }, doSomethingNext: function(messageObj, finished) { var token = messageOgj.headers.authorization; if (!token || token === '') { finished({error: 'Missing authorization token'}); return; } var status = this.sessions.authenticate(token); if (status.error) { finished(status); return; } var session = status.session; // ユーザの要求の認証に成功した // ユーザーのセッションを適切に用いるためのアクセス権を持っています

// ここで要求のコンテンツ/ペイロードを用いて、すべきことを何でもすることができます // 最後に応答オブジェクト (responseObj) を作ります finished(responseObj); }}

2016/9/9 EWD 3 トレーニング・コース #31

トークンは正しく、期限切れでもない

従ってユーザーのセッションにアクセスすることができる

Page 84: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

84

REST / Web サービスでセッションを用いるmodule.exports = { restModule: true, handlers: { login: function(messageObj, finished) { // 以前に示した通り }, doSomethingNext: function(messageObj, finished) { var token = messageOgj.headers.authorization; if (!token || token === '') { finished({error: 'Missing authorization token'}); return; } var status = this.sessions.authenticate(token); if (status.error) { finished(status); return; } var session = status.session; // ユーザの要求の認証に成功した // ユーザーのセッションを適切に用いるためのアクセス権を持っています

// ここで要求のコンテンツ/ペイロードを用いて、すべきことを何でもすることができます // 最後に応答オブジェクト (responseObj) を作ります finished(responseObj); }}

2016/9/9 EWD 3 トレーニング・コース #31

必要な処理をして、応答オブジェクトを返す

Page 85: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

85

試してみましょう

2016/9/9 EWD 3 トレーニング・コース #31

/doSomethingNextという要求を送る

エラー応答

間違った、あるいは期限切れのトー

クン

Page 86: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

86

試してみましょう

2016/9/9 EWD 3 トレーニング・コース #31

エラー応答

権限付与するヘッダーが定義されてい

ない

Page 87: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

87

試してみましょう

2016/9/9 EWD 3 トレーニング・コース #31

今度は成功

権限付与ヘッダーに正しい token が

ある

Page 88: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

88

セッションのログアウト?

•明示的な /logout 要求は必要ありません• セッションは自動的に期限切れになります• もしログアウトしたければ、セッションを非認証にセットすることができます• session.authenticated = false;

2016/9/9 EWD 3 トレーニング・コース #31

Page 89: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

89

セッションのログアウト?

• 一旦トークンが認証されセッションが確立すれば、標準的なメッセージ・ハンドラ内でタイムアウトを変更し、有効期限を更新することができます• session.timeout = 600;• session.updateExpiry();

2016/9/9 EWD 3 トレーニング・コース #31

Page 90: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

90

REST と Web サービス

• これであなたの ewd-xpress システム上で REST と Web サービスをサポートするために必要なものはすべて揃いました• 同じ ewd-xpress サーバー上で 対話的なアプリ

ケーションをサポートするのに加えてです

• ewd-xpress の起動ファイルに、 REST /Web サービスを、必要ならどれだけでも加え、定義することができます

2016/9/9 EWD 3 トレーニング・コース #31

Page 91: EWD 3トレーニングコース#31 ewd-xpressでWebおよびRESTサービスを作る

91

ewd-xpress 起動ファイルの拡張var config = { managementPassword: 'keepThisSecret!', serverName: 'My EWD Server', port: 8080, poolSize: 2, database: { type: ‘gtm', params: { // snip } }};

var ewdXpress = require('ewd-xpress').master,var exprss = ewdXpress.intercept();var bodyParser = require('body-parser');exprss.app.use(bodyParser.json());exprss.app.use('/testWebService', exprss.qx.router());exprss.app.use('/accounts', exprss.qx.router());exprss.app.use('/stockControl', exprss.qx.router());

ewdXpress.start(config);

2016/9/9 EWD 3 トレーニング・コース #31

そして、対応するモジュールを/node_modules  の中に作ります

- accounts.js - stockControl.js