From 827243409389291c0994b26e2437031abf4b507c Mon Sep 17 00:00:00 2001 From: Pedro Pereira Date: Mon, 4 Jun 2018 11:57:51 +0100 Subject: [PATCH 1/6] release: v1.0.2 --- CHANGELOG.md | 10 ++++++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9330062..879d535 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. + +## [1.0.2](https://github.com/ezypeeze/nuxt-neo/compare/v1.0.1...v1.0.2) (2018-06-04) + + +### Bug Fixes + +* arguments call of controllers tree functions in client side ([dc558b4](https://github.com/ezypeeze/nuxt-neo/commit/dc558b4)) + + + ## [1.0.1](https://github.com/ezypeeze/nuxt-neo/compare/v1.0.0...v1.0.1) (2018-05-28) ### Bug Fixes diff --git a/package-lock.json b/package-lock.json index 0ddb23a..feea467 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "nuxt-neo", - "version": "1.0.1", + "version": "1.0.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 50c25f8..a215fa0 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nuxt-neo", - "version": "1.0.1", + "version": "1.0.2", "description": "A nuxt.js module that implements a universal api layer, same-way compatible between server and client side.", "keywords": [ "nuxt", From 2040875e86debe78e4c397d1b23abdda8654ebc5 Mon Sep 17 00:00:00 2001 From: Pedro Pereira Date: Mon, 4 Jun 2018 12:13:07 +0100 Subject: [PATCH 2/6] chlog: refactoring --- CHANGELOG.md | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 879d535..0eb77d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,42 +4,37 @@ All notable changes to this project will be documented in this file. See [standa ## [1.0.2](https://github.com/ezypeeze/nuxt-neo/compare/v1.0.1...v1.0.2) (2018-06-04) - - ### Bug Fixes - * arguments call of controllers tree functions in client side ([dc558b4](https://github.com/ezypeeze/nuxt-neo/commit/dc558b4)) - - ## [1.0.1](https://github.com/ezypeeze/nuxt-neo/compare/v1.0.0...v1.0.1) (2018-05-28) ### Bug Fixes -- Error response handler handles now the proper error, instead of moving to nuxt error handling. ([17b1974](https://github.com/ezypeeze/nuxt-neo/commit/17b1974)) -- Fixed docs basic-usage.md (add two 'export default' on client side api handler example) ([ba06cdf](https://github.com/ezypeeze/nuxt-neo/commit/ba06cdf)) +* Error response handler handles now the proper error, instead of moving to nuxt error handling. ([17b1974](https://github.com/ezypeeze/nuxt-neo/commit/17b1974)) +* Fixed docs basic-usage.md (add two 'export default' on client side api handler example) ([ba06cdf](https://github.com/ezypeeze/nuxt-neo/commit/ba06cdf)) -# [1.0.0](https://github.com/ezypeeze/nuxt-neo/compare/v0.0.5...v1.0.0) (2018-05-28) -- Removed Services Module -- Removed submodules configuration. -- This package will take care only of the API initialization and access both from client and server side -- Updated documentation +## [1.0.0](https://github.com/ezypeeze/nuxt-neo/compare/v0.0.5...v1.0.0) (2018-05-28) +* Removed Services Module +* Removed submodules configuration. +* This package will take care only of the API initialization and access both from client and server side +* Updated documentation ## [0.0.4](https://github.com/ezypeeze/nuxt-neo/compare/v0.0.3...v0.0.4) (2018-05-26) -- Services are disabled by default -- Removed ```asyncData``` and ```fetch``` helpers (now vue js root instance has $api injected (a.k.a app key)) -- Controller tree is generated on every request -- Updated documentation +* Services are disabled by default +* Removed ```asyncData``` and ```fetch``` helpers (now vue js root instance has $api injected (a.k.a app key)) +* Controller tree is generated on every request +* Updated documentation ## [0.0.3](https://github.com/ezypeeze/nuxt-neo/compare/v0.0.2...v0.0.3) (2018-05-14) -Minor updates. +* Minor updates. ## [0.0.2](https://github.com/ezypeeze/nuxt-neo/compare/v0.0.1...v0.0.2) (2018-05-14) -Minor updates. Documentation. +* Minor updates. Documentation. ## [0.0.1](https://github.com/ezypeeze/nuxt-neo/releases/tag/v0.0.1) (2018-05-12) -First release \ No newline at end of file +* First release \ No newline at end of file From fd16e4d68c42312121691cbc486c38b621fb27fd Mon Sep 17 00:00:00 2001 From: Pedro Pereira Date: Wed, 6 Jun 2018 10:38:29 +0100 Subject: [PATCH 3/6] refactor: add jsdocs to functions, create controllerMappingServerSide function. --- lib/server_middleware/api.js | 29 +++++------------------ lib/utility/controllers.js | 45 ++++++++++++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 28 deletions(-) diff --git a/lib/server_middleware/api.js b/lib/server_middleware/api.js index 5758f52..062cc4b 100755 --- a/lib/server_middleware/api.js +++ b/lib/server_middleware/api.js @@ -1,6 +1,6 @@ -const express = require('express'); -const url = require('url'); -const {getControllerFiles, getControllerMiddleware, controllerMapping} = require('../utility/controllers'); +const express = require('express'); +const url = require('url'); +const { getControllerFiles, getControllerMiddleware, controllerMappingServerSide } = require('../utility/controllers'); /** * Action handler middleware. @@ -8,7 +8,6 @@ const {getControllerFiles, getControllerMiddleware, controllerMapping} = require * @param ControllerClass * @param methodName * @param options - * * @returns {Function} */ function actionHandler(ControllerClass, methodName, options) { @@ -29,6 +28,7 @@ function actionHandler(ControllerClass, methodName, options) { * * @param controllerFile * @param options + * @returns {Router} */ function createControllerRouter(controllerFile, options) { const router = express.Router(); @@ -135,30 +135,13 @@ function injectAPI(options) { /** * Injects Route Controller mapper. + * * @param options * @returns {Function} */ function injectRouteControllerMapping(options) { return function (req, res, next) { - req._controllersTree = controllerMapping(options.directory, function (ControllerClass, actionName) { - return function (params, body, query) { - try { - return Promise.resolve(new ControllerClass(req)[actionName]({ - params: params || {}, - body: body || {}, - query: query || {} - })) - .then(function (result) { - return options.successHandler(result); - }) - .catch(function (err) { - return options.errorHandler(err, req); - }); - } catch (err) { - return options.errorHandler(err, req); - } - } - }); + req._controllersTree = controllerMappingServerSide(options.directory, req, options); next(); } diff --git a/lib/utility/controllers.js b/lib/utility/controllers.js index 2d54fb1..8756ed6 100755 --- a/lib/utility/controllers.js +++ b/lib/utility/controllers.js @@ -5,6 +5,7 @@ const fs = require('fs'); * * @param directory * @param fileList + * @returns {Array} */ function getControllerFiles(directory, fileList) { const files = fs.readdirSync(directory); @@ -25,7 +26,7 @@ function getControllerFiles(directory, fileList) { * Gets controller middleware * * @param ControllerClass - * @return Object + * @returns {Object} */ function getControllerMiddleware(ControllerClass) { const all = []; @@ -61,7 +62,11 @@ function controllerMappingRecursive(mapping, parts, onEmpty) { } /** - * Route controller mapping + * Route controller mapping. + * + * @param directory + * @param controllerValue + * @returns {Object} */ function controllerMapping(directory, controllerValue) { let mapping = {}; @@ -88,7 +93,7 @@ function controllerMapping(directory, controllerValue) { * Route Controller mapping for client side api plugin. * * @param directory - * @return Object + * @returns {Object} */ function controllerMappingClientSide(directory) { return controllerMapping(directory, function (ControllerClass, actionName, {path, verb}, routePrefix) { @@ -99,9 +104,39 @@ function controllerMappingClientSide(directory) { }); } +/** + * Route Controller mapping for server side. + * + * @param directory + * @param req + * @param options + * @returns {Object} + */ +function controllerMappingServerSide(directory, req, options) { + return controllerMapping(options.directory, function (ControllerClass, actionName) { + return function (params, body, query) { + try { + return Promise.resolve(new ControllerClass(req)[actionName]({ + params: params || {}, + body: body || {}, + query: query || {} + })) + .then(function (result) { + return options.successHandler(result); + }) + .catch(function (err) { + return options.errorHandler(err, req); + }); + } catch (err) { + return options.errorHandler(err, req); + } + } + }); +} + module.exports = { getControllerFiles, getControllerMiddleware, - controllerMapping, - controllerMappingClientSide + controllerMappingClientSide, + controllerMappingServerSide }; From 5acd9deae6b8be6654848e949434d3df4a989340 Mon Sep 17 00:00:00 2001 From: Pedro Pereira Date: Wed, 6 Jun 2018 10:51:56 +0100 Subject: [PATCH 4/6] refactor: add jsdocs to function controllerRouteRecursive --- lib/utility/controllers.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/utility/controllers.js b/lib/utility/controllers.js index 8756ed6..240add6 100755 --- a/lib/utility/controllers.js +++ b/lib/utility/controllers.js @@ -46,6 +46,11 @@ function getControllerMiddleware(ControllerClass) { /** * Route controller mapping recursive. + * + * @param mapping + * @param parts + * @param onEmpty + * @returns {void} */ function controllerMappingRecursive(mapping, parts, onEmpty) { parts = (Array.isArray(parts) ? parts : []); From b5083b5ed75f6e6ef90a0792c03c4bce2b1ae18b Mon Sep 17 00:00:00 2001 From: Pedro Pereira Date: Wed, 6 Jun 2018 14:03:36 +0100 Subject: [PATCH 5/6] feat(responseMiddleware): add responseMiddleware (both client and server side) to perform actions to payload, uniformly --- lib/module.js | 4 ++++ lib/plugins/api.template.js | 17 ++++++++++++++++- lib/utility/controllers.js | 11 +++++++++++ tests/api.flow.test.js | 4 ++++ tests/fixtures/nuxt.config.js | 3 ++- tests/fixtures/pages/index.vue | 2 ++ tests/fixtures/response_middleware.js | 5 +++++ 7 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 tests/fixtures/response_middleware.js diff --git a/lib/module.js b/lib/module.js index 68bc1d6..06c244b 100755 --- a/lib/module.js +++ b/lib/module.js @@ -8,6 +8,7 @@ const DEFAULT_MODULE_OPTIONS = { debug: process.env.NODE_ENV !== 'production', noContentStatusOnEmpty: true, clientSideApiHandler: '~/api_handler', + responseMiddleware: null, successHandler: function (result) { return result; }, @@ -48,6 +49,8 @@ const DEFAULT_MODULE_OPTIONS = { module.exports = function NeoModule(moduleOptions) { moduleOptions = _.merge(DEFAULT_MODULE_OPTIONS, moduleOptions); + moduleOptions.aliasKey = /^[~|@]/g; + moduleOptions.srcDir = this.options.srcDir; // Globalize http errors exceptions moduleOptions.httpErrors && require('./utility/http_errors'); @@ -66,6 +69,7 @@ module.exports = function NeoModule(moduleOptions) { src: path.resolve(__dirname, 'plugins', 'api.template.js'), options: { apiHandlerFile: moduleOptions.clientSideApiHandler, + responseMiddlewareFile: moduleOptions.responseMiddleware, controllers: JSON.stringify(controllerMappingClientSide(moduleOptions.directory)), apiConfig: JSON.stringify(moduleOptions) } diff --git a/lib/plugins/api.template.js b/lib/plugins/api.template.js index cbe0790..7989137 100644 --- a/lib/plugins/api.template.js +++ b/lib/plugins/api.template.js @@ -1,5 +1,20 @@ import Vue from 'vue'; import ApiHandler from '<%= options.apiHandlerFile %>'; +<% if (options.responseMiddlewareFile) { %> +import ResponseMiddleware from '<%= options.responseMiddlewareFile %>'; +<% } else { %> +const ResponseMiddleware = null; +<% } %> + +/** + * Runs possible middleware for the response + * + * @param result + * @returns {Function} + */ +function runResponseMiddleware(result) { + return ResponseMiddleware && ResponseMiddleware(result) || Promise.resolve(result); +} /** * Inject given params into path (express-like) @@ -40,7 +55,7 @@ function generateAPI(controllerMapping) { context.verb, values || {}, <%= options.apiConfig %> - ); + ).then(runResponseMiddleware); } } else if (typeof controllerMapping[key] === 'object') { api[key] = generateAPI(controllerMapping[key]); diff --git a/lib/utility/controllers.js b/lib/utility/controllers.js index 240add6..42bd2a7 100755 --- a/lib/utility/controllers.js +++ b/lib/utility/controllers.js @@ -118,6 +118,14 @@ function controllerMappingClientSide(directory) { * @returns {Object} */ function controllerMappingServerSide(directory, req, options) { + let ResponseMiddleware = options.responseMiddleware + ? require(options.responseMiddleware.replace(options.aliasKey, options.srcDir)) + : null; + + ResponseMiddleware = ResponseMiddleware && ResponseMiddleware.default + ? ResponseMiddleware.default + : ResponseMiddleware; + return controllerMapping(options.directory, function (ControllerClass, actionName) { return function (params, body, query) { try { @@ -129,6 +137,9 @@ function controllerMappingServerSide(directory, req, options) { .then(function (result) { return options.successHandler(result); }) + .then(function (result) { + return ResponseMiddleware && ResponseMiddleware(result) || Promise.resolve(result); + }) .catch(function (err) { return options.errorHandler(err, req); }); diff --git a/tests/api.flow.test.js b/tests/api.flow.test.js index 7e68654..dab8d15 100644 --- a/tests/api.flow.test.js +++ b/tests/api.flow.test.js @@ -40,8 +40,10 @@ test('Test hybrid api data flow server side.', async (t) => { const window = await nuxt.renderAndGetWindow(URL('/')); const path = window.document.querySelector('.index span.path'); const okay = window.document.querySelector('.index span.okay'); + const resMiddle = window.document.querySelector('.index span.response-middleware'); t.is(okay.textContent, "It's okay!"); + t.is(resMiddle.textContent, "It's okay!"); // Since it accessed to controller on server side, the request path should be '/' which was what we rendered above t.is(path.textContent, '/'); @@ -54,6 +56,7 @@ test('Test hybrid api data flow client side', async (t) => { const okay = window.document.querySelector('.index span.okay'); const idParam = window.document.querySelector('.index span.id-param'); const changePath = window.document.querySelector('.index .change-path'); + const resMiddle = window.document.querySelector('.index span.response-middleware'); changePath.dispatchEvent(clickEvent); await new Promise(resolve => setTimeout(resolve, 1000)); // wait for API request @@ -61,4 +64,5 @@ test('Test hybrid api data flow client side', async (t) => { t.is(path.textContent, '/api/v2/users/1'); t.is(okay.textContent, "It's okay!"); t.is(idParam.textContent, '1'); + t.is(resMiddle.textContent, "It's okay!"); }); diff --git a/tests/fixtures/nuxt.config.js b/tests/fixtures/nuxt.config.js index a5519b9..545b1be 100755 --- a/tests/fixtures/nuxt.config.js +++ b/tests/fixtures/nuxt.config.js @@ -5,7 +5,8 @@ module.exports = { modules: [ [LIB_DIR + '/module', { directory: TEST_DIR + '/fixtures/api', - debug: true + debug: true, + responseMiddleware: '~/response_middleware' }] ], diff --git a/tests/fixtures/pages/index.vue b/tests/fixtures/pages/index.vue index 4acfa2e..4e74172 100644 --- a/tests/fixtures/pages/index.vue +++ b/tests/fixtures/pages/index.vue @@ -4,6 +4,8 @@ {{ data.params && data.params.id }} It's okay! It's not okay... + It's okay! + It's not okay... diff --git a/tests/fixtures/response_middleware.js b/tests/fixtures/response_middleware.js new file mode 100644 index 0000000..503da40 --- /dev/null +++ b/tests/fixtures/response_middleware.js @@ -0,0 +1,5 @@ +export default function (result) { + result.response_middleware = true; + + return result; +} \ No newline at end of file From 2f50d2eb9e8aa5546a7fe333adfe41d77044f860 Mon Sep 17 00:00:00 2001 From: Pedro Pereira Date: Wed, 6 Jun 2018 14:04:02 +0100 Subject: [PATCH 6/6] docs(responseMiddleware): update docs for responseMiddleware --- docs/configuration.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/configuration.md b/docs/configuration.md index f51fa56..606ba7d 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -21,6 +21,9 @@ The default options are: // Client side http request handler -- required clientSideApiHandler: '~/api_handler', + // Universal response handler (will run both on client side and server side $api calls) -- optional + responseMiddleware: null, + // Middleware handlers for all your api. middleware: [],