From 48383bee247eab676299a46d1ef716e9e6e6c4aa Mon Sep 17 00:00:00 2001 From: CD Cabrera Date: Mon, 6 Aug 2018 03:22:30 -0400 Subject: [PATCH] feat(delay response): add ability to delay response time * added delay flag, in milliseconds * open check for delay and forceStatus params * generic console.info JSON to "response" copy * lowercased options to avoid being needlessly specific * readme examples --- README.md | 32 +++++++++++++++++++++++++++++ src/api_mock.js | 8 ++++++-- src/index.js | 53 +++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 81 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 6f39433..59a8da7 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,13 @@ From there you should be able to navigate to ### More examples, and custom responses +Apidoc Mock adds in a few different custom flags to help you identify or demonstrate API responses +- @apiMock {Random|RandomResponse} - pull a random response from either success or error examples +- @apiMock {RandomSuccess} - pull a random success from success examples +- @apiMock {RandomError} - pull a random error from error examples +- @apiMock {ForceStatus} [HTTP STATUS] - force a specific http status +- @apiMock {DelayResponse} [MILLISECONDS] - force (in milliseconds) a delayed response + 1. Get random responses from both `success` and `error` examples with the `@apiMock {RandomResponse}` annotation ```js /** @@ -176,3 +183,28 @@ From there you should be able to navigate to */ const getExample = () => {}; ``` + +1. Delay a response status with the `@apiMock {DelayResponse} [MILLISECONDS GO HERE]` annotation. + ```js + /** + * @api {get} /hello/world/ + * @apiMock {DelayResponse} 3000 + * @apiSuccess {String} foo + * @apiSuccess {String} bar + * @apiSuccessExample {json} Success-Response: + * HTTP/1.1 200 OK + * { + * "foo": "hello", + * "bar": "world", + * } + * @apiError {String} bad + * @apiError {String} request + * @apiErrorExample {json} Error-Response: + * HTTP/1.1 400 OK + * { + * "bad": "hello", + * "request": "world", + * } + */ + const getExample = () => {}; + ``` diff --git a/src/api_mock.js b/src/api_mock.js index d5f8b34..92fa237 100644 --- a/src/api_mock.js +++ b/src/api_mock.js @@ -1,3 +1,7 @@ +/** + * Configure Apidoc output. Filter custom "apiMock" related key/value + * pairs such as randomResponse, forceStatus, or delayResponse. + */ let group = ''; const parse = (content, source, defaultGroup) => { @@ -8,7 +12,7 @@ const parse = (content, source, defaultGroup) => { let key = (keyValue[0] || '').replace(/({|^\s+|\s+$)/, ''); const value = (keyValue[1] || '').replace(/(^\s+|\s+$)/, ''); - key = key.replace(/(?:^\w|[A-Z]|\b\w)/g, function(letter, index) { + key = key.replace(/(?:^\w|[A-Z]|\b\w)/g, (letter, index) => { return index === 0 ? letter.toLowerCase() : letter.toUpperCase(); }); @@ -22,6 +26,6 @@ const path = () => `local.mock.${getGroup()}`; module.exports = { parse, path, - getGroup: getGroup, + getGroup, method: 'push' }; diff --git a/src/index.js b/src/index.js index 09d921b..86ff46a 100644 --- a/src/index.js +++ b/src/index.js @@ -78,24 +78,41 @@ class LoadApi { if (mockSettings.mock && mockSettings.mock.settings && mockSettings.mock.settings.length) { mockSettings.mock.settings.forEach(val => { const keys = Object.keys(val || {}); - const key = keys[0] || null; + const key = keys[0] || ''; - switch (key) { - case 'forceStatus': + switch (key.toLowerCase()) { + case 'delay': + case 'delayresponse': + settings.delay = parseInt(val[key], 10); + + if (Number.isNaN(settings.delay)) { + settings.delay = 1000; + } + + break; + case 'force': + case 'forcestatus': + case 'forcedstatus': settings.forceStatus = parseInt(val[key], 10); + + if (Number.isNaN(settings.forceStatus)) { + settings.forceStatus = 200; + } + break; case 'response': settings.response = 'response'; break; - case 'randomResponse': + case 'random': + case 'randomresponse': settings.response = 'response'; settings.reload = true; break; - case 'randomSuccess': + case 'randomsuccess': settings.response = 'success'; settings.reload = true; break; - case 'randomError': + case 'randomerror': settings.response = 'error'; settings.reload = true; break; @@ -175,7 +192,7 @@ class LoadApi { return; } - console.info('ApiDoc finished...\tloading JSON'); + console.info('ApiDoc finished...\tloading response'); return JSON.parse(fs.readFileSync(apiJsonFile, 'utf8')); } @@ -367,7 +384,16 @@ class LoadApi { response.append('WWW-Authenticate', 'Spoof response'); response.status(401); response.set('Content-Type', authObj.type); - response.end(authObj.content || 'Authorization Required'); + + if (mockSettings.delay > 0) { + setTimeout( + () => response.end(authObj.content || 'Authorization Required'), + mockSettings.delay + ); + } else { + response.end(authObj.content || 'Authorization Required'); + } + return; } } @@ -379,7 +405,12 @@ class LoadApi { response.set('Content-Type', type); response.status(httpStatus); - response.send(content); + + if (mockSettings.delay > 0) { + setTimeout(() => response.send(content), mockSettings.delay); + } else { + response.send(content); + } }); routesLoaded += 1; @@ -390,7 +421,9 @@ class LoadApi { if (routesLoaded) { this.app.listen(port, () => - console.info(`JSON finished...\tloaded routes\nMock finished...\tforwarded port ${port}`) + console.info( + `Response finished...\tloaded routes\nMock finished...\tforwarded port ${port}` + ) ); } else { console.info(`Mock waiting...`);