Upload
rob-tweed
View
158
Download
2
Embed Size (px)
Citation preview
Copyright © 2016 M/Gateway Developments Ltd
EWD 3 Training CoursePart 44
Creating MicroServices with QEWD.js
Rob TweedDirector, M/Gateway Developments Ltd
Twitter: @rtweed
Copyright © 2016 M/Gateway Developments Ltd
Using JSON Web Tokens with QEWD REST Services
• This part of the course assumes that you've taken, at least:
• Part 31: Using QEWD for Web and REST Services• http://www.slideshare.net/robtweed/ewd-3-training-course-part-31-ewdxpress-for-web-and-rest-services
• Part 43: Using JSON Web Tokens with QEWD REST Services
– https://www.slideshare.net/robtweed/ewd-3-training-course-part-43-using-json-web-tokens-with-qewd-rest-services
Copyright © 2016 M/Gateway Developments Ltd
MicroServices: Background
• For an introduction on MicroServices, what they are, how they work and when and why they should be considered, see this overview on QEWD.js and MicroServices:
• https://www.slideshare.net/robtweed/qewdjs-json-web-tokens-microservices
Copyright © 2016 M/Gateway Developments Ltd
QEWD MicroService Fabric
ewd-qoper8queue
Express
Node.js
socket.io
CacheGT.M,YottaDBRedisNode.js
WorkerProcess
CacheGT.M,YottaDBRedisNode.js
WorkerProcess
CacheGT.M,YottaDBRedisNode.js
WorkerProcess
ewd-qoper8queue
Express
Node.js
socket.io
CacheGT.M,YottaDBRedisNode.js
WorkerProcess
CacheGT.M,YottaDBRedisNode.js
WorkerProcess
CacheGT.M,YottaDBRedisNode.js
WorkerProcess
ewd-qoper8queue
Express
Node.js
socket.io
CacheGT.M,YottaDBRedisNode.js
WorkerProcess
CacheGT.M,YottaDBRedisNode.js
WorkerProcess
CacheGT.M,YottaDBRedisNode.js
WorkerProcess
User authentication
Demographics
Pharmacy
ewd-qoper8queue
Express
Node.js
socket.io
CacheGT.M,YottaDBRedis
Node.jsWorkerProcess
CacheGT.M,YottaDBRedis
Node.jsWorkerProcess
CacheGT.M,YottaDBRedis
Node.jsWorkerProcess
Client Orchestration
HTTPSWebSocketConnections
Copyright © 2016 M/Gateway Developments Ltd
QEWD.js Solution
ewd-qoper8queue
Express
Node.js
socket.io
Equivalent toewd-client
socket.io-client
Incoming RESTrequest
Copyright © 2016 M/Gateway Developments Ltd
QEWD.js Solution
ewd-qoper8queue
Express
Node.js
socket.io
Equivalent toewd-client
socket.io-client
IncomingWebSocket
request
Copyright © 2016 M/Gateway Developments Ltd
QEWD.js Solution
ewd-qoper8queue
Express
Node.js
socket.io
Equivalent toewd-client
socket.io-client
IncomingWebSocket
request
ProcessLocally?
Copyright © 2016 M/Gateway Developments Ltd
QEWD.js Solution
ewd-qoper8queue
Express
Node.js
socket.io
Equivalent toewd-client
socket.io-client
IncomingWebSocket
request
Handledby remote
MicroService?
Copyright © 2016 M/Gateway Developments Ltd
QEWD.js Solution
ewd-qoper8queue
Express
Node.js
socket.io
PersistentBi-directionalWebSocketconnection
Securedover
HTTPS
ewd-qoper8queue
Express
Node.js
socket.io
Equivalent toewd-client
socket.io-client
Remote QEWD MicroService
Copyright © 2016 M/Gateway Developments Ltd
QEWD MicroService Architecture
• Incoming requests can be either from:– a browser over WebSockets or Ajax– REST over HTTP / HTTPS
• This tutorial will focus on REST
Copyright © 2016 M/Gateway Developments Ltd
QEWD MicroService Architecture
• MicroService routes are defined in the QEWD Startup file
• On startup, WebSocket connections are established between the primary orchestrating QEWD system(s) and the MicroService QEWD Systems
• MicroService Routing is handled by the QEWD Master Process
Copyright © 2016 M/Gateway Developments Ltd
QEWD MicroService Architecture
• Incoming requests to the orchestrating QEWD Server are over REST/HTTP(S)
• If the requests are destined for a MicroService, they are converted to QEWD WebSocket messages
• Incoming requests on MicroService QEWD systems are handled as QEWD WebSocket requests
Copyright © 2016 M/Gateway Developments Ltd
QEWD MicroService Architecture
• QEWD MicroServices rely on JWTs for authentication and Session/State management
• All participating QEWD systems must be configured with the same JWT secret
Copyright © 2016 M/Gateway Developments Ltd
Let's Get Started!
Copyright © 2016 M/Gateway Developments Ltd
Simple Example
• Two QEWD systems– One will be the primary orchestrating system
that will be the endpoint for incoming REST requests
• We'll refer to this as the Primary QEWD Server
– One will be used as a user authentication service
• We'll refer to this as the Login MicroService server
Copyright © 2016 M/Gateway Developments Ltd
QEWD MicroService Fabric
ewd-qoper8queue
Express
Node.js
socket.io
CacheGT.M,YottaDBRedisNode.js
WorkerProcess
CacheGT.M,YottaDBRedisNode.js
WorkerProcess
CacheGT.M,YottaDBRedisNode.js
WorkerProcess
User authentication
ewd-qoper8queue
Express
Node.js
socket.io
CacheGT.M,YottaDBRedis
Node.jsWorkerProcess
CacheGT.M,YottaDBRedis
Node.jsWorkerProcess
CacheGT.M,YottaDBRedis
Node.jsWorkerProcess
Client Primary Server
HTTPSWebSocketConnections
Login MicroService Server
Copyright © 2016 M/Gateway Developments Ltd
Configuring the Primary Server
Copyright © 2016 M/Gateway Developments Ltd
Startup file from Part 43var config = { managementPassword: 'keepThisSecret!', serverName: 'QEWD REST Server', port: 8080, poolSize: 2, database: { type: 'gtm' },
jwt: {
secret: 'someSecret123'
}};
var routes = [ {path: '/api', module: 'myRestService'}];
var qewd = require('qewd').master;qewd.start(config, routes);
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definitionvar config = { managementPassword: 'keepThisSecret!', serverName: 'QEWD REST Server', port: 8080, poolSize: 2, database: { type: 'gtm' },
jwt: {
secret: 'someSecret123'
},
u_services: {
destinations: {},
routes: []
}};
var routes = [ {path: '/api', module: 'myRestService'}];
var qewd = require('qewd').master;qewd.start(config, routes);
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definitionvar config = { managementPassword: 'keepThisSecret!', serverName: 'QEWD REST Server', port: 8080, poolSize: 2, database: { type: 'gtm' },
jwt: {
secret: 'someSecret123'
},
u_services: {
destinations: {},
routes: []
}};
var routes = [ {path: '/api', module: 'myRestService'}];
var qewd = require('qewd').master;qewd.start(config, routes);
Two parts to the MicroService Configuration:
-destinations: defines the endpoints-routes – assigns URL paths to destinations
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definitionjwt: {
secret: 'someSecret123'
},
u_services: {
destinations: {
login_service: {
host: 'http://192.168.1.114:8080',
application: 'login-micro-service'
}
},
routes: []
}};
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definitionjwt: {
secret: 'someSecret123'
},
u_services: {
destinations: {
login_service: {
host: 'http://192.168.1.114:8080',
application: 'login-micro-service'
}
},
routes: []
}};
You give each destination a name(your choice what it's called)
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definitionjwt: {
secret: 'someSecret123'
},
u_services: {
destinations: {
login_service: {
host: 'http://192.168.1.114:8080',
application: 'login-micro-service'
}
},
routes: []
}};
A destination defines:
-a QEWD host endpoint URL
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definitionjwt: {
secret: 'someSecret123'
},
u_services: {
destinations: {
login_service: {
host: 'http://192.168.1.114:8080',
application: 'login-micro-service'
}
},
routes: []
}};
A destination defines:
-The Application name assigned for this destination (ie the application on the remote machine that will handle incoming requests for this service destination)
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definitionjwt: {
secret: 'someSecret123'
},
u_services: {
destinations: {
login_service: {
host: 'http://192.168.1.114:8080',
application: 'login-micro-service'
}
},
routes: [
{
path: '/api/login',
method: 'POST',
destination: 'login_service'
}
] }};
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definitionu_services: {
destinations: {
login_service: {
host: 'http://192.168.1.114:8080',
application: 'login-micro-service'
}
},
routes: [
{
path: '/api/login',
method: 'POST',
destination: 'login_service'
}
]}
Each Route is defined by an array element
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definitionu_services: {
destinations: {
login_service: {
host: 'http://192.168.1.114:8080',
application: 'login-micro-service'
}
},
routes: [
{
path: '/api/login',
method: 'POST',
destination: 'login_service'
}
]}
Each Route is defined by:
- A URL path (which can be templated)
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definitionu_services: {
destinations: {
login_service: {
host: 'http://192.168.1.114:8080',
application: 'login-micro-service'
}
},
routes: [
{
path: '/api/login',
method: 'POST',
destination: 'login_service'
}
]}
Each Route is defined by:
-optionally, an HTTP method
If not specified, the route will apply toall HTTP methods for the path
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definitionu_services: {
destinations: {
login_service: {
host: 'http://192.168.1.114:8080',
application: 'login-micro-service'
}
},
routes: [
{
path: '/api/login',
method: 'POST',
destination: 'login_service'
}
]}
Each Route is defined by:
-the MicroService destination to which the request will be routed
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definitionu_services: {
destinations: {
login_service: {
host: 'http://192.168.1.114:8080',
application: 'login-micro-service'
}
},
routes: [
{
path: '/api/login',
method: 'POST',
destination: 'login_service'
}
]}
Each Route is defined by:
-the MicroService destination to which the request will be routed
Copyright © 2016 M/Gateway Developments Ltd
MicroService Routes Override Local Routes
• Look in the Startup file and you'll see it also contains a route for locally processing all incoming REST requests starting /api:
var routes = [ {path: '/api', module: 'myRestService'}];
Copyright © 2016 M/Gateway Developments Ltd
MicroService Routes Override Local Routes
• Look in the Startup file and you'll see it also contains a route for locally processing all incoming REST requests starting /api:
• Our MicroService route for /api/login will take preference over this
var routes = [ {path: '/api', module: 'myRestService'}];
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definitionu_services: {
destinations: {
login_service: {
host: 'http://192.168.1.114:8080',
application: 'login-micro-service'
}
},
routes: [
{
path: '/api/login',
method: 'POST',
destination: 'login_service'
}
]}
You can define as many Routes andDestinations as you like
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definitionu_services: {
destinations: {
login_service: {
host: 'http://192.168.1.114:8080',
application: 'login-micro-service'
},
info_service: {
host: 'http://192.168.1.115:8080',
application: 'info-micro-service'
}
},
routes: [
{
path: '/api/login',
method: 'POST',
destination: 'login_service'
}
]}
Destinations can be at differentphysical endpoints
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definitionu_services: {
destinations: {
login_service: {
host: 'http://192.168.1.114:8080',
application: 'login-micro-service'
},
info_service: {
host: 'http://192.168.1.114:8080',
application: 'info-micro-service'
}
},
routes: [
{
path: '/api/login',
method: 'POST',
destination: 'login_service'
}
]}
The same physical endpoint can appearin more than one Destination
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definitionu_services: {
destinations: {
login_service: {
host: 'http://192.168.1.114:8080',
application: 'login-micro-service'
},
info_service: {
host: 'http://192.168.1.114:8080',
application: 'info-micro-service'
}
},
routes: [
{
path: '/api/login',
method: 'POST',
destination: 'login_service'
}
]}
The same physical endpoint can appearin more than one Destination
In which case the application will bedifferent
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definitionu_services: {
destinations: {
login_service: {
host: 'http://192.168.1.114:8080',
application: 'login-micro-service'
},
info_service: {
host: 'http://192.168.1.115:8080',
application: 'info-micro-service'
}
},
routes: [
{
path: '/api/login',
method: 'POST',
destination: 'login_service'
},
{
path: '/api/info',
method: 'GET',
destination: 'info_service'
}
]}
Each Route can use different Destinations
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definitionu_services: {
destinations: {
login_service: {
host: 'http://192.168.1.114:8080',
application: 'login-micro-service'
}
},
routes: [
{
path: '/api/login',
method: 'POST',
destination: 'login_service'
},
{
path: '/api/userinfo',
method: 'GET',
destination: 'login_service'
}
]}
Each Route can use different Destinations
or the same ones
Copyright © 2016 M/Gateway Developments Ltd
Our Example MicroService Definitionjwt: {
secret: 'someSecret123'
},
u_services: {
destinations: {
login_service: {
host: 'http://192.168.1.114:8080',
application: 'login-micro-service'
}
},
routes: [
{
path: '/api/login',
method: 'POST',
destination: 'login_service'
}
] }};
In our example we'll just define a singleDestination and Route
POST requests for /api/login will be routedto the MicroService QEWD systemat 192.168.1.114:8080, where they will behandled by the login-micro-serviceapplication
Copyright © 2016 M/Gateway Developments Ltd
Our Example MicroService Definitionvar config = {
managementPassword: 'keepThisSecret!',
serverName: 'New QEWD Server',
port: 8080,
poolSize: 2,
database: {
type: 'gtm'
},
jwt: {
secret: 'someSecret123'
},
u_services: {
destinations: {
login_service: {
host: 'http://192.168.1.114:8080',
application: 'login-micro-service'
}
},
routes: [
{
path: '/api/login',
method: 'POST',
destination: 'login_service'
}
]
}
};
var routes = [
{
path: '/api',
module: 'myRestService',
errors: {
notfound: {
text: 'Resource Not Recognised',
statusCode: 404
}
}
}
];
var qewd = require('qewd').master;
var q = qewd.start(config, routes);
Save as ~/qewd/ms-startup.js
Change the IP address/domain name of thelogin_service hostproperty to match the serveryou'll be using
Copyright © 2016 M/Gateway Developments Ltd
Next we'll configure the MicroService System
Copyright © 2016 M/Gateway Developments Ltd
Next we'll configure the MicroService System
• Remember – we'll now be working on your second QEWD server
• As our starting point, we'll use that original startup file from Part 43 again…
Copyright © 2016 M/Gateway Developments Ltd
Startup file from Part 43var config = { managementPassword: 'keepThisSecret!', serverName: 'QEWD REST Server', port: 8080, poolSize: 2, database: { type: 'gtm' },
jwt: {
secret: 'someSecret123'
}};
var routes = [ {path: '/api', module: 'myRestService'}];
var qewd = require('qewd').master;qewd.start(config, routes);
Copyright © 2016 M/Gateway Developments Ltd
MicroService Startup filevar config = { managementPassword: 'keepThisSecret!', serverName: 'QEWD REST Server', port: 8080, poolSize: 2, database: { type: 'gtm' },
jwt: {
secret: 'someSecret123'
}};
var routes = [ {path: '/api', module: 'myRestService'}];
var qewd = require('qewd').master;qewd.start(config, routes);
Important: we'll use the sameJWT Secret
Copyright © 2016 M/Gateway Developments Ltd
MicroService Startup filevar config = { managementPassword: 'keepThisSecret!', serverName: 'QEWD REST Server', port: 8080, poolSize: 2, database: { type: 'gtm' },
jwt: {
secret: 'someSecret123'
}};
var routes = [ {path: '/api', module: 'myRestService'}];
var qewd = require('qewd').master;qewd.start(config, routes);
We don't need this, however,even though this QEWDsystem will be handlingforwarded requests for/api/login
Copyright © 2016 M/Gateway Developments Ltd
MicroService Startup filevar config = { managementPassword: 'keepThisSecret!', serverName: 'QEWD REST Server', port: 8080, poolSize: 2, database: { type: 'gtm' },
jwt: {
secret: 'someSecret123'
}};
var qewd = require('qewd').master;qewd.start(config);
That's because the primaryQEWD system will re-formatthe /api/login REST requests to a WebSocket message
Copyright © 2016 M/Gateway Developments Ltd
MicroService Startup filevar config = { managementPassword: 'keepThisSecret!', serverName: 'QEWD REST Server', port: 8080, poolSize: 2, database: { type: 'gtm' },
jwt: {
secret: 'someSecret123'
}};
var qewd = require('qewd').master;qewd.start(config);
That's because the primaryQEWD system will re-formatthe /api/login REST requests to a WebSocket message
These messages will be handledby the login_micro-serviceapplication on this QEWD system
Copyright © 2016 M/Gateway Developments Ltd
MicroService Startup filevar config = { managementPassword: 'keepThisSecret!', serverName: 'QEWD Login MicroService', port: 8080, poolSize: 2, database: { type: 'gtm' },
jwt: {
secret: 'someSecret123'
}};
var qewd = require('qewd').master;qewd.start(config);
Save this file as:
~/qewd/loginservice.js
Copyright © 2016 M/Gateway Developments Ltd
Start Up the Two QEWD Systems
• It doesn't matter which you start up first
• Let's start the main one first and see what happens
Copyright © 2016 M/Gateway Developments Ltd
Start Up the Two QEWD Systems
On the primary QEWD machine:
cd ~/qewdnode ms-startup
Copyright © 2016 M/Gateway Developments Ltd
Look at the QEWD Node Console Log
rtweed@ubuntu:~/qewd$ node microservicesSetting up micro-service connectionsAdding MicroService Client connection: url = http://192.168.1.114:8080; application = login-micro-servicestarting microService connection to http://192.168.1.114:8080webServerRootPath = /home/rtweed/qewd/www/route /api will be handled by qx.router
Copyright © 2016 M/Gateway Developments Ltd
Look at the QEWD Node Console Log
rtweed@ubuntu:~/qewd$ node microservicesSetting up micro-service connectionsAdding MicroService Client connection: url = http://192.168.1.114:8080; application = login-micro-servicestarting microService connection to http://192.168.1.114:8080webServerRootPath = /home/rtweed/qewd/www/route /api will be handled by qx.router
QEWD hasn't fully started yet
It's waiting for a response from the MicroServicemachine on 192.168.1.114:8080
Which, of course, hasn't been started yet
Copyright © 2016 M/Gateway Developments Ltd
Start Up the Two QEWD Systems
On the QEWD Login MicroService machine:
cd ~/qewdnode loginservice
Copyright © 2016 M/Gateway Developments Ltd
Look at the QEWD Node Console Log on the MicroService machine
rtweed@ubuntu:~/qewd$ node loginServicewebServerRootPath = /home/rtweed/qewd/www/Worker Bootstrap Module file written to node_modules/ewd-qoper8-worker.js========================================================ewd-qoper8 is up and running. Max worker pool size: 2========================================================QEWD.js is listening on port 8080========================================================** sockets: incoming message received: {"type":"ewd-register","application":"login-micro-service","jwt":true,"socketId":"L7OwOnSiqhr-nAmdAAAA","ipAddress":"::ffff:192.168.1.119"}no available workerssent qoper8-start message to 30140process.argv[2] = qewd.workerworkerModule: qewd; workerSession Garbage Collector has started in worker 30140Tue, 22 Aug 2017 09:47:46 GMT; master process received response from worker 30140: {"type":"workerProcessStarted","ok":30140}new worker 30140 started and ready so process queue againTue, 22 Aug 2017 09:47:46 GMT; worker 30140 received message: {"type":"ewd-register","application":"login-micro-service","jwt":true,"socketId":"L7OwOnSiqhr-nAmdAAAA","ipAddress":"::ffff:192.168.1.119"}Tue, 22 Aug 2017 09:47:46 GMT; master process received response from worker 30140: {"type":"ewd-register","finished":true,"message":{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDMzOTU1NjYsImlhdCI6MTUwMzM5NTI2NiwiaXNzIjoicWV3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ0aW1lb3V0IjozMDAsInFld2QiOiJmZTc0U5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.DsDntCU3x2w21K3vmK3iaJd1kOhIj_Rl9h10469qXu4"}}*** handleMessage response {"type":"ewd-register","finished":true,"message":{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.ehOTE0OGQ4Nzg1N2ZiZWM5Nzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdjZDUyMjE4ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM0NWNhZjljYjgwMjM2ZjM0M2Q0OWIwMmE4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.DsDntCU3x2w21K3vmK3iaJd1kOhIj_Rl9h10469qXu4"}}Response time: 313ms
Copyright © 2016 M/Gateway Developments Ltd
Look at the QEWD Node Console Log on the MicroService machine
rtweed@ubuntu:~/qewd$ node loginServicewebServerRootPath = /home/rtweed/qewd/www/Worker Bootstrap Module file written to node_modules/ewd-qoper8-worker.js========================================================ewd-qoper8 is up and running. Max worker pool size: 2========================================================QEWD.js is listening on port 8080========================================================** sockets: incoming message received: {"type":"ewd-register","application":"login-micro-service","jwt":true,"socketId":"L7OwOnSiqhr-nAmdAAAA","ipAddress":"::ffff:192.168.1.119"}no available workerssent qoper8-start message to 30140process.argv[2] = qewd.workerworkerModule: qewd; workerSession Garbage Collector has started in worker 30140Tue, 22 Aug 2017 09:47:46 GMT; master process received response from worker 30140: {"type":"workerProcessStarted","ok":30140}new worker 30140 started and ready so process queue againTue, 22 Aug 2017 09:47:46 GMT; worker 30140 received message: {"type":"ewd-register","application":"login-micro-service","jwt":true,"socketId":"L7OwOnSiqhr-nAmdAAAA","ipAddress":"::ffff:192.168.1.119"}Tue, 22 Aug 2017 09:47:46 GMT; master process received response from worker 30140: {"type":"ewd-register","finished":true,"message":{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDMzOTU1NjYsImlhdCI6MTUwMzM5NTI2NiwiaXNzIjoicWV3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ0aW1lb3V0IjozMDAsInFld2QiOiJmZTc0U5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.DsDntCU3x2w21K3vmK3iaJd1kOhIj_Rl9h10469qXu4"}}*** handleMessage response {"type":"ewd-register","finished":true,"message":{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.ehOTE0OGQ4Nzg1N2ZiZWM5Nzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdjZDUyMjE4ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM0NWNhZjljYjgwMjM2ZjM0M2Q0OWIwMmE4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.DsDntCU3x2w21K3vmK3iaJd1kOhIj_Rl9h10469qXu4"}}Response time: 313ms
QEWD has fully started
Copyright © 2016 M/Gateway Developments Ltd
Notice This Activity…Tue, 22 Aug 2017 09:47:46 GMT; worker 30140 received message: {"type":"ewd-register","application":"login-micro-service","jwt":true,"socketId":"L7OwOnSiqhr-nAmdAAAA","ipAddress":"::ffff:192.168.1.119"}Tue, 22 Aug 2017 09:47:46 GMT; master process received response from worker 30140: {"type":"ewd-register","finished":true,"message":{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDMzOTU1NjYsImlhdCI6MTUwMzM5NTI2NiwiaXNzIjoicWV3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ0aW1lb3V0IjozMDAsInFld2QiOiJmZTc0NjBhM2ZjOGFmMWY5YjhlMWY1MWQ2M2FmYjQ3YTU5M2JkZDczYjNhOTE0OGQ4Nzg1N2ZiZWM5Nzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdjZDUyMjE4ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM0NWNhZjljYjgwMjM2ZjM0M2Q0OWIwMmE4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.DsDntCU3x2w21K3vmK3iaJd1kOhIj_Rl9h10469qXu4"}}*** handleMessage response {"type":"ewd-register","finished":true,"message":{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDMzOTU1NjYsImlhdCI6MTUwMzM5NTI2NiwiaXNzIjoicWV3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ0aW1lb3V0IjozMDAsInFld2QiOiJmZTc0NjBhM2ZjOGFmMWY5YjhlMWY1MWQ2M2FmYjQ3YTU5M2JkZDczYjNhOTE0OGQ4Nzg1N2ZiZWM5Nzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdjZDUyMjE4ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM0NWNhZjljYjgwMjM2ZjM0M2Q0OWIwMmE4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.DsDntCU3x2w21K3vmK3iaJd1kOhIj_Rl9h10469qXu4"}}Response time: 313ms
Copyright © 2016 M/Gateway Developments Ltd
What Happened?
• When the QEWD MicroService machine started, the primary machine was able to establish a WebSocket connection to it
• It then registered the login-micro-service application on the QEWD MicroService machine, using a JWT
Copyright © 2016 M/Gateway Developments Ltd
Now look at the Primary QEWD Machine's Console Log
rtweed@ubuntu:~/qewd$ node microservicesSetting up micro-service connectionsAdding MicroService Client connection: url = http://192.168.1.114:8080; application = login-micro-servicestarting microService connection to http://192.168.1.114:8080webServerRootPath = /home/rtweed/qewd/www/route /api will be handled by qx.routerlogin-micro-service registeredhttp://192.168.1.114:8080 micro-service readyWorker Bootstrap Module file written to node_modules/ewd-qoper8-worker.js========================================================ewd-qoper8 is up and running. Max worker pool size: 2========================================================QEWD.js is listening on port 8080========================================================
Connection was established to the Login MicroServiceQEWD system, and the login-micro-service applicationwas registered
Copyright © 2016 M/Gateway Developments Ltd
Now look at the Primary QEWD Machine's Console Log
rtweed@ubuntu:~/qewd$ node microservicesSetting up micro-service connectionsAdding MicroService Client connection: url = http://192.168.1.114:8080; application = login-micro-servicestarting microService connection to http://192.168.1.114:8080webServerRootPath = /home/rtweed/qewd/www/route /api will be handled by qx.routerlogin-micro-service registeredhttp://192.168.1.114:8080 micro-service readyWorker Bootstrap Module file written to node_modules/ewd-qoper8-worker.js========================================================ewd-qoper8 is up and running. Max worker pool size: 2========================================================QEWD.js is listening on port 8080========================================================
So QEWD has now fully started
Both QEWD systems are ready!
Copyright © 2016 M/Gateway Developments Ltd
Startup Sequence Doesn't Matter
• You can try stopping both QEWD systems (just CTRL & C each of them)
• Restart the Login MicroService QEWD system first– It will start up fully and wait for incoming requests
• Then start the primary QEWD system– It will connect to the Login MicroService QEWD
machine immediately– You'll see the Login machine receive the registration
request– The primary machine will then start QEWD
Copyright © 2016 M/Gateway Developments Ltd
You can shut down and restart either server
• You can try stopping and restarting either QEWD system
• After a brief pause, you'll see the two servers re-communicating and re-registering
Copyright © 2016 M/Gateway Developments Ltd
Ready to test the /api/login request
• Use a REST Client
• POST the /api/login request to the primary QEWD server
Copyright © 2016 M/Gateway Developments Ltd
Try POST /api/login
Copyright © 2016 M/Gateway Developments Ltd
Try POST /api/login
Not surprising – we haven't yet written a handlerFor the login-micro-service application to handleThis request on the MicroService machine…..but...
Copyright © 2016 M/Gateway Developments Ltd
Look at the Console Log for both machines
• You'll see that they both burst into life
Copyright © 2016 M/Gateway Developments Ltd
Primary Machine
sent: {"application":"login-micro-service","type":"restRequest","path":"/api/login","pathTemplate":"/api/login","method":"POST","headers":{"host":"192.168.1.119:8080","content-length":"41","content-type":"application/json"},"params":{"type":"login"},"query":{},"body":{"username":"rob","password":"secret"},"ip":"::ffff:192.168.1.74","ips":[],"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDMzOTk1NzMsImlhdCI6MTUwMzM5OTI3MywiaXNzIjoicWV3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ0aW1lb3V0IjozMDAsInFld2QiOiJmZTc0NjBhM2ZjOGFmMWY5YjhlMWY1MWQ2MzhlZWM1OTZiMmJlYzU1YTI5MTRlODljNThmNTE4YTgwNzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdjZDUyMjE4ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM0NWNhZjljYjgwMjM2ZjM0M2Q0OWIwMmE4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.Re4a6cEmIzQ9PFhwwYsoQ-UtMBKHkTPSpAk55FCDyV8","args":{},"jwt":true}
received: {"type":"restRequest","finished":true,"message":{"error":"Unable to load handler module for: login-micro-service","reason":{"code":"MODULE_NOT_FOUND"}},"responseTime":"14ms"}
Copyright © 2016 M/Gateway Developments Ltd
Login MicroService MachineTue, 22 Aug 2017 10:54:33 GMT; worker 30188 received message: {"application":"login-micro-service","type":"restRequest","path":"/api/login","pathTemplate":"/api/login","method":"POST","headers":{"host":"192.168.1.119:8080","content-length":"41","content-type":"application/json"},"params":{"type":"login"},"query":{},"body":{"username":"rob","password":"secret"},"ip":"::ffff:192.168.1.74","ips":[],"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDMzOTk1NzMsImlhdCI6MTUwMzM5OTI3MywiaXNzIjoicWV3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ0aW1lb3V0IjozMDAsInFld2QiOiJmZTc0NjBhM2ZjOGFmMWY5YjhlMWY1MWQ2MzhlZWM1OTZiMmJlYzU1YTI5MTRlODljNThmNTE4YTgwNzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdjZDUyMjE4ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM0NWNhZjljYjgwMjM2ZjM0M2Q0OWIwMmE4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.Re4a6cEmIzQ9PFhwwYsoQ-UtMBKHkTPSpAk55FCDyV8","args":{},"jwt":true}Unable to load handler module for: login-micro-service: Error: Cannot find module 'login-micro-service'Tue, 22 Aug 2017 10:54:33 GMT; master process received response from worker 30188: {"type":"restRequest","finished":true,"message":{"error":"Unable to load handler module for: login-micro-service","reason":{"code":"MODULE_NOT_FOUND"}}}*** handleMessage response {"type":"restRequest","finished":true,"message":{"error":"Unable to load handler module for: login-micro-service","reason":{"code":"MODULE_NOT_FOUND"}}}
Copyright © 2016 M/Gateway Developments Ltd
Login MicroService MachineTue, 22 Aug 2017 10:54:33 GMT; worker 30188 received message: {"application":"login-micro-service","type":"restRequest","path":"/api/login","pathTemplate":"/api/login","method":"POST","headers":{"host":"192.168.1.119:8080","content-length":"41","content-type":"application/json"},"params":{"type":"login"},"query":{},"body":{"username":"rob","password":"secret"},"ip":"::ffff:192.168.1.74","ips":[],"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDMzOTk1NzMsImlhdCI6MTUwMzM5OTI3MywiaXNzIjoicWV3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ0aW1lb3V0IjozMDAsInFld2QiOiJmZTc0NjBhM2ZjOGFmMWY5YjhlMWY1MWQ2MzhlZWM1OTZiMmJlYzU1YTI5MTRlODljNThmNTE4YTgwNzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdjZDUyMjE4ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM0NWNhZjljYjgwMjM2ZjM0M2Q0OWIwMmE4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.Re4a6cEmIzQ9PFhwwYsoQ-UtMBKHkTPSpAk55FCDyV8","args":{},"jwt":true}
Copyright © 2016 M/Gateway Developments Ltd
Login MicroService MachineTue, 22 Aug 2017 10:54:33 GMT; worker 30188 received message: {"application":"login-micro-service","type":"restRequest","path":"/api/login","pathTemplate":"/api/login","method":"POST","headers":{"host":"192.168.1.119:8080","content-length":"41","content-type":"application/json"},"params":{"type":"login"},"query":{},"body":{"username":"rob","password":"secret"},"ip":"::ffff:192.168.1.74","ips":[],"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDMzOTk1NzMsImlhdCI6MTUwMzM5OTI3MywiaXNzIjoicWV3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ0aW1lb3V0IjozMDAsInFld2QiOiJmZTc0NjBhM2ZjOGFmMWY5YjhlMWY1MWQ2MzhlZWM1OTZiMmJlYzU1YTI5MTRlODljNThmNTE4YTgwNzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdjZDUyMjE4ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM0NWNhZjljYjgwMjM2ZjM0M2Q0OWIwMmE4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.Re4a6cEmIzQ9PFhwwYsoQ-UtMBKHkTPSpAk55FCDyV8","args":{},"jwt":true}
Copyright © 2016 M/Gateway Developments Ltd
Incoming WebSocket Message{ "application": "login-micro-service", "type": "restRequest", "path": "/api/login", "pathTemplate": "/api/login", "method": "POST", "headers": { "host": "192.168.1.119:8080", "content-length": "41", "content-type": "application/json" }, "params": { "type": "login" }, "query": {}, "body": { "username": "rob", "password": "secret" }, "ip": "::ffff:192.168.1.74", "ips": [], "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.ey...", "args": {}, "jwt": true }
Copyright © 2016 M/Gateway Developments Ltd
Login MicroService MachineUnable to load handler module for: login-micro-service: Error: Cannot find module 'login-micro-service'
Copyright © 2016 M/Gateway Developments Ltd
Login MicroService MachineTue, 22 Aug 2017 10:54:33 GMT;
master process received response from worker 30188: {"type":"restRequest","finished":true,"message":{"error":"Unable to load handler module for: login-micro-service","reason":{"code":"MODULE_NOT_FOUND"}}}*** handleMessage response {"type":"restRequest","finished":true,"message":{"error":"Unable to load handler module for: login-micro-service","reason":{"code":"MODULE_NOT_FOUND"}}}
Copyright © 2016 M/Gateway Developments Ltd
So let's add a Login Handler
• On the Login MicroService machine– 192.168.1.114 in our example
– Create a new text file:• ~/qewd/node_modules/login-micro-service.js
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Module
• We could write a standard QEWD WebSocket message handler function to deal with the re-packaged incoming message– Here's what it looked like
Copyright © 2016 M/Gateway Developments Ltd
Incoming WebSocket Message{ "application": "login-micro-service", "type": "restRequest", "path": "/api/login", "pathTemplate": "/api/login", "method": "POST", "headers": { "host": "192.168.1.119:8080", "content-length": "41", "content-type": "application/json" }, "params": { "type": "login" }, "query": {}, "body": { "username": "rob", "password": "secret" }, "ip": "::ffff:192.168.1.74", "ips": [], "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.ey...", "args": {}, "jwt": true }
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Module
• We could write a standard QEWD WebSocket message handler function to deal with the re-packaged incoming message
• But QEWD provides a set of shortcuts to make it even simpler– And to allow you to define multiple handler
functions based on the original URL paths, using templated paths if you wish
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Modulevar router = require('qewd-router');var routes;
module.exports = { init: function() { routes = { '/api/login': { POST: login } }; router.addMicroServiceHandler(routes, module.exports); }};
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Modulevar router = require('qewd-router');var routes;
module.exports = { init: function() { routes = { '/api/login': { POST: login } }; router.addMicroServiceHandler(routes, module.exports); }};
First we need to definean init() function in which we'lldefine our URL routes
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Modulevar router = require('qewd-router');var routes;
module.exports = { init: function() { routes = { '/api/login': { POST: login } }; router.addMicroServiceHandler(routes, module.exports); }};
Inside this function, we define a routes object for all the routeswe want to handle.
We only have one: POST /api/login
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Modulevar router = require('qewd-router');var routes;
module.exports = { init: function() { routes = { '/api/login': { POST: login } }; router.addMicroServiceHandler(routes, module.exports); }};
Inside this function, we define a routes object for all the routeswe want to handle.
We only have one: POST /api/login
And it will invoke a handler functionnamed login() (which we haven'tyet written)
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Modulevar router = require('qewd-router');var routes;
module.exports = { init: function() { routes = { '/api/login': { POST: login } }; router.addMicroServiceHandler(routes, module.exports); }}; Then we can run this QEWD
API which constructs thehandler function stubs for uswithin the module
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Modulevar router = require('qewd-router');var routes;
function login(args, finished) { // this will handle the login message}
module.exports = { init: function() { routes = { '/api/login': { POST: login } }; router.addMicroServiceHandler(routes, module.exports); }};
Next we define the login function
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Modulevar router = require('qewd-router');var routes;
function login(args, finished) { // this will handle the login message}
module.exports = { init: function() { routes = { '/api/login': { POST: login } }; router.addMicroServiceHandler(routes, module.exports); }};
Next we define the login() function
It's the same function interfacethat you use for standardREST route handling
The addMicroServiceHandler()API normalises the interfacefor you
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Modulevar router = require('qewd-router');var routes;
function login(args, finished) { // this will handle the login message}
module.exports = { init: function() { routes = { '/api/login': { POST: login } }; router.addMicroServiceHandler(routes, module.exports); }};
Next we define the login function
It's the same function interfacethat you use for standardREST route handling
args is an object containing: -req: incoming request object-session: the JWT payload
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Modulevar router = require('qewd-router');var routes;
function login(args, finished) { // this will handle the login message}
module.exports = { init: function() { routes = { '/api/login': { POST: login } }; router.addMicroServiceHandler(routes, module.exports); }};
Next we define the login function
It's the same function interfacethat you use for standardREST route handling
-finished is the function for returning the response and releasing the worker process
Copyright © 2016 M/Gateway Developments Ltd
Incoming WebSocket Message{ "application": "login-micro-service", "type": "restRequest", "path": "/api/login", "pathTemplate": "/api/login", "method": "POST", "headers": { "host": "192.168.1.119:8080", "content-length": "41", "content-type": "application/json" }, "params": { "type": "login" }, "query": {}, "body": { "username": "rob", "password": "secret" }, "ip": "::ffff:192.168.1.74", "ips": [], "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.ey...", "args": {}, "jwt": true }
We POSTed{"username":"rob","password":"secret"}
So the user login credentialswill be in the message body object
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Modulefunction login( args, finished) { var username = args.req.body.username; var password = args.req.body.password; if (username === 'rob' && password === 'secret') { // valid login credentials } else { // invalid login – return an error }}
We'll just hard-code thevalid credentials for simplicityin this example
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Modulefunction login(args, finished) { var username = args.req.body.username; var password = args.req.body.password; var session = args.session; if (username === 'rob' && password === 'secret') { session.userText = 'Welcome Rob'; session.username = username;
// return success response } else { // invalid login – return an error }}
Update the session objectWith our own data
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Modulefunction login(args, finished) { var username = args.req.body.username; var password = args.req.body.password; var session = args.session; if (username === 'rob' && password === 'secret') { session.userText = 'Welcome Rob'; session.username = username; session.authenticated = true; session.timeout = 1200;
// return success response } else { // invalid login – return an error }}
These are reserved sessionproperties
authenticated helps determinethat the user was properlylogged in
timeout determines the JWTtimeout each time QEWDupdates it
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Modulefunction login(args, finished) { var username = args.req.body.username; var password = args.req.body.password; var session = args.session; if (username === 'rob' && password === 'secret') { session.userText = 'Welcome Rob'; session.username = username; session.authenticated = true; session.timeout = 1200; session.makeSecret('username'); session.makeSecret('authenticated');
// return success response } else { // invalid login – return an error }}
Make these two session propertiessecret. QEWD will encrypt themwithin the JWT so they aren'taccesible or usable by the client.
They will be available, however,for your back-end handler functions
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Modulefunction login(args, finished) { var username = args.req.body.username; var password = args.req.body.password; var session = args.session; if (username === 'rob' && password === 'secret') { session.userText = 'Welcome Rob'; session.username = username; session.authenticated = true; session.timeout = 1200; session.makeSecret('username'); session.makeSecret('authenticated'); finished({ok: true}); } else { // invalid login – return an error }}
Return a success response objectand release the worker process
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Modulefunction login(args, finished) { var username = args.req.body.username; var password = args.req.body.password; var session = args.session; if (username === 'rob' && password === 'secret') { session.userText = 'Welcome Rob'; session.username = username; session.authenticated = true; session.timeout = 1200; session.makeSecret('username'); session.makeSecret('authenticated'); finished({ok: true}); } else { return finished({error: 'Invalid login'}); }}
Return an error response objectand release the worker process
Copyright © 2016 M/Gateway Developments Ltd
Save the Login Handler Modulevar router = require('qewd-router');var routes;function login(args, finished) { var username = args.req.body.username; var password = args.req.body.password; var session = args.session; if (username === 'rob' && password === 'secret') { session.userText = 'Welcome Rob'; session.username = username; session.authenticated = true; session.timeout = 1200; session.makeSecret('username'); session.makeSecret('authenticated'); return finished({ok: true}); } else { return finished({error: 'Invalid login'}); }}module.exports = { init: function() { routes = { '/api/login': { POST: login } }; router.addMicroServiceHandler(routes, module.exports); }};
~/qewd/node_modules/login-micro-service.js
Copyright © 2016 M/Gateway Developments Ltd
Restart the QEWD on the Login machine and re-try POST /api/login
Now it works!
Copyright © 2016 M/Gateway Developments Ltd
Restart the QEWD on the Login machine and re-try POST /api/login
Notice that although we just asked to return {ok: true},it's returned an updated JWT also
Copyright © 2016 M/Gateway Developments Ltd
Let's decode that JWT
Copyright © 2016 M/Gateway Developments Ltd
Let's decode that JWT
Here are the non-secret properties we set in thelogin() function
Copyright © 2016 M/Gateway Developments Ltd
Let's decode that JWT
The secret ones are encrypted into this claim
Copyright © 2016 M/Gateway Developments Ltd
Try an invalid POST /api/login request
Notice that although we just asked to return {ok: true},it's returned an updated JWT also
Copyright © 2016 M/Gateway Developments Ltd
Try an invalid POST /api/login request
There's the error messageWe created in the login()function
Copyright © 2016 M/Gateway Developments Ltd
Try an invalid POST /api/login request
Note that when an error isreported, the JWT is notupdated
Copyright © 2016 M/Gateway Developments Ltd
We now have a working MicroService!
Copyright © 2016 M/Gateway Developments Ltd
We now have a working MicroService
• Let's now add a local API to the primary QEWD system– that can't be run until the user has logged in
via the Login MicroService
Copyright © 2016 M/Gateway Developments Ltd
Already Have a Local Route Defined
• Look in the Startup file and you'll see it also contains a route for locally processing all incoming REST requests starting /api:
var routes = [ { path: '/api', module: 'myRestService', errors: { notfound: { text: 'Resource Not Recognised', statusCode: 404 } } }];
Copyright © 2016 M/Gateway Developments Ltd
Already Have a Local Route Defined
• Look in the Startup file and you'll see it also contains a route for locally processing all incoming REST requests starting /api:
var routes = [ { path: '/api', module: 'myRestService', errors: { notfound: { text: 'Resource Not Recognised', statusCode: 404 } } }];
All /api requests other than /api/login willbe handled locally by the myRestServiceWorker process Handler module
Copyright © 2016 M/Gateway Developments Ltd
Already Have a Local Route Defined
• Look in the Startup file and you'll see it also contains a route for locally processing all incoming REST requests starting /api:
var routes = [ { path: '/api', module: 'myLocalServices', errors: { notfound: { text: 'Resource Not Recognised', statusCode: 404 } } }];
Let's change the name of thehandler module tomyLocalServices, to avoidconfusion
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler ModuleOn the primary QEWD machine:
~/qewd/node_modules/myLocalServices.js
var router = require('qewd-router');var routes;module.exports = { restModule: true,
init: function() { },
beforeHandler: function(req, finished) { }};
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler Modulevar router = require('qewd-router');var routes;module.exports = { restModule: true,
init: function() { routes = [ { url: '/api/info', method: 'GET', handler: info } ] routes = router.initialise(routes, module.exports); },
beforeHandler: function(req, finished) { }};
Define a route to be handled
GET /api/info will be handled bya function named info()
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler Modulevar router = require('qewd-router');var routes;module.exports = { restModule: true,
init: function() { routes = [ { url: '/api/info', method: 'GET', handler: info } ] routes = router.initialise(routes, module.exports); },
beforeHandler: function(req, finished) { }};
Tell QEWD to set up theHandler function stubsAutomatically within themodule
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler Modulevar router = require('qewd-router');var routes;module.exports = { restModule: true,
init: function() { routes = [ { url: '/api/info', method: 'GET', handler: info } ] routes = router.initialise(routes, module.exports); },
beforeHandler: function(req, finished) { }};
The beforeHandler() functionwill be invoked for every incoming/api request
We'll use this to confirm that theuser has logged in before allowingthe incoming request to be handled
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler Module beforeHandler: function(req, finished) { // invoked for every incoming request, // before the route-specific handler }
If the beforeHandler() function returns false,then the route-specific handler won't getcalled.
Any other return value (including undefined) will allow the route-specifichandler to run
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler Module beforeHandler: function(req, finished) { return this.jwt.handlers.validateRestRequest.call(this, req, finished); }
Add this code inside thebeforeHandler() function
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler Module beforeHandler: function(req, finished) { return this.jwt.handlers.validateRestRequest.call(this, req, finished); }
Use this built-in API to extract, validate anddecrypt the incoming JWT in the request'sAuthorization header
All incoming requests will now need to have aValid JWT, otherwise they'll be rejected
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler Module beforeHandler: function(req, finished) { return this.jwt.handlers.validateRestRequest.call(this, req, finished); }
Returns an error, releases the worker processand ceases any further handling of the request if:
-No Authorization Header was found-No JWT was found in the Authorization Header-The JWT signature wasn't valid-The JWT had expired
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler Module beforeHandler: function(req, finished) { return this.jwt.handlers.validateRestRequest.call(this, req, finished); }
Returns an error, releases the worker processand ceases any further handling of the request if:
-No Authorization Header was found-No JWT was found in the Authorization Header-The JWT signature wasn't valid-The JWT had expired
Otherwise, adds the extracted, decrypted payloadto the request as a Session object, and allows theroute-specific handler to be invoked
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler Modulevar router = require('qewd-router');var routes;
function info(args, finished) {}
module.exports = { restModule: true,
init: function() { routes = [ { url: '/api/info', method: 'GET', handler: info } ] routes = router.initialise(routes, module.exports); },
beforeHandler: function(req, finished) { //... etc }};
Now we'll add the info() function
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler Module
function info(args, finished) { args.session.ranInfoAt = Date.now(); var username = args.session.username; console.log('*** info args: ' + JSON.stringify(args, null, 2)); var jwt = this.jwt.handlers.setJWT.call(this, args.session);
finished({ info: { server: 'ubuntu119', loggedInAs: username, arch: process.arch, platform: process.platform, versions: process.versions, memory: process.memoryUsage() }, token: jwt });}
Add this code inside the info()function
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler Module
function info(args, finished) { args.session.ranInfoAt = Date.now(); var username = args.session.username; console.log('*** info args: ' + JSON.stringify(args, null, 2)); var jwt = this.jwt.handlers.setJWT.call(this, args.session);
finished({ info: { server: 'ubuntu119', loggedInAs: username, arch: process.arch, platform: process.platform, versions: process.versions, memory: process.memoryUsage() }, token: jwt });}
By the time the info() handler functionruns, the Session object has been made available as args.session.
We'll add a new property to the Session:-ranInfoAt which is the time when the function was run
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler Module
function info(args, finished) { args.session.ranInfoAt = Date.now(); var username = args.session.username; console.log('*** info args: ' + JSON.stringify(args, null, 2)); var jwt = this.jwt.handlers.setJWT.call(this, args.session);
finished({ info: { server: 'ubuntu119', loggedInAs: username, arch: process.arch, platform: process.platform, versions: process.versions, memory: process.memoryUsage() }, token: jwt });}
username was specified as a private JWT/Session value bythe Login MicroService. However, our handler function can accessit because this server has thesame JWT Secret
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler Module
function info(args, finished) { args.session.ranInfoAt = Date.now(); var username = args.session.username; console.log('*** info args: ' + JSON.stringify(args, null, 2)); var jwt = this.jwt.handlers.setJWT.call(this, args.session);
finished({ info: { server: 'ubuntu119', loggedInAs: username, arch: process.arch, platform: process.platform, versions: process.versions, memory: process.memoryUsage() }, token: jwt });}
You'll be able to see the decrypted, unpacked JWT payload displayedin the Node.js Console log
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler Module
function info(args, finished) { args.session.ranInfoAt = Date.now(); var username = args.session.username; console.log('*** info args: ' + JSON.stringify(args, null, 2)); var jwt = this.jwt.handlers.setJWT.call(this, args.session);
finished({ info: { server: 'ubuntu119', loggedInAs: username, arch: process.arch, platform: process.platform, versions: process.versions, memory: process.memoryUsage() }, token: jwt });}
We'll create a new JWT fromthe updated Session contents
This will also update the JWT'sexpiry time
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler Module
function info(args, finished) { args.session.ranInfoAt = Date.now(); var username = args.session.username; console.log('*** info args: ' + JSON.stringify(args, null, 2)); var jwt = this.jwt.handlers.setJWT.call(this, args.session);
finished({ info: { server: 'ubuntu119', loggedInAs: username, arch: process.arch, platform: process.platform, versions: process.versions, memory: process.memoryUsage() }, token: jwt });}
We'll return some items of Information about the server
We'll also display the username(which was a secret claim inThe JWT)
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler Module
function info(args, finished) { args.session.ranInfoAt = Date.now(); var username = args.session.username; console.log('*** info args: ' + JSON.stringify(args, null, 2)); var jwt = this.jwt.handlers.setJWT.call(this, args.session);
finished({ info: { server: 'ubuntu119', loggedInAs: username, arch: process.arch, platform: process.platform, versions: process.versions, memory: process.memoryUsage() }, token: jwt });}
And finally we'll also returnthe updated JWT
The Worker process willthen be released
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler Module
function info(args, finished) { args.session.ranInfoAt = Date.now(); var username = args.session.username; console.log('*** info args: ' + JSON.stringify(args, null, 2)); var jwt = this.jwt.handlers.setJWT.call(this, args.session);
finished({ info: { server: 'ubuntu119', loggedInAs: username, arch: process.arch, platform: process.platform, versions: process.versions, memory: process.memoryUsage() }, token: jwt });}
Save as ~/qewd/node_modules/myLocalServices.js
Copyright © 2016 M/Gateway Developments Ltd
Restart the Primary QEWD System and Try the GET /api/info request
Copyright © 2016 M/Gateway Developments Ltd
Add an invalid Authorization Header
Copyright © 2016 M/Gateway Developments Ltd
Add an invalid JWT
Copyright © 2016 M/Gateway Developments Ltd
Now Login using the Login MicroService
Note: Make sure you remove the Authorization Header!
Copyright © 2016 M/Gateway Developments Ltd
Successful Login
Copyright © 2016 M/Gateway Developments Ltd
Paste the JWT into the Authorization Header and try GET /api/info request again
Copyright © 2016 M/Gateway Developments Ltd
Success!
Copyright © 2016 M/Gateway Developments Ltd
Check the Node.js Console Logs
• When you run the POST /api/login request, you'll see activity on both servers– Request passed to Login MicroService and
response returned to primary QEWD server
Copyright © 2016 M/Gateway Developments Ltd
Check the Node.js Console Logs
• When you run the GET /api/info request, there's only activity on the primary QEWD Server as it's handled locally– But it's only allowing the request to be
handled locally if the JWT from the Login MicroService is present
Copyright © 2016 M/Gateway Developments Ltd
Adding More Local Routes
• You can add as many additional local routes as you want to the primary QEWD server's Worker Process handler module
• The beforeHandler() function will be automatically invoked before any of them are handled, so all will be authenticated
• Each one should follow the pattern we used for the /api/info route definition and info() function
Copyright © 2016 M/Gateway Developments Ltd
QEWD MicroServices
• You should now have all the information you need to build a set of MicroServices using QEWD systems
Copyright © 2016 M/Gateway Developments Ltd
Advanced QEWD MicroServices
• In the next Part of this course, we'll look at the advanced MicroServices features of QEWD, including:– Variables within URL Routes– Dynamic path-defined destinations
– Federated composite MicroServices from a group of destinations
– Re-direction of MicroService responses to another MicroService
– Chained MicroServices