SlideShare a Scribd company logo
Copyright © 2016 M/Gateway Developments Ltd
EWD 3 Training Course
Part 44
Creating MicroServices with QEWD.js
Rob Tweed
Director, 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-qoper8
queue
Express
Node.js
socket.io
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
ewd-qoper8
queue
Express
Node.js
socket.io
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
ewd-qoper8
queue
Express
Node.js
socket.io
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
User authentication
Demographics
Pharmacy
ewd-qoper8
queue
Express
Node.js
socket.io
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
Client Orchestration
HTTPS
WebSocket
Connections
Copyright © 2016 M/Gateway Developments Ltd
QEWD.js Solution
ewd-qoper8
queue
Express
Node.js
socket.io
Equivalent to
ewd-client
socket.io-client
Incoming REST
request
Copyright © 2016 M/Gateway Developments Ltd
QEWD.js Solution
ewd-qoper8
queue
Express
Node.js
socket.io
Equivalent to
ewd-client
socket.io-client
Incoming
WebSocket
request
Copyright © 2016 M/Gateway Developments Ltd
QEWD.js Solution
ewd-qoper8
queue
Express
Node.js
socket.io
Equivalent to
ewd-client
socket.io-client
Incoming
WebSocket
request
Process
Locally?
Copyright © 2016 M/Gateway Developments Ltd
QEWD.js Solution
ewd-qoper8
queue
Express
Node.js
socket.io
Equivalent to
ewd-client
socket.io-client
Incoming
WebSocket
request
Handled
by remote
MicroService?
Copyright © 2016 M/Gateway Developments Ltd
QEWD.js Solution
ewd-qoper8
queue
Express
Node.js
socket.io
Persistent
Bi-directional
WebSocket
connection
Secured
over
HTTPS
ewd-qoper8
queue
Express
Node.js
socket.io
Equivalent to
ewd-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-qoper8
queue
Express
Node.js
socket.io
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
User authentication
ewd-qoper8
queue
Express
Node.js
socket.io
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
Client Primary Server
HTTPS
WebSocket
Connections
Login MicroService Server
Copyright © 2016 M/Gateway Developments Ltd
Configuring the Primary Server
Copyright © 2016 M/Gateway Developments Ltd
Startup file from Part 43
var 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 Definition
var 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 Definition
var 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 Definition
jwt: {
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 Definition
jwt: {
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 Definition
jwt: {
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 Definition
jwt: {
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 Definition
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'
}
]
}
};
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definition
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'
}
]
}
Each Route is defined by an array element
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definition
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'
}
]
}
Each Route is defined by:
- A URL path (which can be templated)
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definition
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'
}
]
}
Each Route is defined by:
-optionally, an HTTP method
If not specified, the route will apply to
all HTTP methods for the path
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definition
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'
}
]
}
Each Route is defined by:
-the MicroService destination to which
the request will be routed
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definition
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'
}
]
}
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 Definition
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'
}
]
}
You can define as many Routes and
Destinations as you like
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definition
u_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 different
physical endpoints
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definition
u_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 appear
in more than one Destination
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definition
u_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 appear
in more than one Destination
In which case the application will be
different
Copyright © 2016 M/Gateway Developments Ltd
Add the MicroService Definition
u_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 Definition
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'
},
{
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 Definition
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'
}
]
}
};
In our example we'll just define a single
Destination and Route
POST requests for /api/login will be routed
to the MicroService QEWD system
at 192.168.1.114:8080, where they will be
handled by the login-micro-service
application
Copyright © 2016 M/Gateway Developments Ltd
Our Example MicroService Definition
var 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 the
login_service host
property to match the server
you'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 43
var 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 file
var 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 same
JWT Secret
Copyright © 2016 M/Gateway Developments Ltd
MicroService Startup file
var 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 QEWD
system will be handling
forwarded requests for
/api/login
Copyright © 2016 M/Gateway Developments Ltd
MicroService Startup file
var 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 primary
QEWD system will re-format
the /api/login REST requests to
a WebSocket message
Copyright © 2016 M/Gateway Developments Ltd
MicroService Startup file
var 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 primary
QEWD system will re-format
the /api/login REST requests to
a WebSocket message
These messages will be handled
by the login_micro-service
application on this QEWD system
Copyright © 2016 M/Gateway Developments Ltd
MicroService Startup file
var 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 ~/qewd
node ms-startup
Copyright © 2016 M/Gateway Developments Ltd
Look at the QEWD Node
Console Log
rtweed@ubuntu:~/qewd$ node microservices
Setting up micro-service connections
Adding MicroService Client connection: url = http://192.168.1.114:8080; application = login-micro-service
starting microService connection to http://192.168.1.114:8080
webServerRootPath = /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 microservices
Setting up micro-service connections
Adding MicroService Client connection: url = http://192.168.1.114:8080; application = login-micro-service
starting microService connection to http://192.168.1.114:8080
webServerRootPath = /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 MicroService
machine 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 ~/qewd
node loginservice
Copyright © 2016 M/Gateway Developments Ltd
Look at the QEWD Node Console
Log on the MicroService machine
rtweed@ubuntu:~/qewd$ node loginService
webServerRootPath = /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":"L7OwOn
Siqhr-nAmdAAAA","ipAddress":"::ffff:192.168.1.119"}
no available workers
sent qoper8-start message to 30140
process.argv[2] = qewd.worker
workerModule: qewd; worker
Session Garbage Collector has started in worker 30140
Tue, 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 again
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.eyJleHAiOjE1MDMzOTU1NjYsImlhdCI6MTUwMzM5NTI2Niwia
XNzIjoicWV3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ0aW1lb3V0IjozMDAsInFld2QiOiJmZTc0
U5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.DsDntCU3x2w21K3vmK3iaJd1kOhIj_Rl9h1
0469qXu4"}}
*** handleMessage response {"type":"ewd-register","finished":true,"message":{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e
hOTE0OGQ4Nzg1N2ZiZWM5Nzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdjZDUyMjE4ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM
0NWNhZjljYjgwMjM2ZjM0M2Q0OWIwMmE4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.D
sDntCU3x2w21K3vmK3iaJd1kOhIj_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 loginService
webServerRootPath = /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":"L7OwOn
Siqhr-nAmdAAAA","ipAddress":"::ffff:192.168.1.119"}
no available workers
sent qoper8-start message to 30140
process.argv[2] = qewd.worker
workerModule: qewd; worker
Session Garbage Collector has started in worker 30140
Tue, 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 again
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.eyJleHAiOjE1MDMzOTU1NjYsImlhdCI6MTUwMzM5NTI2Niwia
XNzIjoicWV3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ0aW1lb3V0IjozMDAsInFld2QiOiJmZTc0
U5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.DsDntCU3x2w21K3vmK3iaJd1kOhIj_Rl9h1
0469qXu4"}}
*** handleMessage response {"type":"ewd-register","finished":true,"message":{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e
hOTE0OGQ4Nzg1N2ZiZWM5Nzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdjZDUyMjE4ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM
0NWNhZjljYjgwMjM2ZjM0M2Q0OWIwMmE4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.D
sDntCU3x2w21K3vmK3iaJd1kOhIj_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":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUz
I1NiJ9.eyJleHAiOjE1MDMzOTU1NjYsImlhdCI6MTUwMzM5NTI2NiwiaXNzIjoicWV3ZC5qd3Q
iLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ0aW1lb3V0IjozMDAsInFld2Q
iOiJmZTc0NjBhM2ZjOGFmMWY5YjhlMWY1MWQ2M2FmYjQ3YTU5M2JkZDczYjNhOTE0OG
Q4Nzg1N2ZiZWM5Nzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdjZDUyMjE4ZjA1MTcxNGUxMT
ViNGJhMjU2OGEzNjQyZGM0NWNhZjljYjgwMjM2ZjM0M2Q0OWIwMmE4MzU5ZTZhNDRjNG
ZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.DsDntCU3x2w21K3vmK3iaJ
d1kOhIj_Rl9h10469qXu4"}}
*** handleMessage response {"type":"ewd-register","finished":true,"message":{"token":"eyJ0e
XAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDMzOTU1NjYsImlhdCI6MTUwMzM5NTI
2NiwiaXNzIjoicWV3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ
0aW1lb3V0IjozMDAsInFld2QiOiJmZTc0NjBhM2ZjOGFmMWY5YjhlMWY1MWQ2M2FmYjQ3Y
TU5M2JkZDczYjNhOTE0OGQ4Nzg1N2ZiZWM5Nzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdj
ZDUyMjE4ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM0NWNhZjljYjgwMjM2ZjM0M2Q0O
WIwMmE4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3I
n0.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 microservices
Setting up micro-service connections
Adding MicroService Client connection: url = http://192.168.1.114:8080; application = login-micro-service
starting microService connection to http://192.168.1.114:8080
webServerRootPath = /home/rtweed/qewd/www/
route /api will be handled by qx.router
login-micro-service registered
http://192.168.1.114:8080 micro-service ready
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
========================================================
Connection was established to the Login MicroService
QEWD system, and the login-micro-service application
was registered
Copyright © 2016 M/Gateway Developments Ltd
Now look at the Primary QEWD
Machine's Console Log
rtweed@ubuntu:~/qewd$ node microservices
Setting up micro-service connections
Adding MicroService Client connection: url = http://192.168.1.114:8080; application = login-micro-service
starting microService connection to http://192.168.1.114:8080
webServerRootPath = /home/rtweed/qewd/www/
route /api will be handled by qx.router
login-micro-service registered
http://192.168.1.114:8080 micro-service ready
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
========================================================
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 handler
For the login-micro-service application to handle
This 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":"eyJ
0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDMzOTk1NzMsImlhdCI6MTUwMz
M5OTI3MywiaXNzIjoicWV3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcn
ZpY2UiLCJ0aW1lb3V0IjozMDAsInFld2QiOiJmZTc0NjBhM2ZjOGFmMWY5YjhlMWY1MW
Q2MzhlZWM1OTZiMmJlYzU1YTI5MTRlODljNThmNTE4YTgwNzk2YTc4MmYwYmRmMm
Y0MjFlZTZjNTdjZDUyMjE4ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM0NWNhZjljYj
gwMjM2ZjM0M2Q0OWIwMmE4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZ
jc4MzEyODhlZGJkOTE3In0.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 Machine
Tue, 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":"eyJ0eXAiOiJKV1QiLCJhbGci
OiJIUzI1NiJ9.eyJleHAiOjE1MDMzOTk1NzMsImlhdCI6MTUwMzM5OTI3MywiaXNzIjoicWV
3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ0aW1lb3V0Ijoz
MDAsInFld2QiOiJmZTc0NjBhM2ZjOGFmMWY5YjhlMWY1MWQ2MzhlZWM1OTZiMmJlYz
U1YTI5MTRlODljNThmNTE4YTgwNzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdjZDUyMjE4
ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM0NWNhZjljYjgwMjM2ZjM0M2Q0OWIwMm
E4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.R
e4a6cEmIzQ9PFhwwYsoQ-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 Machine
Tue, 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":"eyJ0eXAiOiJKV1QiLCJhbGci
OiJIUzI1NiJ9.eyJleHAiOjE1MDMzOTk1NzMsImlhdCI6MTUwMzM5OTI3MywiaXNzIjoicWV
3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ0aW1lb3V0Ijoz
MDAsInFld2QiOiJmZTc0NjBhM2ZjOGFmMWY5YjhlMWY1MWQ2MzhlZWM1OTZiMmJlYz
U1YTI5MTRlODljNThmNTE4YTgwNzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdjZDUyMjE4
ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM0NWNhZjljYjgwMjM2ZjM0M2Q0OWIwMm
E4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.R
e4a6cEmIzQ9PFhwwYsoQ-UtMBKHkTPSpAk55FCDyV8","args":{},"jwt":true}
Copyright © 2016 M/Gateway Developments Ltd
Login MicroService Machine
Tue, 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":"eyJ0eXAiOiJKV1QiLCJhbGci
OiJIUzI1NiJ9.eyJleHAiOjE1MDMzOTk1NzMsImlhdCI6MTUwMzM5OTI3MywiaXNzIjoicWV
3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ0aW1lb3V0Ijoz
MDAsInFld2QiOiJmZTc0NjBhM2ZjOGFmMWY5YjhlMWY1MWQ2MzhlZWM1OTZiMmJlYz
U1YTI5MTRlODljNThmNTE4YTgwNzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdjZDUyMjE4
ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM0NWNhZjljYjgwMjM2ZjM0M2Q0OWIwMm
E4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.R
e4a6cEmIzQ9PFhwwYsoQ-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 Machine
Unable to load handler module for: login-micro-service: Error: Cannot find module
'login-micro-service'
Copyright © 2016 M/Gateway Developments Ltd
Login MicroService Machine
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
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 Module
var 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 Module
var router = require('qewd-router');
var routes;
module.exports = {
init: function() {
routes = {
'/api/login': {
POST: login
}
};
router.addMicroServiceHandler(routes, module.exports);
}
};
First we need to define
an init() function in which we'll
define our URL routes
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Module
var 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 routes
we want to handle.
We only have one:
POST /api/login
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Module
var 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 routes
we want to handle.
We only have one:
POST /api/login
And it will invoke a handler function
named login() (which we haven't
yet written)
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Module
var 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 the
handler function stubs for us
within the module
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Module
var 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 Module
var 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 interface
that you use for standard
REST route handling
The addMicroServiceHandler()
API normalises the interface
for you
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Module
var 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 interface
that you use for standard
REST route handling
args is an object containing:
-req: incoming request object
-session: the JWT payload
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Module
var 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 interface
that you use for standard
REST 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 credentials
will be in the message body object
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Module
function 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 the
valid credentials for simplicity
in this example
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Module
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;
// return success response
}
else {
// invalid login – return an error
}
}
Update the session object
With our own data
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Module
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;
// return success response
}
else {
// invalid login – return an error
}
}
These are reserved session
properties
authenticated helps determine
that the user was properly
logged in
timeout determines the JWT
timeout each time QEWD
updates it
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Module
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 success response
}
else {
// invalid login – return an error
}
}
Make these two session properties
secret. QEWD will encrypt them
within the JWT so they aren't
accesible or usable by the client.
They will be available, however,
for your back-end handler
functions
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Module
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');
finished({ok: true});
}
else {
// invalid login – return an error
}
}
Return a success response object
and release the worker process
Copyright © 2016 M/Gateway Developments Ltd
Login Handler Module
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');
finished({ok: true});
}
else {
return finished({error: 'Invalid login'});
}
}
Return an error response object
and release the worker process
Copyright © 2016 M/Gateway Developments Ltd
Save the Login Handler Module
var 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 the
login() 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 message
We created in the login()
function
Copyright © 2016 M/Gateway Developments Ltd
Try an invalid POST /api/login request
Note that when an error is
reported, the JWT is not
updated
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 will
be handled locally by the myRestService
Worker 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 the
handler module to
myLocalServices, to avoid
confusion
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler Module
On 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 Module
var 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 by
a function named info()
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler Module
var 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 the
Handler function stubs
Automatically within the
module
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler Module
var 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() function
will be invoked for every incoming
/api request
We'll use this to confirm that the
user has logged in before allowing
the 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 get
called.
Any other return value (including
undefined) will allow the route-specific
handler 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 the
beforeHandler() 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 and
decrypt the incoming JWT in the request's
Authorization header
All incoming requests will now need to have a
Valid 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 process
and 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 process
and 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 payload
to the request as a Session object, and allows the
route-specific handler to be invoked
Copyright © 2016 M/Gateway Developments Ltd
Create a new Handler Module
var 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 function
runs, 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 by
the Login MicroService. However,
our handler function can access
it because this server has the
same 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 displayed
in 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 from
the updated Session contents
This will also update the JWT's
expiry 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 in
The 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 return
the updated JWT
The Worker process will
then 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:
– Dynamic path-defined destinations
– Federated composite MicroServices from a
group of destinations
– Re-direction of MicroService responses to
another MicroService
– Chained MicroServices

More Related Content

What's hot

암호화 이것만 알면 된다.
암호화 이것만 알면 된다.암호화 이것만 알면 된다.
암호화 이것만 알면 된다.
KwangSeob Jeong
 
Secure SHell
Secure SHellSecure SHell
Secure SHell
Çağrı Çakır
 
NGINX: High Performance Load Balancing
NGINX: High Performance Load BalancingNGINX: High Performance Load Balancing
NGINX: High Performance Load Balancing
NGINX, Inc.
 
NAT Traversal
NAT TraversalNAT Traversal
NAT Traversal
Davide Carboni
 
[Community Open Camp] 給 PHP 開發者的 VS Code 指南
[Community Open Camp] 給 PHP 開發者的 VS Code 指南[Community Open Camp] 給 PHP 開發者的 VS Code 指南
[Community Open Camp] 給 PHP 開發者的 VS Code 指南
Shengyou Fan
 
2 TomcatによるWebアプリケーションサーバ構築 第4章 Tomcatの構成(2)-デプロイ
2 TomcatによるWebアプリケーションサーバ構築 第4章 Tomcatの構成(2)-デプロイ2 TomcatによるWebアプリケーションサーバ構築 第4章 Tomcatの構成(2)-デプロイ
2 TomcatによるWebアプリケーションサーバ構築 第4章 Tomcatの構成(2)-デプロイEnpel
 
Vyos clustering ipsec
Vyos clustering ipsecVyos clustering ipsec
Vyos clustering ipsec
Gireesh Hariharasubramony
 
Load Balancing and Scaling with NGINX
Load Balancing and Scaling with NGINXLoad Balancing and Scaling with NGINX
Load Balancing and Scaling with NGINX
NGINX, Inc.
 
Tuning TCP and NGINX on EC2
Tuning TCP and NGINX on EC2Tuning TCP and NGINX on EC2
Tuning TCP and NGINX on EC2
Chartbeat
 
An introduction to SSH
An introduction to SSHAn introduction to SSH
An introduction to SSH
nussbauml
 
ssh.ppt
ssh.pptssh.ppt
ssh.ppt
joekr1
 
Deep Dive into Keystone Tokens and Lessons Learned
Deep Dive into Keystone Tokens and Lessons LearnedDeep Dive into Keystone Tokens and Lessons Learned
Deep Dive into Keystone Tokens and Lessons Learned
Priti Desai
 
NGINX ADC: Basics and Best Practices – EMEA
NGINX ADC: Basics and Best Practices – EMEANGINX ADC: Basics and Best Practices – EMEA
NGINX ADC: Basics and Best Practices – EMEA
NGINX, Inc.
 
CloudStack and cloud-init
CloudStack and cloud-initCloudStack and cloud-init
CloudStack and cloud-init
MarcusS13
 
Netem -emulating real networks in the lab
Netem -emulating real networks in the labNetem -emulating real networks in the lab
Netem -emulating real networks in the lab
Stephen Hemminger
 
OpenSSL programming (still somewhat initial version)
OpenSSL programming (still somewhat initial version)OpenSSL programming (still somewhat initial version)
OpenSSL programming (still somewhat initial version)
Shteryana Shopova
 
Intro to CloudStack API
Intro to CloudStack APIIntro to CloudStack API
Intro to CloudStack API
Sebastien Goasguen
 
HTTP/3 for everyone
HTTP/3 for everyoneHTTP/3 for everyone
HTTP/3 for everyone
Daniel Stenberg
 
Oracle Unified Directory. Lessons learnt. Is it ready for a move from OID? (O...
Oracle Unified Directory. Lessons learnt. Is it ready for a move from OID? (O...Oracle Unified Directory. Lessons learnt. Is it ready for a move from OID? (O...
Oracle Unified Directory. Lessons learnt. Is it ready for a move from OID? (O...
Andrejs Prokopjevs
 
Nginx Essential
Nginx EssentialNginx Essential
Nginx Essential
Gong Haibing
 

What's hot (20)

암호화 이것만 알면 된다.
암호화 이것만 알면 된다.암호화 이것만 알면 된다.
암호화 이것만 알면 된다.
 
Secure SHell
Secure SHellSecure SHell
Secure SHell
 
NGINX: High Performance Load Balancing
NGINX: High Performance Load BalancingNGINX: High Performance Load Balancing
NGINX: High Performance Load Balancing
 
NAT Traversal
NAT TraversalNAT Traversal
NAT Traversal
 
[Community Open Camp] 給 PHP 開發者的 VS Code 指南
[Community Open Camp] 給 PHP 開發者的 VS Code 指南[Community Open Camp] 給 PHP 開發者的 VS Code 指南
[Community Open Camp] 給 PHP 開發者的 VS Code 指南
 
2 TomcatによるWebアプリケーションサーバ構築 第4章 Tomcatの構成(2)-デプロイ
2 TomcatによるWebアプリケーションサーバ構築 第4章 Tomcatの構成(2)-デプロイ2 TomcatによるWebアプリケーションサーバ構築 第4章 Tomcatの構成(2)-デプロイ
2 TomcatによるWebアプリケーションサーバ構築 第4章 Tomcatの構成(2)-デプロイ
 
Vyos clustering ipsec
Vyos clustering ipsecVyos clustering ipsec
Vyos clustering ipsec
 
Load Balancing and Scaling with NGINX
Load Balancing and Scaling with NGINXLoad Balancing and Scaling with NGINX
Load Balancing and Scaling with NGINX
 
Tuning TCP and NGINX on EC2
Tuning TCP and NGINX on EC2Tuning TCP and NGINX on EC2
Tuning TCP and NGINX on EC2
 
An introduction to SSH
An introduction to SSHAn introduction to SSH
An introduction to SSH
 
ssh.ppt
ssh.pptssh.ppt
ssh.ppt
 
Deep Dive into Keystone Tokens and Lessons Learned
Deep Dive into Keystone Tokens and Lessons LearnedDeep Dive into Keystone Tokens and Lessons Learned
Deep Dive into Keystone Tokens and Lessons Learned
 
NGINX ADC: Basics and Best Practices – EMEA
NGINX ADC: Basics and Best Practices – EMEANGINX ADC: Basics and Best Practices – EMEA
NGINX ADC: Basics and Best Practices – EMEA
 
CloudStack and cloud-init
CloudStack and cloud-initCloudStack and cloud-init
CloudStack and cloud-init
 
Netem -emulating real networks in the lab
Netem -emulating real networks in the labNetem -emulating real networks in the lab
Netem -emulating real networks in the lab
 
OpenSSL programming (still somewhat initial version)
OpenSSL programming (still somewhat initial version)OpenSSL programming (still somewhat initial version)
OpenSSL programming (still somewhat initial version)
 
Intro to CloudStack API
Intro to CloudStack APIIntro to CloudStack API
Intro to CloudStack API
 
HTTP/3 for everyone
HTTP/3 for everyoneHTTP/3 for everyone
HTTP/3 for everyone
 
Oracle Unified Directory. Lessons learnt. Is it ready for a move from OID? (O...
Oracle Unified Directory. Lessons learnt. Is it ready for a move from OID? (O...Oracle Unified Directory. Lessons learnt. Is it ready for a move from OID? (O...
Oracle Unified Directory. Lessons learnt. Is it ready for a move from OID? (O...
 
Nginx Essential
Nginx EssentialNginx Essential
Nginx Essential
 

Similar to EWD 3 Training Course Part 44: Creating MicroServices with QEWD.js

EWD 3 Training Course Part 45: Using QEWD's Advanced MicroService Functionality
EWD 3 Training Course Part 45: Using QEWD's Advanced MicroService FunctionalityEWD 3 Training Course Part 45: Using QEWD's Advanced MicroService Functionality
EWD 3 Training Course Part 45: Using QEWD's Advanced MicroService Functionality
Rob Tweed
 
EWD 3 Training Course Part 8: Anatomy of the QEWD Messaging Cycle
EWD 3 Training Course Part 8: Anatomy of the QEWD Messaging CycleEWD 3 Training Course Part 8: Anatomy of the QEWD Messaging Cycle
EWD 3 Training Course Part 8: Anatomy of the QEWD Messaging Cycle
Rob Tweed
 
qewd-ripple: The Ripple OSI Middle Tier
qewd-ripple: The Ripple OSI Middle Tierqewd-ripple: The Ripple OSI Middle Tier
qewd-ripple: The Ripple OSI Middle Tier
Rob Tweed
 
EWD 3 Training Course Part 36: Accessing REST and Web Services from a QEWD ap...
EWD 3 Training Course Part 36: Accessing REST and Web Services from a QEWD ap...EWD 3 Training Course Part 36: Accessing REST and Web Services from a QEWD ap...
EWD 3 Training Course Part 36: Accessing REST and Web Services from a QEWD ap...
Rob Tweed
 
EWD 3 Training Course Part 5b: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5b: First Steps in Building a QEWD ApplicationEWD 3 Training Course Part 5b: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5b: First Steps in Building a QEWD Application
Rob Tweed
 
EWD 3 Training Course Part 16: QEWD Services
EWD 3 Training Course Part 16: QEWD ServicesEWD 3 Training Course Part 16: QEWD Services
EWD 3 Training Course Part 16: QEWD Services
Rob Tweed
 
Microservices with Node.js and Apache Cassandra
Microservices with Node.js and Apache CassandraMicroservices with Node.js and Apache Cassandra
Microservices with Node.js and Apache Cassandra
Jorge Bay Gondra
 
EWD 3 Training Course Part 3: Summary of EWD 3 Modules
EWD 3 Training Course Part 3: Summary of EWD 3 ModulesEWD 3 Training Course Part 3: Summary of EWD 3 Modules
EWD 3 Training Course Part 3: Summary of EWD 3 Modules
Rob Tweed
 
EWD 3 Training Course Part 6: What Happens when a QEWD Application is Started
EWD 3 Training Course Part 6: What Happens when a QEWD Application is StartedEWD 3 Training Course Part 6: What Happens when a QEWD Application is Started
EWD 3 Training Course Part 6: What Happens when a QEWD Application is Started
Rob Tweed
 
ewd-qoper8-vistarpc: Exposing VistA's RPCs as REST Services
ewd-qoper8-vistarpc: Exposing VistA's RPCs as REST Servicesewd-qoper8-vistarpc: Exposing VistA's RPCs as REST Services
ewd-qoper8-vistarpc: Exposing VistA's RPCs as REST Services
Rob Tweed
 
Simplify and Scale Enterprise Apps in the Cloud | Boston 2023
Simplify and Scale Enterprise Apps in the Cloud | Boston 2023Simplify and Scale Enterprise Apps in the Cloud | Boston 2023
Simplify and Scale Enterprise Apps in the Cloud | Boston 2023
VMware Tanzu
 
Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023
Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023
Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023
VMware Tanzu
 
Cloud APIs Overview Tucker
Cloud APIs Overview   TuckerCloud APIs Overview   Tucker
Cloud APIs Overview Tucker
Infrastructure 2.0
 
EWD 3 Training Course Part 5a: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5a: First Steps in Building a QEWD ApplicationEWD 3 Training Course Part 5a: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5a: First Steps in Building a QEWD Application
Rob Tweed
 
Accessing APIs using OAuth on the federated (WordPress) web
Accessing APIs using OAuth on the federated (WordPress) webAccessing APIs using OAuth on the federated (WordPress) web
Accessing APIs using OAuth on the federated (WordPress) web
Felix Arntz
 
DevSecOps: Let's Write Security Unit Tests
DevSecOps: Let's Write Security Unit TestsDevSecOps: Let's Write Security Unit Tests
DevSecOps: Let's Write Security Unit Tests
Puma Security, LLC
 
Running your Spring Apps in the Cloud Javaone 2014
Running your Spring Apps in the Cloud Javaone 2014Running your Spring Apps in the Cloud Javaone 2014
Running your Spring Apps in the Cloud Javaone 2014
cornelia davis
 
PRIVATE CLOUD SERVER IMPLEMENTATIONS FOR DATA STORAGE
PRIVATE CLOUD SERVER IMPLEMENTATIONS FOR DATA STORAGEPRIVATE CLOUD SERVER IMPLEMENTATIONS FOR DATA STORAGE
PRIVATE CLOUD SERVER IMPLEMENTATIONS FOR DATA STORAGE
Editor IJCTER
 
Ruby Driver Explained: DataStax Webinar May 5th 2015
Ruby Driver Explained: DataStax Webinar May 5th 2015Ruby Driver Explained: DataStax Webinar May 5th 2015
Ruby Driver Explained: DataStax Webinar May 5th 2015
DataStax
 
Hands-On Lab: Managing and Monitoring Node.js Made Easy with CA Application P...
Hands-On Lab: Managing and Monitoring Node.js Made Easy with CA Application P...Hands-On Lab: Managing and Monitoring Node.js Made Easy with CA Application P...
Hands-On Lab: Managing and Monitoring Node.js Made Easy with CA Application P...
CA Technologies
 

Similar to EWD 3 Training Course Part 44: Creating MicroServices with QEWD.js (20)

EWD 3 Training Course Part 45: Using QEWD's Advanced MicroService Functionality
EWD 3 Training Course Part 45: Using QEWD's Advanced MicroService FunctionalityEWD 3 Training Course Part 45: Using QEWD's Advanced MicroService Functionality
EWD 3 Training Course Part 45: Using QEWD's Advanced MicroService Functionality
 
EWD 3 Training Course Part 8: Anatomy of the QEWD Messaging Cycle
EWD 3 Training Course Part 8: Anatomy of the QEWD Messaging CycleEWD 3 Training Course Part 8: Anatomy of the QEWD Messaging Cycle
EWD 3 Training Course Part 8: Anatomy of the QEWD Messaging Cycle
 
qewd-ripple: The Ripple OSI Middle Tier
qewd-ripple: The Ripple OSI Middle Tierqewd-ripple: The Ripple OSI Middle Tier
qewd-ripple: The Ripple OSI Middle Tier
 
EWD 3 Training Course Part 36: Accessing REST and Web Services from a QEWD ap...
EWD 3 Training Course Part 36: Accessing REST and Web Services from a QEWD ap...EWD 3 Training Course Part 36: Accessing REST and Web Services from a QEWD ap...
EWD 3 Training Course Part 36: Accessing REST and Web Services from a QEWD ap...
 
EWD 3 Training Course Part 5b: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5b: First Steps in Building a QEWD ApplicationEWD 3 Training Course Part 5b: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5b: First Steps in Building a QEWD Application
 
EWD 3 Training Course Part 16: QEWD Services
EWD 3 Training Course Part 16: QEWD ServicesEWD 3 Training Course Part 16: QEWD Services
EWD 3 Training Course Part 16: QEWD Services
 
Microservices with Node.js and Apache Cassandra
Microservices with Node.js and Apache CassandraMicroservices with Node.js and Apache Cassandra
Microservices with Node.js and Apache Cassandra
 
EWD 3 Training Course Part 3: Summary of EWD 3 Modules
EWD 3 Training Course Part 3: Summary of EWD 3 ModulesEWD 3 Training Course Part 3: Summary of EWD 3 Modules
EWD 3 Training Course Part 3: Summary of EWD 3 Modules
 
EWD 3 Training Course Part 6: What Happens when a QEWD Application is Started
EWD 3 Training Course Part 6: What Happens when a QEWD Application is StartedEWD 3 Training Course Part 6: What Happens when a QEWD Application is Started
EWD 3 Training Course Part 6: What Happens when a QEWD Application is Started
 
ewd-qoper8-vistarpc: Exposing VistA's RPCs as REST Services
ewd-qoper8-vistarpc: Exposing VistA's RPCs as REST Servicesewd-qoper8-vistarpc: Exposing VistA's RPCs as REST Services
ewd-qoper8-vistarpc: Exposing VistA's RPCs as REST Services
 
Simplify and Scale Enterprise Apps in the Cloud | Boston 2023
Simplify and Scale Enterprise Apps in the Cloud | Boston 2023Simplify and Scale Enterprise Apps in the Cloud | Boston 2023
Simplify and Scale Enterprise Apps in the Cloud | Boston 2023
 
Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023
Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023
Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023
 
Cloud APIs Overview Tucker
Cloud APIs Overview   TuckerCloud APIs Overview   Tucker
Cloud APIs Overview Tucker
 
EWD 3 Training Course Part 5a: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5a: First Steps in Building a QEWD ApplicationEWD 3 Training Course Part 5a: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5a: First Steps in Building a QEWD Application
 
Accessing APIs using OAuth on the federated (WordPress) web
Accessing APIs using OAuth on the federated (WordPress) webAccessing APIs using OAuth on the federated (WordPress) web
Accessing APIs using OAuth on the federated (WordPress) web
 
DevSecOps: Let's Write Security Unit Tests
DevSecOps: Let's Write Security Unit TestsDevSecOps: Let's Write Security Unit Tests
DevSecOps: Let's Write Security Unit Tests
 
Running your Spring Apps in the Cloud Javaone 2014
Running your Spring Apps in the Cloud Javaone 2014Running your Spring Apps in the Cloud Javaone 2014
Running your Spring Apps in the Cloud Javaone 2014
 
PRIVATE CLOUD SERVER IMPLEMENTATIONS FOR DATA STORAGE
PRIVATE CLOUD SERVER IMPLEMENTATIONS FOR DATA STORAGEPRIVATE CLOUD SERVER IMPLEMENTATIONS FOR DATA STORAGE
PRIVATE CLOUD SERVER IMPLEMENTATIONS FOR DATA STORAGE
 
Ruby Driver Explained: DataStax Webinar May 5th 2015
Ruby Driver Explained: DataStax Webinar May 5th 2015Ruby Driver Explained: DataStax Webinar May 5th 2015
Ruby Driver Explained: DataStax Webinar May 5th 2015
 
Hands-On Lab: Managing and Monitoring Node.js Made Easy with CA Application P...
Hands-On Lab: Managing and Monitoring Node.js Made Easy with CA Application P...Hands-On Lab: Managing and Monitoring Node.js Made Easy with CA Application P...
Hands-On Lab: Managing and Monitoring Node.js Made Easy with CA Application P...
 

More from Rob Tweed

QEWD Update
QEWD UpdateQEWD Update
QEWD Update
Rob Tweed
 
Data Persistence as a Language Feature
Data Persistence as a Language FeatureData Persistence as a Language Feature
Data Persistence as a Language Feature
Rob Tweed
 
LNUG: Having Your Node.js Cake and Eating It Too
LNUG: Having Your Node.js Cake and Eating It TooLNUG: Having Your Node.js Cake and Eating It Too
LNUG: Having Your Node.js Cake and Eating It Too
Rob Tweed
 
EWD 3 Training Course Part 43: Using JSON Web Tokens with QEWD REST Services
EWD 3 Training Course Part 43: Using JSON Web Tokens with QEWD REST ServicesEWD 3 Training Course Part 43: Using JSON Web Tokens with QEWD REST Services
EWD 3 Training Course Part 43: Using JSON Web Tokens with QEWD REST Services
Rob Tweed
 
QEWD.js, JSON Web Tokens & MicroServices
QEWD.js, JSON Web Tokens & MicroServicesQEWD.js, JSON Web Tokens & MicroServices
QEWD.js, JSON Web Tokens & MicroServices
Rob Tweed
 
QEWD.js: Have your Node.js Cake and Eat It Too
QEWD.js: Have your Node.js Cake and Eat It TooQEWD.js: Have your Node.js Cake and Eat It Too
QEWD.js: Have your Node.js Cake and Eat It Too
Rob Tweed
 
EWD 3 Training Course Part 41: Building a React.js application with QEWD, Part 5
EWD 3 Training Course Part 41: Building a React.js application with QEWD, Part 5EWD 3 Training Course Part 41: Building a React.js application with QEWD, Part 5
EWD 3 Training Course Part 41: Building a React.js application with QEWD, Part 5
Rob Tweed
 
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4
Rob Tweed
 
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
Rob Tweed
 
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 2
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 2EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 2
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 2
Rob Tweed
 
EWD 3 Training Course Part 37: Building a React.js application with ewd-xpres...
EWD 3 Training Course Part 37: Building a React.js application with ewd-xpres...EWD 3 Training Course Part 37: Building a React.js application with ewd-xpres...
EWD 3 Training Course Part 37: Building a React.js application with ewd-xpres...
Rob Tweed
 
EWD 3 Training Course Part 35: QEWD Session Locking
EWD 3 Training Course Part 35: QEWD Session LockingEWD 3 Training Course Part 35: QEWD Session Locking
EWD 3 Training Course Part 35: QEWD Session Locking
Rob Tweed
 
EWD 3 Training Course Part 34: QEWD Resilient Mode
EWD 3 Training Course Part 34: QEWD Resilient ModeEWD 3 Training Course Part 34: QEWD Resilient Mode
EWD 3 Training Course Part 34: QEWD Resilient Mode
Rob Tweed
 
EWD 3 Training Course Part 33: Configuring QEWD to use CORS
EWD 3 Training Course Part 33: Configuring QEWD to use CORSEWD 3 Training Course Part 33: Configuring QEWD to use CORS
EWD 3 Training Course Part 33: Configuring QEWD to use CORS
Rob Tweed
 
EWD 3 Training Course Part 32: Configuring QEWD to use SSL/HTTPS
EWD 3 Training Course Part 32: Configuring QEWD to use SSL/HTTPSEWD 3 Training Course Part 32: Configuring QEWD to use SSL/HTTPS
EWD 3 Training Course Part 32: Configuring QEWD to use SSL/HTTPS
Rob Tweed
 
EWD 3 Training Course Part 30: Modularising QEWD Applications
EWD 3 Training Course Part 30: Modularising QEWD ApplicationsEWD 3 Training Course Part 30: Modularising QEWD Applications
EWD 3 Training Course Part 30: Modularising QEWD Applications
Rob Tweed
 
EWD 3 Training Course Part 29: Running QEWD as a Service
EWD 3 Training Course Part 29: Running QEWD as a ServiceEWD 3 Training Course Part 29: Running QEWD as a Service
EWD 3 Training Course Part 29: Running QEWD as a Service
Rob Tweed
 
EWD 3 Training Course Part 28: Integrating Legacy Mumps Code with QEWD
EWD 3 Training Course Part 28: Integrating Legacy Mumps Code with QEWDEWD 3 Training Course Part 28: Integrating Legacy Mumps Code with QEWD
EWD 3 Training Course Part 28: Integrating Legacy Mumps Code with QEWD
Rob Tweed
 
EWD 3 Training Course Part 27: The QEWD Session
EWD 3 Training Course Part 27: The QEWD SessionEWD 3 Training Course Part 27: The QEWD Session
EWD 3 Training Course Part 27: The QEWD Session
Rob Tweed
 
EWD 3 Training Course Part 26: Event-driven Indexing
EWD 3 Training Course Part 26: Event-driven IndexingEWD 3 Training Course Part 26: Event-driven Indexing
EWD 3 Training Course Part 26: Event-driven Indexing
Rob Tweed
 

More from Rob Tweed (20)

QEWD Update
QEWD UpdateQEWD Update
QEWD Update
 
Data Persistence as a Language Feature
Data Persistence as a Language FeatureData Persistence as a Language Feature
Data Persistence as a Language Feature
 
LNUG: Having Your Node.js Cake and Eating It Too
LNUG: Having Your Node.js Cake and Eating It TooLNUG: Having Your Node.js Cake and Eating It Too
LNUG: Having Your Node.js Cake and Eating It Too
 
EWD 3 Training Course Part 43: Using JSON Web Tokens with QEWD REST Services
EWD 3 Training Course Part 43: Using JSON Web Tokens with QEWD REST ServicesEWD 3 Training Course Part 43: Using JSON Web Tokens with QEWD REST Services
EWD 3 Training Course Part 43: Using JSON Web Tokens with QEWD REST Services
 
QEWD.js, JSON Web Tokens & MicroServices
QEWD.js, JSON Web Tokens & MicroServicesQEWD.js, JSON Web Tokens & MicroServices
QEWD.js, JSON Web Tokens & MicroServices
 
QEWD.js: Have your Node.js Cake and Eat It Too
QEWD.js: Have your Node.js Cake and Eat It TooQEWD.js: Have your Node.js Cake and Eat It Too
QEWD.js: Have your Node.js Cake and Eat It Too
 
EWD 3 Training Course Part 41: Building a React.js application with QEWD, Part 5
EWD 3 Training Course Part 41: Building a React.js application with QEWD, Part 5EWD 3 Training Course Part 41: Building a React.js application with QEWD, Part 5
EWD 3 Training Course Part 41: Building a React.js application with QEWD, Part 5
 
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4
 
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
 
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 2
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 2EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 2
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 2
 
EWD 3 Training Course Part 37: Building a React.js application with ewd-xpres...
EWD 3 Training Course Part 37: Building a React.js application with ewd-xpres...EWD 3 Training Course Part 37: Building a React.js application with ewd-xpres...
EWD 3 Training Course Part 37: Building a React.js application with ewd-xpres...
 
EWD 3 Training Course Part 35: QEWD Session Locking
EWD 3 Training Course Part 35: QEWD Session LockingEWD 3 Training Course Part 35: QEWD Session Locking
EWD 3 Training Course Part 35: QEWD Session Locking
 
EWD 3 Training Course Part 34: QEWD Resilient Mode
EWD 3 Training Course Part 34: QEWD Resilient ModeEWD 3 Training Course Part 34: QEWD Resilient Mode
EWD 3 Training Course Part 34: QEWD Resilient Mode
 
EWD 3 Training Course Part 33: Configuring QEWD to use CORS
EWD 3 Training Course Part 33: Configuring QEWD to use CORSEWD 3 Training Course Part 33: Configuring QEWD to use CORS
EWD 3 Training Course Part 33: Configuring QEWD to use CORS
 
EWD 3 Training Course Part 32: Configuring QEWD to use SSL/HTTPS
EWD 3 Training Course Part 32: Configuring QEWD to use SSL/HTTPSEWD 3 Training Course Part 32: Configuring QEWD to use SSL/HTTPS
EWD 3 Training Course Part 32: Configuring QEWD to use SSL/HTTPS
 
EWD 3 Training Course Part 30: Modularising QEWD Applications
EWD 3 Training Course Part 30: Modularising QEWD ApplicationsEWD 3 Training Course Part 30: Modularising QEWD Applications
EWD 3 Training Course Part 30: Modularising QEWD Applications
 
EWD 3 Training Course Part 29: Running QEWD as a Service
EWD 3 Training Course Part 29: Running QEWD as a ServiceEWD 3 Training Course Part 29: Running QEWD as a Service
EWD 3 Training Course Part 29: Running QEWD as a Service
 
EWD 3 Training Course Part 28: Integrating Legacy Mumps Code with QEWD
EWD 3 Training Course Part 28: Integrating Legacy Mumps Code with QEWDEWD 3 Training Course Part 28: Integrating Legacy Mumps Code with QEWD
EWD 3 Training Course Part 28: Integrating Legacy Mumps Code with QEWD
 
EWD 3 Training Course Part 27: The QEWD Session
EWD 3 Training Course Part 27: The QEWD SessionEWD 3 Training Course Part 27: The QEWD Session
EWD 3 Training Course Part 27: The QEWD Session
 
EWD 3 Training Course Part 26: Event-driven Indexing
EWD 3 Training Course Part 26: Event-driven IndexingEWD 3 Training Course Part 26: Event-driven Indexing
EWD 3 Training Course Part 26: Event-driven Indexing
 

Recently uploaded

8 Best Automated Android App Testing Tool and Framework in 2024.pdf
8 Best Automated Android App Testing Tool and Framework in 2024.pdf8 Best Automated Android App Testing Tool and Framework in 2024.pdf
8 Best Automated Android App Testing Tool and Framework in 2024.pdf
kalichargn70th171
 
Hand Rolled Applicative User Validation Code Kata
Hand Rolled Applicative User ValidationCode KataHand Rolled Applicative User ValidationCode Kata
Hand Rolled Applicative User Validation Code Kata
Philip Schwarz
 
Measures in SQL (SIGMOD 2024, Santiago, Chile)
Measures in SQL (SIGMOD 2024, Santiago, Chile)Measures in SQL (SIGMOD 2024, Santiago, Chile)
Measures in SQL (SIGMOD 2024, Santiago, Chile)
Julian Hyde
 
Energy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina JonuziEnergy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina Jonuzi
Green Software Development
 
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
mz5nrf0n
 
Mobile app Development Services | Drona Infotech
Mobile app Development Services  | Drona InfotechMobile app Development Services  | Drona Infotech
Mobile app Development Services | Drona Infotech
Drona Infotech
 
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdfTop Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
VALiNTRY360
 
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
Bert Jan Schrijver
 
UI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
UI5con 2024 - Boost Your Development Experience with UI5 Tooling ExtensionsUI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
UI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
Peter Muessig
 
Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !
Marcin Chrost
 
All you need to know about Spring Boot and GraalVM
All you need to know about Spring Boot and GraalVMAll you need to know about Spring Boot and GraalVM
All you need to know about Spring Boot and GraalVM
Alina Yurenko
 
WWDC 2024 Keynote Review: For CocoaCoders Austin
WWDC 2024 Keynote Review: For CocoaCoders AustinWWDC 2024 Keynote Review: For CocoaCoders Austin
WWDC 2024 Keynote Review: For CocoaCoders Austin
Patrick Weigel
 
Odoo ERP Vs. Traditional ERP Systems – A Comparative Analysis
Odoo ERP Vs. Traditional ERP Systems – A Comparative AnalysisOdoo ERP Vs. Traditional ERP Systems – A Comparative Analysis
Odoo ERP Vs. Traditional ERP Systems – A Comparative Analysis
Envertis Software Solutions
 
Using Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional SafetyUsing Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional Safety
Ayan Halder
 
Mobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona InfotechMobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona Infotech
Drona Infotech
 
Oracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptxOracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptx
Remote DBA Services
 
Transform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR SolutionsTransform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR Solutions
TheSMSPoint
 
GreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-JurisicGreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-Jurisic
Green Software Development
 
What next after learning python programming basics
What next after learning python programming basicsWhat next after learning python programming basics
What next after learning python programming basics
Rakesh Kumar R
 
Unveiling the Advantages of Agile Software Development.pdf
Unveiling the Advantages of Agile Software Development.pdfUnveiling the Advantages of Agile Software Development.pdf
Unveiling the Advantages of Agile Software Development.pdf
brainerhub1
 

Recently uploaded (20)

8 Best Automated Android App Testing Tool and Framework in 2024.pdf
8 Best Automated Android App Testing Tool and Framework in 2024.pdf8 Best Automated Android App Testing Tool and Framework in 2024.pdf
8 Best Automated Android App Testing Tool and Framework in 2024.pdf
 
Hand Rolled Applicative User Validation Code Kata
Hand Rolled Applicative User ValidationCode KataHand Rolled Applicative User ValidationCode Kata
Hand Rolled Applicative User Validation Code Kata
 
Measures in SQL (SIGMOD 2024, Santiago, Chile)
Measures in SQL (SIGMOD 2024, Santiago, Chile)Measures in SQL (SIGMOD 2024, Santiago, Chile)
Measures in SQL (SIGMOD 2024, Santiago, Chile)
 
Energy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina JonuziEnergy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina Jonuzi
 
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
 
Mobile app Development Services | Drona Infotech
Mobile app Development Services  | Drona InfotechMobile app Development Services  | Drona Infotech
Mobile app Development Services | Drona Infotech
 
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdfTop Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
 
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
 
UI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
UI5con 2024 - Boost Your Development Experience with UI5 Tooling ExtensionsUI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
UI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
 
Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !
 
All you need to know about Spring Boot and GraalVM
All you need to know about Spring Boot and GraalVMAll you need to know about Spring Boot and GraalVM
All you need to know about Spring Boot and GraalVM
 
WWDC 2024 Keynote Review: For CocoaCoders Austin
WWDC 2024 Keynote Review: For CocoaCoders AustinWWDC 2024 Keynote Review: For CocoaCoders Austin
WWDC 2024 Keynote Review: For CocoaCoders Austin
 
Odoo ERP Vs. Traditional ERP Systems – A Comparative Analysis
Odoo ERP Vs. Traditional ERP Systems – A Comparative AnalysisOdoo ERP Vs. Traditional ERP Systems – A Comparative Analysis
Odoo ERP Vs. Traditional ERP Systems – A Comparative Analysis
 
Using Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional SafetyUsing Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional Safety
 
Mobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona InfotechMobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona Infotech
 
Oracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptxOracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptx
 
Transform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR SolutionsTransform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR Solutions
 
GreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-JurisicGreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-Jurisic
 
What next after learning python programming basics
What next after learning python programming basicsWhat next after learning python programming basics
What next after learning python programming basics
 
Unveiling the Advantages of Agile Software Development.pdf
Unveiling the Advantages of Agile Software Development.pdfUnveiling the Advantages of Agile Software Development.pdf
Unveiling the Advantages of Agile Software Development.pdf
 

EWD 3 Training Course Part 44: Creating MicroServices with QEWD.js

  • 1. Copyright © 2016 M/Gateway Developments Ltd EWD 3 Training Course Part 44 Creating MicroServices with QEWD.js Rob Tweed Director, M/Gateway Developments Ltd Twitter: @rtweed
  • 2. 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
  • 3. 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
  • 4. Copyright © 2016 M/Gateway Developments Ltd QEWD MicroService Fabric ewd-qoper8 queue Express Node.js socket.io Cache GT.M, YottaDB Redis Node.js Worker Process Cache GT.M, YottaDB Redis Node.js Worker Process Cache GT.M, YottaDB Redis Node.js Worker Process ewd-qoper8 queue Express Node.js socket.io Cache GT.M, YottaDB Redis Node.js Worker Process Cache GT.M, YottaDB Redis Node.js Worker Process Cache GT.M, YottaDB Redis Node.js Worker Process ewd-qoper8 queue Express Node.js socket.io Cache GT.M, YottaDB Redis Node.js Worker Process Cache GT.M, YottaDB Redis Node.js Worker Process Cache GT.M, YottaDB Redis Node.js Worker Process User authentication Demographics Pharmacy ewd-qoper8 queue Express Node.js socket.io Cache GT.M, YottaDB Redis Node.js Worker Process Cache GT.M, YottaDB Redis Node.js Worker Process Cache GT.M, YottaDB Redis Node.js Worker Process Client Orchestration HTTPS WebSocket Connections
  • 5. Copyright © 2016 M/Gateway Developments Ltd QEWD.js Solution ewd-qoper8 queue Express Node.js socket.io Equivalent to ewd-client socket.io-client Incoming REST request
  • 6. Copyright © 2016 M/Gateway Developments Ltd QEWD.js Solution ewd-qoper8 queue Express Node.js socket.io Equivalent to ewd-client socket.io-client Incoming WebSocket request
  • 7. Copyright © 2016 M/Gateway Developments Ltd QEWD.js Solution ewd-qoper8 queue Express Node.js socket.io Equivalent to ewd-client socket.io-client Incoming WebSocket request Process Locally?
  • 8. Copyright © 2016 M/Gateway Developments Ltd QEWD.js Solution ewd-qoper8 queue Express Node.js socket.io Equivalent to ewd-client socket.io-client Incoming WebSocket request Handled by remote MicroService?
  • 9. Copyright © 2016 M/Gateway Developments Ltd QEWD.js Solution ewd-qoper8 queue Express Node.js socket.io Persistent Bi-directional WebSocket connection Secured over HTTPS ewd-qoper8 queue Express Node.js socket.io Equivalent to ewd-client socket.io-client Remote QEWD MicroService
  • 10. 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
  • 11. 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
  • 12. 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
  • 13. 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
  • 14. Copyright © 2016 M/Gateway Developments Ltd Let's Get Started!
  • 15. 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
  • 16. Copyright © 2016 M/Gateway Developments Ltd QEWD MicroService Fabric ewd-qoper8 queue Express Node.js socket.io Cache GT.M, YottaDB Redis Node.js Worker Process Cache GT.M, YottaDB Redis Node.js Worker Process Cache GT.M, YottaDB Redis Node.js Worker Process User authentication ewd-qoper8 queue Express Node.js socket.io Cache GT.M, YottaDB Redis Node.js Worker Process Cache GT.M, YottaDB Redis Node.js Worker Process Cache GT.M, YottaDB Redis Node.js Worker Process Client Primary Server HTTPS WebSocket Connections Login MicroService Server
  • 17. Copyright © 2016 M/Gateway Developments Ltd Configuring the Primary Server
  • 18. Copyright © 2016 M/Gateway Developments Ltd Startup file from Part 43 var 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);
  • 19. Copyright © 2016 M/Gateway Developments Ltd Add the MicroService Definition var 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);
  • 20. Copyright © 2016 M/Gateway Developments Ltd Add the MicroService Definition var 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
  • 21. Copyright © 2016 M/Gateway Developments Ltd Add the MicroService Definition jwt: { secret: 'someSecret123' }, u_services: { destinations: { login_service: { host: 'http://192.168.1.114:8080', application: 'login-micro-service' } }, routes: [] } };
  • 22. Copyright © 2016 M/Gateway Developments Ltd Add the MicroService Definition jwt: { 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)
  • 23. Copyright © 2016 M/Gateway Developments Ltd Add the MicroService Definition jwt: { 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
  • 24. Copyright © 2016 M/Gateway Developments Ltd Add the MicroService Definition jwt: { 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)
  • 25. Copyright © 2016 M/Gateway Developments Ltd Add the MicroService Definition 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' } ] } };
  • 26. Copyright © 2016 M/Gateway Developments Ltd Add the MicroService Definition 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' } ] } Each Route is defined by an array element
  • 27. Copyright © 2016 M/Gateway Developments Ltd Add the MicroService Definition 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' } ] } Each Route is defined by: - A URL path (which can be templated)
  • 28. Copyright © 2016 M/Gateway Developments Ltd Add the MicroService Definition 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' } ] } Each Route is defined by: -optionally, an HTTP method If not specified, the route will apply to all HTTP methods for the path
  • 29. Copyright © 2016 M/Gateway Developments Ltd Add the MicroService Definition 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' } ] } Each Route is defined by: -the MicroService destination to which the request will be routed
  • 30. Copyright © 2016 M/Gateway Developments Ltd Add the MicroService Definition 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' } ] } Each Route is defined by: -the MicroService destination to which the request will be routed
  • 31. 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'} ];
  • 32. 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'} ];
  • 33. Copyright © 2016 M/Gateway Developments Ltd Add the MicroService Definition 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' } ] } You can define as many Routes and Destinations as you like
  • 34. Copyright © 2016 M/Gateway Developments Ltd Add the MicroService Definition u_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 different physical endpoints
  • 35. Copyright © 2016 M/Gateway Developments Ltd Add the MicroService Definition u_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 appear in more than one Destination
  • 36. Copyright © 2016 M/Gateway Developments Ltd Add the MicroService Definition u_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 appear in more than one Destination In which case the application will be different
  • 37. Copyright © 2016 M/Gateway Developments Ltd Add the MicroService Definition u_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
  • 38. Copyright © 2016 M/Gateway Developments Ltd Add the MicroService Definition 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' }, { path: '/api/userinfo', method: 'GET', destination: 'login_service' } ] } Each Route can use different Destinations or the same ones
  • 39. Copyright © 2016 M/Gateway Developments Ltd Our Example MicroService Definition 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' } ] } }; In our example we'll just define a single Destination and Route POST requests for /api/login will be routed to the MicroService QEWD system at 192.168.1.114:8080, where they will be handled by the login-micro-service application
  • 40. Copyright © 2016 M/Gateway Developments Ltd Our Example MicroService Definition var 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 the login_service host property to match the server you'll be using
  • 41. Copyright © 2016 M/Gateway Developments Ltd Next we'll configure the MicroService System
  • 42. 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…
  • 43. Copyright © 2016 M/Gateway Developments Ltd Startup file from Part 43 var 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);
  • 44. Copyright © 2016 M/Gateway Developments Ltd MicroService Startup file var 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 same JWT Secret
  • 45. Copyright © 2016 M/Gateway Developments Ltd MicroService Startup file var 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 QEWD system will be handling forwarded requests for /api/login
  • 46. Copyright © 2016 M/Gateway Developments Ltd MicroService Startup file var 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 primary QEWD system will re-format the /api/login REST requests to a WebSocket message
  • 47. Copyright © 2016 M/Gateway Developments Ltd MicroService Startup file var 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 primary QEWD system will re-format the /api/login REST requests to a WebSocket message These messages will be handled by the login_micro-service application on this QEWD system
  • 48. Copyright © 2016 M/Gateway Developments Ltd MicroService Startup file var 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
  • 49. 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
  • 50. Copyright © 2016 M/Gateway Developments Ltd Start Up the Two QEWD Systems On the primary QEWD machine: cd ~/qewd node ms-startup
  • 51. Copyright © 2016 M/Gateway Developments Ltd Look at the QEWD Node Console Log rtweed@ubuntu:~/qewd$ node microservices Setting up micro-service connections Adding MicroService Client connection: url = http://192.168.1.114:8080; application = login-micro-service starting microService connection to http://192.168.1.114:8080 webServerRootPath = /home/rtweed/qewd/www/ route /api will be handled by qx.router
  • 52. Copyright © 2016 M/Gateway Developments Ltd Look at the QEWD Node Console Log rtweed@ubuntu:~/qewd$ node microservices Setting up micro-service connections Adding MicroService Client connection: url = http://192.168.1.114:8080; application = login-micro-service starting microService connection to http://192.168.1.114:8080 webServerRootPath = /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 MicroService machine on 192.168.1.114:8080 Which, of course, hasn't been started yet
  • 53. Copyright © 2016 M/Gateway Developments Ltd Start Up the Two QEWD Systems On the QEWD Login MicroService machine: cd ~/qewd node loginservice
  • 54. Copyright © 2016 M/Gateway Developments Ltd Look at the QEWD Node Console Log on the MicroService machine rtweed@ubuntu:~/qewd$ node loginService webServerRootPath = /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":"L7OwOn Siqhr-nAmdAAAA","ipAddress":"::ffff:192.168.1.119"} no available workers sent qoper8-start message to 30140 process.argv[2] = qewd.worker workerModule: qewd; worker Session Garbage Collector has started in worker 30140 Tue, 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 again 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.eyJleHAiOjE1MDMzOTU1NjYsImlhdCI6MTUwMzM5NTI2Niwia XNzIjoicWV3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ0aW1lb3V0IjozMDAsInFld2QiOiJmZTc0 U5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.DsDntCU3x2w21K3vmK3iaJd1kOhIj_Rl9h1 0469qXu4"}} *** handleMessage response {"type":"ewd-register","finished":true,"message":{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e hOTE0OGQ4Nzg1N2ZiZWM5Nzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdjZDUyMjE4ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM 0NWNhZjljYjgwMjM2ZjM0M2Q0OWIwMmE4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.D sDntCU3x2w21K3vmK3iaJd1kOhIj_Rl9h10469qXu4"}} Response time: 313ms
  • 55. Copyright © 2016 M/Gateway Developments Ltd Look at the QEWD Node Console Log on the MicroService machine rtweed@ubuntu:~/qewd$ node loginService webServerRootPath = /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":"L7OwOn Siqhr-nAmdAAAA","ipAddress":"::ffff:192.168.1.119"} no available workers sent qoper8-start message to 30140 process.argv[2] = qewd.worker workerModule: qewd; worker Session Garbage Collector has started in worker 30140 Tue, 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 again 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.eyJleHAiOjE1MDMzOTU1NjYsImlhdCI6MTUwMzM5NTI2Niwia XNzIjoicWV3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ0aW1lb3V0IjozMDAsInFld2QiOiJmZTc0 U5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.DsDntCU3x2w21K3vmK3iaJd1kOhIj_Rl9h1 0469qXu4"}} *** handleMessage response {"type":"ewd-register","finished":true,"message":{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e hOTE0OGQ4Nzg1N2ZiZWM5Nzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdjZDUyMjE4ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM 0NWNhZjljYjgwMjM2ZjM0M2Q0OWIwMmE4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.D sDntCU3x2w21K3vmK3iaJd1kOhIj_Rl9h10469qXu4"}} Response time: 313ms QEWD has fully started
  • 56. 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":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUz I1NiJ9.eyJleHAiOjE1MDMzOTU1NjYsImlhdCI6MTUwMzM5NTI2NiwiaXNzIjoicWV3ZC5qd3Q iLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ0aW1lb3V0IjozMDAsInFld2Q iOiJmZTc0NjBhM2ZjOGFmMWY5YjhlMWY1MWQ2M2FmYjQ3YTU5M2JkZDczYjNhOTE0OG Q4Nzg1N2ZiZWM5Nzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdjZDUyMjE4ZjA1MTcxNGUxMT ViNGJhMjU2OGEzNjQyZGM0NWNhZjljYjgwMjM2ZjM0M2Q0OWIwMmE4MzU5ZTZhNDRjNG ZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.DsDntCU3x2w21K3vmK3iaJ d1kOhIj_Rl9h10469qXu4"}} *** handleMessage response {"type":"ewd-register","finished":true,"message":{"token":"eyJ0e XAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDMzOTU1NjYsImlhdCI6MTUwMzM5NTI 2NiwiaXNzIjoicWV3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ 0aW1lb3V0IjozMDAsInFld2QiOiJmZTc0NjBhM2ZjOGFmMWY5YjhlMWY1MWQ2M2FmYjQ3Y TU5M2JkZDczYjNhOTE0OGQ4Nzg1N2ZiZWM5Nzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdj ZDUyMjE4ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM0NWNhZjljYjgwMjM2ZjM0M2Q0O WIwMmE4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3I n0.DsDntCU3x2w21K3vmK3iaJd1kOhIj_Rl9h10469qXu4"}} Response time: 313ms
  • 57. 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
  • 58. Copyright © 2016 M/Gateway Developments Ltd Now look at the Primary QEWD Machine's Console Log rtweed@ubuntu:~/qewd$ node microservices Setting up micro-service connections Adding MicroService Client connection: url = http://192.168.1.114:8080; application = login-micro-service starting microService connection to http://192.168.1.114:8080 webServerRootPath = /home/rtweed/qewd/www/ route /api will be handled by qx.router login-micro-service registered http://192.168.1.114:8080 micro-service ready 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 ======================================================== Connection was established to the Login MicroService QEWD system, and the login-micro-service application was registered
  • 59. Copyright © 2016 M/Gateway Developments Ltd Now look at the Primary QEWD Machine's Console Log rtweed@ubuntu:~/qewd$ node microservices Setting up micro-service connections Adding MicroService Client connection: url = http://192.168.1.114:8080; application = login-micro-service starting microService connection to http://192.168.1.114:8080 webServerRootPath = /home/rtweed/qewd/www/ route /api will be handled by qx.router login-micro-service registered http://192.168.1.114:8080 micro-service ready 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 ======================================================== So QEWD has now fully started Both QEWD systems are ready!
  • 60. 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
  • 61. 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
  • 62. 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
  • 63. Copyright © 2016 M/Gateway Developments Ltd Try POST /api/login
  • 64. Copyright © 2016 M/Gateway Developments Ltd Try POST /api/login Not surprising – we haven't yet written a handler For the login-micro-service application to handle This request on the MicroService machine…..but...
  • 65. Copyright © 2016 M/Gateway Developments Ltd Look at the Console Log for both machines • You'll see that they both burst into life
  • 66. 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":"eyJ 0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDMzOTk1NzMsImlhdCI6MTUwMz M5OTI3MywiaXNzIjoicWV3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcn ZpY2UiLCJ0aW1lb3V0IjozMDAsInFld2QiOiJmZTc0NjBhM2ZjOGFmMWY5YjhlMWY1MW Q2MzhlZWM1OTZiMmJlYzU1YTI5MTRlODljNThmNTE4YTgwNzk2YTc4MmYwYmRmMm Y0MjFlZTZjNTdjZDUyMjE4ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM0NWNhZjljYj gwMjM2ZjM0M2Q0OWIwMmE4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZ jc4MzEyODhlZGJkOTE3In0.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"}
  • 67. Copyright © 2016 M/Gateway Developments Ltd Login MicroService Machine Tue, 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":"eyJ0eXAiOiJKV1QiLCJhbGci OiJIUzI1NiJ9.eyJleHAiOjE1MDMzOTk1NzMsImlhdCI6MTUwMzM5OTI3MywiaXNzIjoicWV 3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ0aW1lb3V0Ijoz MDAsInFld2QiOiJmZTc0NjBhM2ZjOGFmMWY5YjhlMWY1MWQ2MzhlZWM1OTZiMmJlYz U1YTI5MTRlODljNThmNTE4YTgwNzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdjZDUyMjE4 ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM0NWNhZjljYjgwMjM2ZjM0M2Q0OWIwMm E4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.R e4a6cEmIzQ9PFhwwYsoQ-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"}}}
  • 68. Copyright © 2016 M/Gateway Developments Ltd Login MicroService Machine Tue, 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":"eyJ0eXAiOiJKV1QiLCJhbGci OiJIUzI1NiJ9.eyJleHAiOjE1MDMzOTk1NzMsImlhdCI6MTUwMzM5OTI3MywiaXNzIjoicWV 3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ0aW1lb3V0Ijoz MDAsInFld2QiOiJmZTc0NjBhM2ZjOGFmMWY5YjhlMWY1MWQ2MzhlZWM1OTZiMmJlYz U1YTI5MTRlODljNThmNTE4YTgwNzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdjZDUyMjE4 ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM0NWNhZjljYjgwMjM2ZjM0M2Q0OWIwMm E4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.R e4a6cEmIzQ9PFhwwYsoQ-UtMBKHkTPSpAk55FCDyV8","args":{},"jwt":true}
  • 69. Copyright © 2016 M/Gateway Developments Ltd Login MicroService Machine Tue, 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":"eyJ0eXAiOiJKV1QiLCJhbGci OiJIUzI1NiJ9.eyJleHAiOjE1MDMzOTk1NzMsImlhdCI6MTUwMzM5OTI3MywiaXNzIjoicWV 3ZC5qd3QiLCJhcHBsaWNhdGlvbiI6ImxvZ2luLW1pY3JvLXNlcnZpY2UiLCJ0aW1lb3V0Ijoz MDAsInFld2QiOiJmZTc0NjBhM2ZjOGFmMWY5YjhlMWY1MWQ2MzhlZWM1OTZiMmJlYz U1YTI5MTRlODljNThmNTE4YTgwNzk2YTc4MmYwYmRmMmY0MjFlZTZjNTdjZDUyMjE4 ZjA1MTcxNGUxMTViNGJhMjU2OGEzNjQyZGM0NWNhZjljYjgwMjM2ZjM0M2Q0OWIwMm E4MzU5ZTZhNDRjNGZlNTYyZTM2NGE0ZjJjOTBmOGRjZjc4MzEyODhlZGJkOTE3In0.R e4a6cEmIzQ9PFhwwYsoQ-UtMBKHkTPSpAk55FCDyV8","args":{},"jwt":true}
  • 70. 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 }
  • 71. Copyright © 2016 M/Gateway Developments Ltd Login MicroService Machine Unable to load handler module for: login-micro-service: Error: Cannot find module 'login-micro-service'
  • 72. Copyright © 2016 M/Gateway Developments Ltd Login MicroService Machine 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"}}}
  • 73. 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
  • 74. 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
  • 75. 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 }
  • 76. 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
  • 77. Copyright © 2016 M/Gateway Developments Ltd Login Handler Module var router = require('qewd-router'); var routes; module.exports = { init: function() { routes = { '/api/login': { POST: login } }; router.addMicroServiceHandler(routes, module.exports); } };
  • 78. Copyright © 2016 M/Gateway Developments Ltd Login Handler Module var router = require('qewd-router'); var routes; module.exports = { init: function() { routes = { '/api/login': { POST: login } }; router.addMicroServiceHandler(routes, module.exports); } }; First we need to define an init() function in which we'll define our URL routes
  • 79. Copyright © 2016 M/Gateway Developments Ltd Login Handler Module var 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 routes we want to handle. We only have one: POST /api/login
  • 80. Copyright © 2016 M/Gateway Developments Ltd Login Handler Module var 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 routes we want to handle. We only have one: POST /api/login And it will invoke a handler function named login() (which we haven't yet written)
  • 81. Copyright © 2016 M/Gateway Developments Ltd Login Handler Module var 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 the handler function stubs for us within the module
  • 82. Copyright © 2016 M/Gateway Developments Ltd Login Handler Module var 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
  • 83. Copyright © 2016 M/Gateway Developments Ltd Login Handler Module var 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 interface that you use for standard REST route handling The addMicroServiceHandler() API normalises the interface for you
  • 84. Copyright © 2016 M/Gateway Developments Ltd Login Handler Module var 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 interface that you use for standard REST route handling args is an object containing: -req: incoming request object -session: the JWT payload
  • 85. Copyright © 2016 M/Gateway Developments Ltd Login Handler Module var 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 interface that you use for standard REST route handling -finished is the function for returning the response and releasing the worker process
  • 86. 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 credentials will be in the message body object
  • 87. Copyright © 2016 M/Gateway Developments Ltd Login Handler Module function 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 the valid credentials for simplicity in this example
  • 88. Copyright © 2016 M/Gateway Developments Ltd Login Handler Module 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; // return success response } else { // invalid login – return an error } } Update the session object With our own data
  • 89. Copyright © 2016 M/Gateway Developments Ltd Login Handler Module 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; // return success response } else { // invalid login – return an error } } These are reserved session properties authenticated helps determine that the user was properly logged in timeout determines the JWT timeout each time QEWD updates it
  • 90. Copyright © 2016 M/Gateway Developments Ltd Login Handler Module 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 success response } else { // invalid login – return an error } } Make these two session properties secret. QEWD will encrypt them within the JWT so they aren't accesible or usable by the client. They will be available, however, for your back-end handler functions
  • 91. Copyright © 2016 M/Gateway Developments Ltd Login Handler Module 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'); finished({ok: true}); } else { // invalid login – return an error } } Return a success response object and release the worker process
  • 92. Copyright © 2016 M/Gateway Developments Ltd Login Handler Module 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'); finished({ok: true}); } else { return finished({error: 'Invalid login'}); } } Return an error response object and release the worker process
  • 93. Copyright © 2016 M/Gateway Developments Ltd Save the Login Handler Module var 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
  • 94. Copyright © 2016 M/Gateway Developments Ltd Restart the QEWD on the Login machine and re-try POST /api/login Now it works!
  • 95. 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
  • 96. Copyright © 2016 M/Gateway Developments Ltd Let's decode that JWT
  • 97. Copyright © 2016 M/Gateway Developments Ltd Let's decode that JWT Here are the non-secret properties we set in the login() function
  • 98. Copyright © 2016 M/Gateway Developments Ltd Let's decode that JWT The secret ones are encrypted into this claim
  • 99. 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
  • 100. Copyright © 2016 M/Gateway Developments Ltd Try an invalid POST /api/login request There's the error message We created in the login() function
  • 101. Copyright © 2016 M/Gateway Developments Ltd Try an invalid POST /api/login request Note that when an error is reported, the JWT is not updated
  • 102. Copyright © 2016 M/Gateway Developments Ltd We now have a working MicroService!
  • 103. 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
  • 104. 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 } } } ];
  • 105. 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 will be handled locally by the myRestService Worker process Handler module
  • 106. 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 the handler module to myLocalServices, to avoid confusion
  • 107. Copyright © 2016 M/Gateway Developments Ltd Create a new Handler Module On 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) { } };
  • 108. Copyright © 2016 M/Gateway Developments Ltd Create a new Handler Module var 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 by a function named info()
  • 109. Copyright © 2016 M/Gateway Developments Ltd Create a new Handler Module var 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 the Handler function stubs Automatically within the module
  • 110. Copyright © 2016 M/Gateway Developments Ltd Create a new Handler Module var 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() function will be invoked for every incoming /api request We'll use this to confirm that the user has logged in before allowing the incoming request to be handled
  • 111. 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 get called. Any other return value (including undefined) will allow the route-specific handler to run
  • 112. 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 the beforeHandler() function
  • 113. 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 and decrypt the incoming JWT in the request's Authorization header All incoming requests will now need to have a Valid JWT, otherwise they'll be rejected
  • 114. 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 process and 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
  • 115. 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 process and 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 payload to the request as a Session object, and allows the route-specific handler to be invoked
  • 116. Copyright © 2016 M/Gateway Developments Ltd Create a new Handler Module var 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
  • 117. 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
  • 118. 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 function runs, 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
  • 119. 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 by the Login MicroService. However, our handler function can access it because this server has the same JWT Secret
  • 120. 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 displayed in the Node.js Console log
  • 121. 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 from the updated Session contents This will also update the JWT's expiry time
  • 122. 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 in The JWT)
  • 123. 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 return the updated JWT The Worker process will then be released
  • 124. 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
  • 125. Copyright © 2016 M/Gateway Developments Ltd Restart the Primary QEWD System and Try the GET /api/info request
  • 126. Copyright © 2016 M/Gateway Developments Ltd Add an invalid Authorization Header
  • 127. Copyright © 2016 M/Gateway Developments Ltd Add an invalid JWT
  • 128. Copyright © 2016 M/Gateway Developments Ltd Now Login using the Login MicroService Note: Make sure you remove the Authorization Header!
  • 129. Copyright © 2016 M/Gateway Developments Ltd Successful Login
  • 130. Copyright © 2016 M/Gateway Developments Ltd Paste the JWT into the Authorization Header and try GET /api/info request again
  • 131. Copyright © 2016 M/Gateway Developments Ltd Success!
  • 132. 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
  • 133. 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
  • 134. 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
  • 135. 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
  • 136. 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: – Dynamic path-defined destinations – Federated composite MicroServices from a group of destinations – Re-direction of MicroService responses to another MicroService – Chained MicroServices