From aa0ae92d18d44b73e8dd6698518a2eb2e217a75c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nataniel=20L=C3=B3pez?= Date: Fri, 8 Nov 2019 12:17:31 -0300 Subject: [PATCH] Minor fixes, added tests for new features and updated docs --- CHANGELOG.md | 2 + README.md | 30 +++++++ lib/api.js | 16 ++++ lib/dispatcher.js | 8 +- tests/dispatcher-test.js | 172 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 224 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cd3666..5c23cfa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- Logs for api requests ## [4.1.1] - 2019-10-01 ### Changed diff --git a/README.md b/README.md index b3821d4..b749d3d 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,21 @@ Returns the the headers of the request as a key-value object. * **cookies** (*getter*). Returns the the cookies of the request as a key-value object. +* **shouldCreateLog(*getter*)**. +Returns if the api execution should be logged as a boolean. + +* **shouldLogRequestData(*getter*)**. +Returns if the api request data should be logged as a boolean. + +* **shouldLogRequestHeaders(*getter*)**. +Returns if the api response data should be logged as a boolean. + +* **excludeFieldsLogRequestData(*getter*)**. +Returns the fields to exclude from the api request data that will be logged as an array. + +* **excludeFieldsLogResponseBody(*getter*)**. +Returns the fields to exclude from the api response body that will be logged as an array. + ### Setters All this setters are chainable! @@ -63,6 +78,21 @@ Set response cookies. `cookies` must be an object with "key-value" cookies. * **setBody(body)**. Set the response body. +* **shouldCreateLog(bool)**. +Set if the api execution should be logged. `true` by default except for `get` http methods. + +* **shouldLogRequestData(bool)**. +Set if the api request data should be logged. `true` by default. + +* **shouldLogRequestHeaders(bool)**. +Set if the api response data should be logged. `true` by default. + +* **excludeFieldsLogRequestData(fields)**. +Set the fields to exclude from the api request data that will be logged. `fields` should be an array. + +* **excludeFieldsLogResponseBody(fields)**. +Set the fields to exclude from the api response body that will be logged. `fields` should be an array. + ## Dispatcher diff --git a/lib/api.js b/lib/api.js index 141b857..5acd892 100644 --- a/lib/api.js +++ b/lib/api.js @@ -47,6 +47,22 @@ class API { return typeof this._shouldLogResponseBody !== 'undefined' ? this._shouldLogResponseBody : true; } + set excludeFieldsLogRequestData(fields) { + this._excludeFieldsLogRequestData = fields; + } + + get excludeFieldsLogRequestData() { + return this._excludeFieldsLogRequestData; + } + + set excludeFieldsLogResponseBody(fields) { + this._excludeFieldsLogResponseBody = fields; + } + + get excludeFieldsLogResponseBody() { + return this._excludeFieldsLogResponseBody; + } + // Request setters and getters set data(data) { diff --git a/lib/dispatcher.js b/lib/dispatcher.js index ffefbe7..3890daa 100644 --- a/lib/dispatcher.js +++ b/lib/dispatcher.js @@ -68,10 +68,10 @@ class Dispatcher { _saveLog() { // Set default in case of shouldCreateLog is not defined - if(typeof this.shouldCreateLog === 'undefined') - this.shouldCreateLog = this.endpoint !== 'get'; + if(typeof this.api.shouldCreateLog === 'undefined') + this.api.shouldCreateLog = this.method !== 'get'; - if(!this._isObject(this.session) || typeof this.session.clientCode !== 'string' || !this.shouldCreateLog) + if(!this._isObject(this.api.session) || typeof this.api.session.clientCode !== 'string' || !this.api.shouldCreateLog) return; const executionTime = this._executionFinished[1] / 1000000; @@ -102,7 +102,7 @@ class Dispatcher { executionTime }; - Log.add(this.session.clientCode, { + Log.add(this.api.session.clientCode, { entity: 'api', entityId, type: 'api-request', diff --git a/tests/dispatcher-test.js b/tests/dispatcher-test.js index c86fa2a..0eb0b93 100644 --- a/tests/dispatcher-test.js +++ b/tests/dispatcher-test.js @@ -417,4 +417,176 @@ describe('Dispatcher', function() { }); + context('when an api request is executed', function() { + + const defaultApi = { + endpoint: 'api/valid-endpoint', + headers: { + 'janis-api-key': 'foo', + 'janis-api-secret': 'bar', + 'my-header': 'sarasa' + }, + data: { some: 'data' }, + authenticationData: { clientCode: 'fizzmod' } + }; + + it('should log the api request', async () => { + + extraProcess = api => { + api.shouldCreateLog = true; + }; + + responseBody = { message: 'ok' }; + responseHeaders = { 'res-header': 'some-data' }; + + await test({ + ...defaultApi, + endpoint: 'api/valid-endpoint/10' + }, 200, responseHeaders); + + sandbox.assert.calledWithMatch(Log.add, 'fizzmod', { + entity: 'api', + entityId: 'valid-endpoint', + type: 'api-request', + log: { + api: { + endpoint: 'valid-endpoint/10', + httpMethod: 'get' + }, + request: { + headers: { + 'my-header': 'sarasa' + }, + data: { some: 'data' } + }, + response: { + code: 200, + headers: responseHeaders, + body: responseBody + }, + executionTime: sandbox.match.number + } + }); + }); + + it('should log the request without request data, headers and response body', async function() { + + extraProcess = api => { + + api.shouldCreateLog = true; + api.shouldLogRequestData = false; + api.shouldLogRequestHeaders = false; + api.shouldLogResponseBody = false; + }; + + responseBody = { message: 'ok' }; + + await test(defaultApi, 200); + + sandbox.assert.calledWithMatch(Log.add, 'fizzmod', { + entity: 'api', + entityId: 'valid-endpoint', + type: 'api-request', + log: { + api: { + endpoint: 'valid-endpoint', + httpMethod: 'get' + }, + request: {}, + response: { + code: 200 + }, + executionTime: sandbox.match.number + } + }); + }); + + it('should log the request exlcuding the specified fields of request data and response body', async function() { + + extraProcess = api => { + + api.shouldCreateLog = true; + + api.excludeFieldsLogRequestData = [ + 'password', + 'address' + ]; + + api.excludeFieldsLogResponseBody = [ + 'password', + 'secretCode' + ]; + }; + + responseBody = { + message: 'ok', + password: 'foobar', + authData: { + secretCode: 1, + publicCode: 2 + } + }; + + await test({ + ...defaultApi, + data: { + some: 'data', + password: 'foobar', + location: { + address: 'Fake St. 123', + country: 'AR' + } + } + }, 200); + + sandbox.assert.calledWithMatch(Log.add, 'fizzmod', { + entity: 'api', + entityId: 'valid-endpoint', + type: 'api-request', + log: { + api: { + endpoint: 'valid-endpoint', + httpMethod: 'get' + }, + request: { + data: { + some: 'data', + password: sandbox.match.undefined, + location: { + address: sandbox.match.undefined, + country: 'AR' + } + } + }, + response: { + code: 200, + body: { + message: 'ok', + password: sandbox.match.undefined, + authData: { + secretCode: sandbox.match.undefined, + publicCode: 2 + } + } + }, + executionTime: sandbox.match.number + } + }); + }); + + it('should not log the api request with get method when api.shouldCreateLog is not set', async function() { + await test(defaultApi, 200); + sandbox.assert.notCalled(Log.add); + }); + + it('should not log the api request when api.shouldCreateLog is false', async function() { + + extraProcess = api => { + api.shouldCreateLog = false; + }; + + await test(defaultApi, 200); + sandbox.assert.notCalled(Log.add); + }); + }); });