diff --git a/lib/basic-controller-generator.js b/lib/basic-controller-generator.js new file mode 100644 index 0000000..6cc3941 --- /dev/null +++ b/lib/basic-controller-generator.js @@ -0,0 +1,66 @@ +'use strict'; + +const { decorate, metadata, param } = require('./helpers.js'); +const rest = require('@loopback/rest'); +const context = require('@loopback/context'); + +module.exports = function (specifications, operations) { + + const paths = Object.keys(specifications); + const controllerClasses = {}; + const decorationProperties = []; + + paths.forEach(path => { + const methods = Object.keys(specifications[path]); + methods.forEach(method => { + const decorationProperty = [path]; + const specs = specifications[path][method]; + const controllerName = specs['x-controller-name']; + const operationName = specs['x-operation-name']; + + if (!(controllerName in controllerClasses)) { + // Create the basic class + controllerClasses[controllerName] = class { + constructor(req) { + this.req = req; + } + } + } + + // Add the class methods dynamically + controllerClasses[controllerName].prototype[operationName] = operations[operationName]; + decorationProperty.push(method); + decorationProperty.push(operationName); + decorationProperties.push(decorationProperty); + }); + }); + + const controllerName = Object.keys(controllerClasses)[0]; + let ControllerClass = controllerClasses[controllerName]; + + Object.defineProperty(ControllerClass, 'name', { writable: true }); + ControllerClass.name = controllerName; + Object.defineProperty(ControllerClass, 'name', { writable: false }); + + decorationProperties.forEach(decorationProperty => { + const path = decorationProperty[0]; + const method = decorationProperty[1]; + const operation = decorationProperty[2]; + + decorate([ + rest[method](path, { + responses: specifications[path][method].responses + }), + metadata('design:type', Function), + metadata('design:paramtypes', []), + metadata('design:returntype', Object) + ], ControllerClass.prototype, operation, null); + }); + + ControllerClass = decorate([ + param(0, context.inject(rest.RestBindings.Http.REQUEST)), + metadata('design:paramtypes', [Object]) + ], ControllerClass); + + return ControllerClass; +}; diff --git a/server/controllers/ping.controller.js b/server/controllers/ping.controller.js index ba5965c..c70bf45 100644 --- a/server/controllers/ping.controller.js +++ b/server/controllers/ping.controller.js @@ -1,40 +1,29 @@ 'use strict'; -const { decorate, metadata, param } = require('../../lib/helpers.js'); -const rest = require("@loopback/rest"); -const context = require("@loopback/context"); +const generateBasicController = require('../../lib/basic-controller-generator.js'); -const PING_RESPONSE = { - description: 'Ping Response', - content: { - 'application/json': { - schema: { - type: 'object', - properties: { - greeting: { type: 'string' }, - date: { type: 'string' }, - url: { type: 'string' }, - headers: { - type: 'object', - properties: { - 'Content-Type': { type: 'string' }, - }, - additionalProperties: true, - }, - }, - }, - }, +const operations = { + ping: function ping() { + return { + greeting: 'Ping from LoopBack', + date: new Date(), + url: this.req.url, + headers: Object.assign({}, this.req.headers), + }; }, -}; -class PingController { - constructor(req) { - this.req = req; - } + pang: function pang() { + return { + greeting: 'Pang from LoopBack', + date: new Date(), + url: this.req.url, + headers: Object.assign({}, this.req.headers), + }; + }, - ping() { + pong: function pong() { return { - greeting: 'Hello from LoopBack', + greeting: 'Pong from LoopBack', date: new Date(), url: this.req.url, headers: Object.assign({}, this.req.headers), @@ -42,20 +31,119 @@ class PingController { } }; -decorate([ - rest.get('/ping', { - responses: { - '200': PING_RESPONSE, +const specifications = { + '/ping': { + 'get': { + 'x-controller-name': 'PingController', + 'x-operation-name': 'ping', + 'responses': { + '200': { + 'description': 'GET Ping Response', + 'content': { + 'application/json': { + 'schema': { + 'type': 'object', + 'properties': { + 'greeting': { + 'type': 'string' + }, + 'date': { + 'type': 'string' + }, + 'url': { + 'type': 'string' + }, + 'headers': { + 'type': 'object', + 'properties': { + 'Content-Type': { + 'type': 'string' + } + }, + 'additionalProperties': true + } + } + } + } + } + } + } }, - }), - metadata("design:type", Function), - metadata("design:paramtypes", []), - metadata("design:returntype", Object) -], PingController.prototype, "ping", null); - -PingController = decorate([ - param(0, context.inject(rest.RestBindings.Http.REQUEST)), - metadata("design:paramtypes", [Object]) -], PingController); + 'post': { + 'x-controller-name': 'PingController', + 'x-operation-name': 'pang', + 'responses': { + '200': { + 'description': 'POST Ping Response', + 'content': { + 'application/json': { + 'schema': { + 'type': 'object', + 'properties': { + 'greeting': { + 'type': 'string' + }, + 'date': { + 'type': 'string' + }, + 'url': { + 'type': 'string' + }, + 'headers': { + 'type': 'object', + 'properties': { + 'Content-Type': { + 'type': 'string' + } + }, + 'additionalProperties': true + } + } + } + } + } + } + } + } + }, + '/pong': { + 'get': { + 'x-controller-name': 'PingController', + 'x-operation-name': 'pong', + 'responses': { + '200': { + 'description': 'GET Ping Response', + 'content': { + 'application/json': { + 'schema': { + 'type': 'object', + 'properties': { + 'greeting': { + 'type': 'string' + }, + 'date': { + 'type': 'string' + }, + 'url': { + 'type': 'string' + }, + 'headers': { + 'type': 'object', + 'properties': { + 'Content-Type': { + 'type': 'string' + } + }, + 'additionalProperties': true + } + } + } + } + } + } + } + }, + } +} -exports.PingController = PingController; +exports.PingPongController = generateBasicController(specifications, operations);