From 5e03e16c09ba2c8f5b119c9534dc78390a299d1f Mon Sep 17 00:00:00 2001 From: Manuel Rauber Date: Wed, 17 Feb 2016 21:13:11 +0100 Subject: [PATCH 1/6] Removed the comments, which could disturb during live-coding --- src/nodejs/STS/server/index.js | 33 ----------- src/nodejs/STS/server/oAuthModel.js | 37 ------------ src/nodejs/WebAPI/controllers/customer.js | 56 ------------------- src/nodejs/WebAPI/database/customerModel.js | 20 ------- src/nodejs/WebAPI/database/index.js | 1 - src/nodejs/WebAPI/index.js | 1 - src/nodejs/WebAPI/server/index.js | 40 ------------- .../WebAPI/server/referenceTokenValidation.js | 15 ----- .../WebAPI/service/customer.database.js | 15 ----- .../WebAPI/service/customer.inmemory.js | 22 -------- 10 files changed, 240 deletions(-) diff --git a/src/nodejs/STS/server/index.js b/src/nodejs/STS/server/index.js index cd823c8..a93f722 100644 --- a/src/nodejs/STS/server/index.js +++ b/src/nodejs/STS/server/index.js @@ -1,18 +1,10 @@ 'use strict'; -// Require express, another hosting platform for Node.js const express = require('express'), - // Require the body-parser for express - bodyParser = require('body-parser'), - - // Require a oauth2-server for node.js oAuthServer = require('oauth2-server'), - - // Require the cors middleware for express cors = require('cors'); -// Require a oAuthModel which is used by the oauth2-server const oAuthModel = require('./oAuthModel'); /** @@ -22,54 +14,29 @@ const oAuthModel = require('./oAuthModel'); function Server() { let app; - /** - * Starts the STS server on the given port - * @param {number} port - The port where to start the server - */ this.start = port => { - // Create a new express instance app = express(); - // Enable cors app.use(cors()); - - // Add the urlencoded parser middleware for express: https://github.com/expressjs/body-parser#bodyparserurlencodedoptions app.use(bodyParser.urlencoded({ extended: true })); - - // Add the json parser middleware for express: https://github.com/expressjs/body-parser#bodyparserjsonoptions app.use(bodyParser.json()); - - // Create a new oAuthServer app.oAuth = oAuthServer({ - // Using our own oAuthModel model: oAuthModel, - - // Allow the password grant only for resource owner flow grants: ['password'] }); - - // Add the HTTP POST route /connect/token to get tokens using oAuthServer app.post('/connect/token', app.oAuth.grant()); - - // Add a custom HTTP POST route /connect/accesstokenvalidation to validate our tokens app.get('/connect/accesstokenvalidation', validateAccessToken); - - // Add the errorHandler middleware for express app.use(app.oAuth.errorHandler()); - // Start the server on the given port app.listen(port, () => console.log(`STS is up and running on port ${port}.`)); }; - // Method for validation access tokens function validateAccessToken(req, res) { if (!req.query.token) { return res.status(400).send('token is missing'); } - // simply validate by checking if a token is saved in our oAuthModel - // Should get some more validation for expiry etc. app.oAuth.model.getAccessToken(req.query.token, function (err) { if (err) { return res.status(400).send(err); diff --git a/src/nodejs/STS/server/oAuthModel.js b/src/nodejs/STS/server/oAuthModel.js index eb3db4b..730ddc1 100644 --- a/src/nodejs/STS/server/oAuthModel.js +++ b/src/nodejs/STS/server/oAuthModel.js @@ -7,36 +7,18 @@ function OAuthModel() { const internalTokenStorage = {}; - // Sample client as configured in vNext, too const sampleClient = { clientId: 'sample-client', clientSecret: 'sample-secret' }; - // See here for needed method implementations: https://github.com/thomseddon/node-oauth2-server - - /** - * Returns a client. In this sample there is only one valid client - * @param {string} clientId - * @param {string} clientSecret - * @param {function} callback - */ this.getClient = (clientId, clientSecret, callback) => { - // This is a point, where clients can be loaded from a database callback(null, { clientId: sampleClient.clientId, clientSecret: sampleClient.clientSecret }); }; - /** - * Saves the access token to an internal storage object - * @param {string} accessToken - * @param {string} clientId - * @param {number} expires - * @param {string} user - * @param {function} callback - */ this.saveAccessToken = (accessToken, clientId, expires, user, callback) => { internalTokenStorage[accessToken] = { accessToken: accessToken, @@ -48,21 +30,10 @@ function OAuthModel() { callback(); }; - /** - * Checks if the grant type is allowed. For our sample, it must be password and the clientId must be sample-client - * @param {string} clientId - * @param {string} grantType - * @param {function} callback - */ this.grantTypeAllowed = (clientId, grantType, callback) => { callback(null, grantType === 'password' && clientId === sampleClient.clientId); }; - /** - * Tries to return an access token which has been saved previously by saveAccessToken method - * @param {string} bearerToken - * @param {function} callback - */ this.getAccessToken = (bearerToken, callback) => { const token = internalTokenStorage[bearerToken]; @@ -78,15 +49,7 @@ function OAuthModel() { }); }; - /** - * Authorizes a user. For our sample, only username bob with password bob is valid - * - * @param {string} username - * @param {string} password - * @param {function} callback - */ this.getUser = (username, password, callback) => { - // This is the point, where a database could be queried for user and check their password if (username === 'bob' && password === 'bob') { return callback(null, { id: 'bob' diff --git a/src/nodejs/WebAPI/controllers/customer.js b/src/nodejs/WebAPI/controllers/customer.js index 63f66f9..b9dbccd 100644 --- a/src/nodejs/WebAPI/controllers/customer.js +++ b/src/nodejs/WebAPI/controllers/customer.js @@ -1,6 +1,5 @@ 'use strict'; -// Require the services const services = require('../service'); /** @@ -9,57 +8,21 @@ const services = require('../service'); */ function CustomerController() { this.initialize = function (server) { - // Define a HTTP GET route which will execute "handleCustomerList" server.get('api/customer/list', handleCustomerList); - - // Define a HTTP POST route server.post('api/customer', handleCustomerCreation); - - // Define a HTTP DELETE route server.del('api/customer/:id', handleCustomerDeletion); }; - /** - * @swagger - * path: /api/customer/list - * httpMethod: GET - * spec: - * tags: - * - Customer - * summary: This method returns the customer list - * responses: - * 200: - * description: Successful response - * schema: - * '$ref': '#/definitions/CustomerModel' - */ function handleCustomerList(req, res) { - // Call list method of the customer service services.get() .then(srv => srv.customer.list()) .then( - // Successful handler: Return a json customers => res.json(200, customers), - - // Error handler: Send a HTTP status code 500 together with the error err => res.json(500, err) ); } - /** - * @swagger - * path: /api/customer - * httpMethod: POST - * spec: - * tags: - * - Customer - * summary: This methods creates a new customer - * responses: - * 200: - * description: Customer created - */ function handleCustomerCreation(req, res) { - // req.body contains the json object which was transmitted services.get() .then(srv => srv.customer.create(req.body.firstName, req.body.lastName)) .then( @@ -68,26 +31,7 @@ function CustomerController() { ); } - /** - * @swagger - * path: /api/customer/{id} - * httpMethod: DELETE - * spec: - * tags: - * - Customer - * summary: This methods removes a customer - * parameters: - * - name: id - * in: path - * description: The id of the user to remove - * required: true - * type: integer - * responses: - * 200: - * description: Customer removed - */ function handleCustomerDeletion(req, res) { - // req.params contains the url parameters defined in the route (:id) services.get() .then(srv => srv.customer.remove(req.params.id)) .then( diff --git a/src/nodejs/WebAPI/database/customerModel.js b/src/nodejs/WebAPI/database/customerModel.js index afce842..4920ae6 100644 --- a/src/nodejs/WebAPI/database/customerModel.js +++ b/src/nodejs/WebAPI/database/customerModel.js @@ -17,23 +17,3 @@ module.exports = function (sequelize, DataTypes) { } }); }; - -/** - * @swagger - * definitions: - * CustomerModel: - * required: - * - id - * - firstName - * - lastName - * properties: - * id: - * type: integer - * description: A unique identifier - * firstName: - * type: string - * description: The first name of the given customer - * lastName: - * type: string - * description: The last name of the given customer - */ diff --git a/src/nodejs/WebAPI/database/index.js b/src/nodejs/WebAPI/database/index.js index b90e5ed..f3c0922 100644 --- a/src/nodejs/WebAPI/database/index.js +++ b/src/nodejs/WebAPI/database/index.js @@ -38,7 +38,6 @@ function Database() { let database; -// Using a provider pattern for db configuration and initialization module.exports = { configure: (connectionString) => { config = { diff --git a/src/nodejs/WebAPI/index.js b/src/nodejs/WebAPI/index.js index bfae5f0..51bc7e4 100644 --- a/src/nodejs/WebAPI/index.js +++ b/src/nodejs/WebAPI/index.js @@ -1,6 +1,5 @@ 'use strict'; -// Require the server, create a new instance and start it on port 8080 const Server = require('./server'); const server = new Server(); server.start(5000); diff --git a/src/nodejs/WebAPI/server/index.js b/src/nodejs/WebAPI/server/index.js index 7e67aac..6ec2dfc 100644 --- a/src/nodejs/WebAPI/server/index.js +++ b/src/nodejs/WebAPI/server/index.js @@ -1,77 +1,39 @@ 'use strict'; -// Require the restify npm module const restify = require('restify'), - -// Require the cors middleware for restify corsMiddleware = require('restify-cors-middleware'), - -// Require swagger to build an API documentation swagger = require('swagger-restify'), - -// Require node.js' path module path = require('path'); -// Require the services const services = require('../service'), - -// Require the controllers controllers = require('../controllers'), - -// Require the reference token validation service referenceTokenValidation = require('./referenceTokenValidation'), - -// Require the database to configure it database = require('../database'); /** - * Restify server exposing some APIs to manipulate customer data - * * @public * @constructor */ function Server() { - /** - * Starts the server on the given port - * @param {number} port - The port where the server should listen on - */ this.start = port => { - // Create a new restify server const server = restify.createServer(); - // Enable cors for restify const cors = corsMiddleware({ allowHeaders: ['Authorization'] }); initializeSwagger(server, port); - // server.pre runs before other server.use middlewares. It will run before all http requests, so we can handle CORS preflights server.pre(cors.preflight); - - // Validate all request for an valid token server.pre(referenceTokenValidation.validate()); - - // Allow cors on all routes server.use(cors.actual); - - // Include a query parser middleware which will expose all parsed query parameters on a special "req.params" object server.use(restify.queryParser()); - - // Include a body parser middleware which will parse the body to json objects (in case of application/json) - // Will parse other content types like application/form-data or application/x-www-form-urlencoded server.use(restify.bodyParser()); - // Initialize all controllers controllers.initialize(server); - - // Configure the database to use PostgreSQL database.configure('postgres://CustomerSample:CustomerSample@localhost:5432/CustomerSampleNodejs'); - - // Configure services to use database as backend storage services.configure(false); - // Start the server on the given port and output a console message, if it started successfully server.listen(port, () => { console.log(`Server is up and running on port ${port}`); }); @@ -92,7 +54,6 @@ function Server() { } }, host: `localhost:${port}`, - // Reference the files containing the swagger definitions apis: [ path.join(__dirname, '..', 'database', 'customerModel.js'), path.join(__dirname, '..', 'controllers', 'customer.js') @@ -106,5 +67,4 @@ function Server() { } } -// Expose the Server, so it can be used outside of this JavaScript file. Like a "public class Server..." module.exports = Server; diff --git a/src/nodejs/WebAPI/server/referenceTokenValidation.js b/src/nodejs/WebAPI/server/referenceTokenValidation.js index 502c618..83b27c3 100644 --- a/src/nodejs/WebAPI/server/referenceTokenValidation.js +++ b/src/nodejs/WebAPI/server/referenceTokenValidation.js @@ -4,52 +4,37 @@ const request = require('request'), restify = require('restify'); /** - * This class is used to validate the tokens which are sent to the Web API - * * @public * @constructor */ function ReferenceTokenValidation() { - // The Url where the Node STS is hosted. const authorityUrl = 'http://localhost:5001/'; - // Internal method for creating a 401 Not authorized http error function notAuthorized(res) { res.send(401, new Error('Not authorized')); } - /** - * Returns a restify middleware to validate tokens - * @returns {Function} - */ this.validate = () => { return (req, res, next) => { - // Don't authorise docs and swagger json if (req.url.indexOf('/docs') === 0 || req.url.indexOf('/swagger.json') === 0) { return next(); } - // Get the authorization header const authorizationHeader = req.header('authorization'); - // If not present, return 401 Not authorized if (!authorizationHeader) { notAuthorized(res); return next(); } - // Cut the 'Bearer' part, so we only have the token const token = authorizationHeader.substr(7); - // Call our STS to validate the token request(`${authorityUrl}connect/accesstokenvalidation?token=${token}`, (err, response) => { - // If it returns an error or the statusCode is not 200 OK, return a 401 Not authorized if (err || response.statusCode !== 200) { notAuthorized(res); return next(); } - // If everything is ok, go to the next middleware return next(); }); }; diff --git a/src/nodejs/WebAPI/service/customer.database.js b/src/nodejs/WebAPI/service/customer.database.js index b5afa17..fd2bf47 100644 --- a/src/nodejs/WebAPI/service/customer.database.js +++ b/src/nodejs/WebAPI/service/customer.database.js @@ -7,21 +7,11 @@ const database = require('../database'); * @constructor */ function CustomerService() { - /** - * Returns a list of customers - * @returns {Promise} - */ this.list = () => { return database.get() .then(db => db.models.customer.findAll()); }; - /** - * Creates a new customer - * @param {string} firstName - * @param {string} lastName - * @returns {Promise} - */ this.create = (firstName, lastName) => { return database.get() .then(db => db.models.customer.create({ @@ -30,11 +20,6 @@ function CustomerService() { })); }; - /** - * Removes a customer - * @param {number} id - * @returns {Promise} - */ this.remove = id => { return database.get() .then(db => db.models.customer.findById(id)) diff --git a/src/nodejs/WebAPI/service/customer.inmemory.js b/src/nodejs/WebAPI/service/customer.inmemory.js index 9e0521a..6ed75bf 100644 --- a/src/nodejs/WebAPI/service/customer.inmemory.js +++ b/src/nodejs/WebAPI/service/customer.inmemory.js @@ -1,28 +1,17 @@ 'use strict'; /** - * Customer service which uses an simple object to store and retrieve data. - * Provides a promise based method access. - * * @public * @constructor */ function Customer() { - // Internal counter for ids. "AutoInc" :-) let internalCounter = 0; - - // Internal storage object const internalStorage = {}; - /** - * Returns a list of customers - * @returns {Promise} - */ this.list = () => { return new Promise(resolve => { let result = []; - // Run through the object's keys and put all values into an array Object.keys(internalStorage).forEach(key => { result.push(internalStorage[key]); }); @@ -31,12 +20,6 @@ function Customer() { }); }; - /** - * Creates a new customer - * @param {string} firstName - * @param {string} lastName - * @returns {Promise} - */ this.create = (firstName, lastName) => { return new Promise(resolve => { internalCounter++; @@ -51,11 +34,6 @@ function Customer() { }); }; - /** - * Removes a customer - * @param {number} id - * @returns {Promise} - */ this.remove = id => { return new Promise((resolve, reject) => { if (internalStorage[id]) { From 9f81db34f438fce4cc6ba16bd651026c2ca1e5b0 Mon Sep 17 00:00:00 2001 From: Manuel Rauber Date: Wed, 17 Feb 2016 21:14:58 +0100 Subject: [PATCH 2/6] Removed web apis for customers. --- src/nodejs/WebAPI/controllers/customer.js | 30 ----------------------- 1 file changed, 30 deletions(-) diff --git a/src/nodejs/WebAPI/controllers/customer.js b/src/nodejs/WebAPI/controllers/customer.js index b9dbccd..5effd5c 100644 --- a/src/nodejs/WebAPI/controllers/customer.js +++ b/src/nodejs/WebAPI/controllers/customer.js @@ -8,37 +8,7 @@ const services = require('../service'); */ function CustomerController() { this.initialize = function (server) { - server.get('api/customer/list', handleCustomerList); - server.post('api/customer', handleCustomerCreation); - server.del('api/customer/:id', handleCustomerDeletion); }; - - function handleCustomerList(req, res) { - services.get() - .then(srv => srv.customer.list()) - .then( - customers => res.json(200, customers), - err => res.json(500, err) - ); - } - - function handleCustomerCreation(req, res) { - services.get() - .then(srv => srv.customer.create(req.body.firstName, req.body.lastName)) - .then( - () => res.send(200), - err => res.json(500, err) - ); - } - - function handleCustomerDeletion(req, res) { - services.get() - .then(srv => srv.customer.remove(req.params.id)) - .then( - () => res.send(200), - err => res.send(500, err) - ); - } } module.exports = new CustomerController(); From 85787221752bec9b47a4fa8a32099acfe8c9f6b5 Mon Sep 17 00:00:00 2001 From: Manuel Rauber Date: Wed, 17 Feb 2016 21:15:24 +0100 Subject: [PATCH 3/6] Removed sequelize model --- src/nodejs/WebAPI/database/customerModel.js | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/nodejs/WebAPI/database/customerModel.js b/src/nodejs/WebAPI/database/customerModel.js index 4920ae6..b8c1d8e 100644 --- a/src/nodejs/WebAPI/database/customerModel.js +++ b/src/nodejs/WebAPI/database/customerModel.js @@ -1,19 +1,5 @@ 'use strict'; module.exports = function (sequelize, DataTypes) { - return sequelize.define('customer', { - id: { - type: DataTypes.INTEGER, - autoIncrement: true, - primaryKey: true - }, - firstName: { - type: DataTypes.STRING, - allowNull: false - }, - lastName: { - type: DataTypes.STRING, - allowNull: false - } - }); + }; From 40306765f13f91e50de75f0eda26377a2a02f17f Mon Sep 17 00:00:00 2001 From: Manuel Rauber Date: Wed, 17 Feb 2016 21:16:19 +0100 Subject: [PATCH 4/6] Removed server.listen --- src/nodejs/WebAPI/server/index.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/nodejs/WebAPI/server/index.js b/src/nodejs/WebAPI/server/index.js index 6ec2dfc..4cc6727 100644 --- a/src/nodejs/WebAPI/server/index.js +++ b/src/nodejs/WebAPI/server/index.js @@ -33,10 +33,6 @@ function Server() { controllers.initialize(server); database.configure('postgres://CustomerSample:CustomerSample@localhost:5432/CustomerSampleNodejs'); services.configure(false); - - server.listen(port, () => { - console.log(`Server is up and running on port ${port}`); - }); }; function initializeSwagger(server, port) { From fa211527405f5205aac620577ea77603966d2c2e Mon Sep 17 00:00:00 2001 From: Manuel Rauber Date: Wed, 17 Feb 2016 21:17:30 +0100 Subject: [PATCH 5/6] Removed database create method --- src/nodejs/WebAPI/service/customer.database.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/nodejs/WebAPI/service/customer.database.js b/src/nodejs/WebAPI/service/customer.database.js index fd2bf47..281ddab 100644 --- a/src/nodejs/WebAPI/service/customer.database.js +++ b/src/nodejs/WebAPI/service/customer.database.js @@ -7,17 +7,13 @@ const database = require('../database'); * @constructor */ function CustomerService() { - this.list = () => { - return database.get() - .then(db => db.models.customer.findAll()); + this.create = (firstName, lastName) => { + }; - this.create = (firstName, lastName) => { + this.list = () => { return database.get() - .then(db => db.models.customer.create({ - firstName: firstName, - lastName: lastName - })); + .then(db => db.models.customer.findAll()); }; this.remove = id => { From 489f8310b93c1bc8abf7264545051f1d5ae21bcd Mon Sep 17 00:00:00 2001 From: Manuel Rauber Date: Wed, 2 Mar 2016 22:13:16 +0100 Subject: [PATCH 6/6] Added codeme hiints --- src/nodejs/WebAPI/controllers/customer.js | 1 + src/nodejs/WebAPI/database/customerModel.js | 2 +- src/nodejs/WebAPI/server/index.js | 2 ++ src/nodejs/WebAPI/service/customer.database.js | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/nodejs/WebAPI/controllers/customer.js b/src/nodejs/WebAPI/controllers/customer.js index 5effd5c..22a0926 100644 --- a/src/nodejs/WebAPI/controllers/customer.js +++ b/src/nodejs/WebAPI/controllers/customer.js @@ -8,6 +8,7 @@ const services = require('../service'); */ function CustomerController() { this.initialize = function (server) { + // TODO: Code me! }; } diff --git a/src/nodejs/WebAPI/database/customerModel.js b/src/nodejs/WebAPI/database/customerModel.js index b8c1d8e..6509659 100644 --- a/src/nodejs/WebAPI/database/customerModel.js +++ b/src/nodejs/WebAPI/database/customerModel.js @@ -1,5 +1,5 @@ 'use strict'; module.exports = function (sequelize, DataTypes) { - + // TODO: Code me! }; diff --git a/src/nodejs/WebAPI/server/index.js b/src/nodejs/WebAPI/server/index.js index 4cc6727..d638a93 100644 --- a/src/nodejs/WebAPI/server/index.js +++ b/src/nodejs/WebAPI/server/index.js @@ -33,6 +33,8 @@ function Server() { controllers.initialize(server); database.configure('postgres://CustomerSample:CustomerSample@localhost:5432/CustomerSampleNodejs'); services.configure(false); + + // TODO: Code me! }; function initializeSwagger(server, port) { diff --git a/src/nodejs/WebAPI/service/customer.database.js b/src/nodejs/WebAPI/service/customer.database.js index 281ddab..467899a 100644 --- a/src/nodejs/WebAPI/service/customer.database.js +++ b/src/nodejs/WebAPI/service/customer.database.js @@ -8,7 +8,7 @@ const database = require('../database'); */ function CustomerService() { this.create = (firstName, lastName) => { - + // TODO: Code me! }; this.list = () => {