@mimik/api-helper 3.0.0 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -31
- package/index.js +54 -41
- package/lib/baseHandlers.js +6 -24
- package/lib/common.js +1 -1
- package/lib/extract-helper.js +7 -12
- package/lib/oauthValidation-helper.js +2 -2
- package/lib/securityHandlers.js +59 -132
- package/package.json +16 -13
- package/.claude/settings.local.json +0 -9
- package/.husky/pre-commit +0 -2
- package/.husky/pre-push +0 -2
- package/eslint.config.js +0 -82
- package/test/ajvHelpers.test.js +0 -159
- package/test/baseHandlers.test.js +0 -150
- package/test/extract-helper.test.js +0 -100
- package/test/index-async.test.js +0 -599
- package/test/index-sync.test.js +0 -282
- package/test/oauthValidation-helper.test.js +0 -136
- package/test/securityHandlers.test.js +0 -557
package/README.md
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
## Modules
|
|
2
|
+
|
|
3
|
+
<dl>
|
|
4
|
+
<dt><a href="#module_api-helper">api-helper</a></dt>
|
|
5
|
+
<dd></dd>
|
|
6
|
+
</dl>
|
|
7
|
+
|
|
8
|
+
## Typedefs
|
|
9
|
+
|
|
10
|
+
<dl>
|
|
11
|
+
<dt><a href="#UUID">UUID</a> : <code>string</code></dt>
|
|
12
|
+
<dd><p>UUID string in RFC 4122 format.</p>
|
|
13
|
+
</dd>
|
|
14
|
+
<dt><a href="#PATH">PATH</a> : <code>string</code></dt>
|
|
15
|
+
<dd><p>File system path string.</p>
|
|
16
|
+
</dd>
|
|
17
|
+
</dl>
|
|
18
|
+
|
|
1
19
|
<a name="module_api-helper"></a>
|
|
2
20
|
|
|
3
21
|
## api-helper
|
|
@@ -21,19 +39,19 @@ import { apiSetup, securityLib, getAPIFile, validateSecuritySchemes, extractProp
|
|
|
21
39
|
<a name="module_api-helper..apiSetup"></a>
|
|
22
40
|
|
|
23
41
|
### api-helper~apiSetup(setup, registeredOperations, securityHandlers, extraFormats, config, correlationId) ⇒ <code>Promise.<object></code>
|
|
24
|
-
|
|
42
|
+
Set up the API to be used for a service
|
|
25
43
|
|
|
26
44
|
**Kind**: inner method of [<code>api-helper</code>](#module_api-helper)
|
|
27
|
-
**Returns**: <code>Promise.<object></code> - The
|
|
45
|
+
**Returns**: <code>Promise.<object></code> - The initialized OpenAPIBackend instance.
|
|
28
46
|
**Category**: async
|
|
29
47
|
**Throws**:
|
|
30
48
|
|
|
31
|
-
- <code>
|
|
49
|
+
- <code>Error</code> Rejects with an error if the initialization failed.
|
|
32
50
|
|
|
33
51
|
The following scheme names are reserved: `SystemSecurity`, `AdminSecurity`, `UserSecurity`, `PeerSecurity`, `ApiKeySecurity`.
|
|
34
52
|
The following security schemes can be defaulted: `SystemSecurity`, `AdminSecurity`, `UserSecurity`, `ApiKeySecurity`.
|
|
35
53
|
The secOptions in the options property passed when using `init` allows the following operations:
|
|
36
|
-
- introduce a
|
|
54
|
+
- introduce a custom security scheme, in this case secOptions contains: { newSecurityScheme: {function}newSecurityHandler },
|
|
37
55
|
- disable a security scheme that is defined in the swagger API, in this case secOptions contains: { securitySchemeToDisable: { {boolean}notEnabled: true } },
|
|
38
56
|
- overwrite an existing security scheme, in this case secOptions contains: { securitySchemeToOverwrite: {function}newSecurityHandler }.
|
|
39
57
|
If the secOptions is not present either to introduce, disable or overwrite a security scheme that is present in the swagger API file an error is generated.
|
|
@@ -46,23 +64,26 @@ The default formats for validation are: `date`, `time`, `date-time`, `byte`, `uu
|
|
|
46
64
|
| Param | Type | Description |
|
|
47
65
|
| --- | --- | --- |
|
|
48
66
|
| setup | <code>object</code> | Object containing the apiFilename and the existing security schemes in the API definition. |
|
|
49
|
-
|
|
|
50
|
-
|
|
|
51
|
-
|
|
|
67
|
+
| setup.apiFilename | [<code>PATH</code>](#PATH) | Path to the resolved API definition file. |
|
|
68
|
+
| setup.existingSecuritySchemes | <code>Array.<string></code> | Known security scheme names present in the API definition. |
|
|
69
|
+
| setup.definedSecuritySchemes | <code>Array.<string></code> | All security scheme names defined in the API definition. |
|
|
70
|
+
| registeredOperations | <code>object</code> | Map of operationId to handler function to register for the API. |
|
|
71
|
+
| securityHandlers | <code>object</code> | Map of security scheme name to handler object to add for the service. |
|
|
72
|
+
| extraFormats | <code>object</code> | Map of format name to format definition for validating properties. Each entry is either an empty object (to use a built-in ajv-formats format) or an object with `type` and `validate` properties (to define a custom format). |
|
|
52
73
|
| config | <code>object</code> | Configuration of the service. |
|
|
53
|
-
| correlationId | <code>UUID
|
|
74
|
+
| correlationId | [<code>UUID</code>](#UUID) | CorrelationId when logging activities. |
|
|
54
75
|
|
|
55
76
|
<a name="module_api-helper..getAPIFile"></a>
|
|
56
77
|
|
|
57
78
|
### api-helper~getAPIFile(apiFilename, correlationId, options) ⇒ <code>Promise.<object></code>
|
|
58
|
-
Gets the API
|
|
79
|
+
Gets and resolves the API definition, loading from local file, Bitbucket, or SwaggerHub, and stores it in the given PATH location.
|
|
59
80
|
|
|
60
81
|
**Kind**: inner method of [<code>api-helper</code>](#module_api-helper)
|
|
61
82
|
**Returns**: <code>Promise.<object></code> - The API file itself.
|
|
62
83
|
**Category**: async
|
|
63
84
|
**Throws**:
|
|
64
85
|
|
|
65
|
-
- <code>
|
|
86
|
+
- <code>Error</code> Rejects with an error if the apiFilename resolution generates an error or the request to the API provider fails or the file cannot be saved.
|
|
66
87
|
|
|
67
88
|
`apiInfo` options has the following format:
|
|
68
89
|
``` javascript
|
|
@@ -80,45 +101,45 @@ Gets the API file from swaggerhub and stores it in the given PATH location.
|
|
|
80
101
|
|
|
81
102
|
| Param | Type | Description |
|
|
82
103
|
| --- | --- | --- |
|
|
83
|
-
| apiFilename | <code>PATH
|
|
84
|
-
| correlationId | <code>UUID
|
|
104
|
+
| apiFilename | [<code>PATH</code>](#PATH) | Name of the file where the API file will be stored. |
|
|
105
|
+
| correlationId | [<code>UUID</code>](#UUID) | CorrelationId when logging activities. |
|
|
85
106
|
| options | <code>object</code> | Options associated with the call. Use to pass `metrics` to `rpRetry` and `apiInfo` to access the api file in the api provider. |
|
|
86
107
|
|
|
87
108
|
<a name="module_api-helper..setupServerFiles"></a>
|
|
88
109
|
|
|
89
110
|
### api-helper~setupServerFiles(apiFilename, controllersDirectory, buildDirectory, correlationId, options) ⇒ <code>Promise.<object></code>
|
|
90
|
-
|
|
111
|
+
Sets up and validates files for the server
|
|
91
112
|
|
|
92
113
|
**Kind**: inner method of [<code>api-helper</code>](#module_api-helper)
|
|
93
114
|
**Returns**: <code>Promise.<object></code> - The API file, the API filename, the existing known security schemes and the defined security schemes.
|
|
94
115
|
**Category**: async
|
|
95
116
|
**Throws**:
|
|
96
117
|
|
|
97
|
-
- <code>
|
|
118
|
+
- <code>Error</code> Rejects with an error for many reasons associated with getAPIFile or validateSecuritySchemes or extractProperties.
|
|
98
119
|
|
|
99
120
|
**Requires**: <code>module:@mimik/request-retry</code>, <code>module:@mimik/response-helper</code>, <code>module:@mimik/sumologic-winston-logger</code>, <code>module:fs</code>, <code>module:js-yaml</code>, <code>module:path</code>
|
|
100
121
|
|
|
101
122
|
| Param | Type | Description |
|
|
102
123
|
| --- | --- | --- |
|
|
103
|
-
| apiFilename | <code>PATH
|
|
104
|
-
| controllersDirectory | <code>PATH
|
|
105
|
-
| buildDirectory | <code>PATH
|
|
106
|
-
| correlationId | <code>UUID
|
|
124
|
+
| apiFilename | [<code>PATH</code>](#PATH) | Name of the file where the API file will be stored. |
|
|
125
|
+
| controllersDirectory | [<code>PATH</code>](#PATH) | Directory to find the controller files. |
|
|
126
|
+
| buildDirectory | [<code>PATH</code>](#PATH) | Directory where the register file will be stored. |
|
|
127
|
+
| correlationId | [<code>UUID</code>](#UUID) | CorrelationId when logging activities. |
|
|
107
128
|
| options | <code>object</code> | Options associated with the call. Use to pass `metrics` to `rpRetry` and `apiKey` to access private API. |
|
|
108
129
|
|
|
109
130
|
<a name="module_api-helper..securityLib"></a>
|
|
110
131
|
|
|
111
132
|
### api-helper~securityLib(config) ⇒ <code>object</code>
|
|
112
|
-
|
|
133
|
+
Implements the security flows for the API.
|
|
113
134
|
|
|
114
135
|
**Kind**: inner method of [<code>api-helper</code>](#module_api-helper)
|
|
115
136
|
**Returns**: <code>object</code> - An object containing `SystemSecurity`, `AdminSecurity`, `UserSecurity`, and `ApiKeySecurity` handlers.
|
|
116
137
|
|
|
117
|
-
This function is used to
|
|
118
|
-
- `SystemSecurity` - used for
|
|
119
|
-
- `AdminSecurity` - used for
|
|
120
|
-
- `UserSecurity` - used for
|
|
121
|
-
- `ApiKeySecurity` - used for
|
|
138
|
+
This function is used to set up the following security handlers for the API:
|
|
139
|
+
- `SystemSecurity` - used for system-to-system operations, validates client credentials tokens.
|
|
140
|
+
- `AdminSecurity` - used for admin operations, validates admin/subAdmin client credentials tokens.
|
|
141
|
+
- `UserSecurity` - used for user operations, validates implicit flow tokens.
|
|
142
|
+
- `ApiKeySecurity` - used for API key authenticated operations, validates API keys from headers.
|
|
122
143
|
The security handlers are used to validate the tokens and scopes for the API operations.
|
|
123
144
|
**Category**: sync
|
|
124
145
|
**Requires**: <code>module:@mimik/swagger-helper</code>, <code>module:jsonwebtoken</code>
|
|
@@ -137,32 +158,44 @@ Validates the known SecuritySchemes: `SystemSecurity`, `AdminSecurity`, `UserSec
|
|
|
137
158
|
**Category**: sync
|
|
138
159
|
**Throws**:
|
|
139
160
|
|
|
140
|
-
- An error is thrown if a validation fails.
|
|
161
|
+
- <code>Error</code> An error is thrown if a validation fails.
|
|
141
162
|
|
|
142
163
|
**Requires**: <code>module:@mimik/sumologic-winston-logger</code>, <code>module:@mimik/response-helper</code>
|
|
143
164
|
|
|
144
165
|
| Param | Type | Description |
|
|
145
166
|
| --- | --- | --- |
|
|
146
167
|
| apiDefinition | <code>object</code> | JSON object containing the API definition. |
|
|
147
|
-
| correlationId | <code>UUID
|
|
168
|
+
| correlationId | [<code>UUID</code>](#UUID) | CorrelationId when logging activities. |
|
|
148
169
|
|
|
149
170
|
<a name="module_api-helper..extractProperties"></a>
|
|
150
171
|
|
|
151
172
|
### api-helper~extractProperties(apiDefinition, controllersDirectory, buildDirectory, correlationId) ⇒ <code>void</code>
|
|
152
|
-
Extracts the properties from API definition and creates a file binding the handler with the controller operations.
|
|
173
|
+
Extracts the properties from API definition and creates a `register.js` file in the build directory binding the handler with the controller operations.
|
|
153
174
|
|
|
154
175
|
**Kind**: inner method of [<code>api-helper</code>](#module_api-helper)
|
|
155
176
|
**Category**: sync
|
|
156
177
|
**Throws**:
|
|
157
178
|
|
|
158
|
-
- An error is thrown for many reasons, like operationId does not exist in controllers, controller does not exist...
|
|
179
|
+
- <code>Error</code> An error is thrown for many reasons, like operationId does not exist in controllers, controller does not exist...
|
|
159
180
|
|
|
160
181
|
**Requires**: <code>module:@mimik/response-helper</code>, <code>module:@mimik/sumologic-winston-logger</code>, <code>module:fs</code>
|
|
161
182
|
|
|
162
183
|
| Param | Type | Description |
|
|
163
184
|
| --- | --- | --- |
|
|
164
185
|
| apiDefinition | <code>object</code> | JSON object containing the API definition. |
|
|
165
|
-
| controllersDirectory | <code>PATH
|
|
166
|
-
| buildDirectory | <code>PATH
|
|
167
|
-
| correlationId | <code>UUID
|
|
186
|
+
| controllersDirectory | [<code>PATH</code>](#PATH) | Directory to find the controller files. |
|
|
187
|
+
| buildDirectory | [<code>PATH</code>](#PATH) | Directory where the register file will be stored. |
|
|
188
|
+
| correlationId | [<code>UUID</code>](#UUID) | CorrelationId when logging activities. |
|
|
189
|
+
|
|
190
|
+
<a name="UUID"></a>
|
|
191
|
+
|
|
192
|
+
## UUID : <code>string</code>
|
|
193
|
+
UUID string in RFC 4122 format.
|
|
194
|
+
|
|
195
|
+
**Kind**: global typedef
|
|
196
|
+
<a name="PATH"></a>
|
|
197
|
+
|
|
198
|
+
## PATH : <code>string</code>
|
|
199
|
+
File system path string.
|
|
168
200
|
|
|
201
|
+
**Kind**: global typedef
|
package/index.js
CHANGED
|
@@ -38,6 +38,14 @@ import pathLib from 'path';
|
|
|
38
38
|
import { rpRetry } from '@mimik/request-retry';
|
|
39
39
|
import { saveProperties } from './lib/extract-helper.js';
|
|
40
40
|
import { securityLib } from './lib/securityHandlers.js';
|
|
41
|
+
/**
|
|
42
|
+
* UUID string in RFC 4122 format.
|
|
43
|
+
* @typedef {string} UUID
|
|
44
|
+
*/
|
|
45
|
+
/**
|
|
46
|
+
* File system path string.
|
|
47
|
+
* @typedef {string} PATH
|
|
48
|
+
*/
|
|
41
49
|
/**
|
|
42
50
|
* @module api-helper
|
|
43
51
|
* @example
|
|
@@ -54,7 +62,7 @@ const API_VERSION_INDEX = 2;
|
|
|
54
62
|
const POSTFIX_INDEX = 3;
|
|
55
63
|
/**
|
|
56
64
|
*
|
|
57
|
-
*
|
|
65
|
+
* Implements the security flows for the API.
|
|
58
66
|
*
|
|
59
67
|
* @function securityLib
|
|
60
68
|
* @category sync
|
|
@@ -63,37 +71,40 @@ const POSTFIX_INDEX = 3;
|
|
|
63
71
|
* @param {object} config - Configuration of the service.
|
|
64
72
|
* @return {object} An object containing `SystemSecurity`, `AdminSecurity`, `UserSecurity`, and `ApiKeySecurity` handlers.
|
|
65
73
|
*
|
|
66
|
-
* This function is used to
|
|
67
|
-
* - `SystemSecurity` - used for
|
|
68
|
-
* - `AdminSecurity` - used for
|
|
69
|
-
* - `UserSecurity` - used for
|
|
70
|
-
* - `ApiKeySecurity` - used for
|
|
74
|
+
* This function is used to set up the following security handlers for the API:
|
|
75
|
+
* - `SystemSecurity` - used for system-to-system operations, validates client credentials tokens.
|
|
76
|
+
* - `AdminSecurity` - used for admin operations, validates admin/subAdmin client credentials tokens.
|
|
77
|
+
* - `UserSecurity` - used for user operations, validates implicit flow tokens.
|
|
78
|
+
* - `ApiKeySecurity` - used for API key authenticated operations, validates API keys from headers.
|
|
71
79
|
* The security handlers are used to validate the tokens and scopes for the API operations.
|
|
72
80
|
*/
|
|
73
81
|
export { securityLib };
|
|
74
82
|
|
|
75
83
|
/**
|
|
76
84
|
*
|
|
77
|
-
*
|
|
85
|
+
* Set up the API to be used for a service
|
|
78
86
|
*
|
|
79
87
|
* @function apiSetup
|
|
80
88
|
* @category async
|
|
81
89
|
* @requires @mimik/response-helper
|
|
82
90
|
* @requires @mimik/sumologic-winston-logger
|
|
83
91
|
* @requires openapi-backend
|
|
84
|
-
* @param {object} setup -
|
|
85
|
-
* @param {
|
|
86
|
-
* @param {
|
|
87
|
-
* @param {
|
|
92
|
+
* @param {object} setup - Object containing the apiFilename and the existing security schemes in the API definition.
|
|
93
|
+
* @param {PATH} setup.apiFilename - Path to the resolved API definition file.
|
|
94
|
+
* @param {Array.<string>} setup.existingSecuritySchemes - Known security scheme names present in the API definition.
|
|
95
|
+
* @param {Array.<string>} setup.definedSecuritySchemes - All security scheme names defined in the API definition.
|
|
96
|
+
* @param {object} registeredOperations - Map of operationId to handler function to register for the API.
|
|
97
|
+
* @param {object} securityHandlers - Map of security scheme name to handler object to add for the service.
|
|
98
|
+
* @param {object} extraFormats - Map of format name to format definition for validating properties. Each entry is either an empty object (to use a built-in ajv-formats format) or an object with `type` and `validate` properties (to define a custom format).
|
|
88
99
|
* @param {object} config - Configuration of the service.
|
|
89
|
-
* @param {UUID
|
|
90
|
-
* @return {Promise.<object>} The
|
|
91
|
-
* @throws {
|
|
100
|
+
* @param {UUID} correlationId - CorrelationId when logging activities.
|
|
101
|
+
* @return {Promise.<object>} The initialized OpenAPIBackend instance.
|
|
102
|
+
* @throws {Error} Rejects with an error if the initialization failed.
|
|
92
103
|
*
|
|
93
104
|
* The following scheme names are reserved: `SystemSecurity`, `AdminSecurity`, `UserSecurity`, `PeerSecurity`, `ApiKeySecurity`.
|
|
94
105
|
* The following security schemes can be defaulted: `SystemSecurity`, `AdminSecurity`, `UserSecurity`, `ApiKeySecurity`.
|
|
95
106
|
* The secOptions in the options property passed when using `init` allows the following operations:
|
|
96
|
-
* - introduce a
|
|
107
|
+
* - introduce a custom security scheme, in this case secOptions contains: { newSecurityScheme: {function}newSecurityHandler },
|
|
97
108
|
* - disable a security scheme that is defined in the swagger API, in this case secOptions contains: { securitySchemeToDisable: { {boolean}notEnabled: true } },
|
|
98
109
|
* - overwrite an existing security scheme, in this case secOptions contains: { securitySchemeToOverwrite: {function}newSecurityHandler }.
|
|
99
110
|
* If the secOptions is not present either to introduce, disable or overwrite a security scheme that is present in the swagger API file an error is generated.
|
|
@@ -124,7 +135,7 @@ export const apiSetup = (setup, registeredOperations, securityHandlers, extraFor
|
|
|
124
135
|
let mode;
|
|
125
136
|
|
|
126
137
|
api.register(registeredOperations);
|
|
127
|
-
if (config
|
|
138
|
+
if (config.nodeEnvironment.toLowerCase() !== LOCAL || config.serverSettings.securitySet === SET_ON) {
|
|
128
139
|
mode = SECURITY_ON;
|
|
129
140
|
}
|
|
130
141
|
else {
|
|
@@ -152,7 +163,7 @@ export const apiSetup = (setup, registeredOperations, securityHandlers, extraFor
|
|
|
152
163
|
if (unusedSecuritySchemes.length !== EMPTY) throw getRichError('System', 'unused handlers for security schemes', { unusedSecuritySchemes });
|
|
153
164
|
|
|
154
165
|
remainingSecurities.forEach((securityScheme) => {
|
|
155
|
-
if (!securityHandlerNames.includes(securityScheme)
|
|
166
|
+
if (!securityHandlerNames.includes(securityScheme)) {
|
|
156
167
|
throw getRichError('System', 'missing handler for security scheme', { securityScheme });
|
|
157
168
|
}
|
|
158
169
|
});
|
|
@@ -165,7 +176,7 @@ export const apiSetup = (setup, registeredOperations, securityHandlers, extraFor
|
|
|
165
176
|
else if (remainingSecurities.length !== EMPTY) throw getRichError('System', 'missing handlers for security schemes', { missingSecuritySchemes: remainingSecurities });
|
|
166
177
|
return api.init()
|
|
167
178
|
.catch((err) => {
|
|
168
|
-
throw getRichError('System', 'could not initialize the api', {
|
|
179
|
+
throw getRichError('System', 'could not initialize the api', { apiFilename }, err);
|
|
169
180
|
})
|
|
170
181
|
.then(() => api);
|
|
171
182
|
};
|
|
@@ -228,7 +239,7 @@ const buildProviderRequest = (params, apiInfo, apiFilename) => {
|
|
|
228
239
|
|
|
229
240
|
/**
|
|
230
241
|
*
|
|
231
|
-
* Gets the API
|
|
242
|
+
* Gets and resolves the API definition, loading from local file, Bitbucket, or SwaggerHub, and stores it in the given PATH location.
|
|
232
243
|
*
|
|
233
244
|
* @function getAPIFile
|
|
234
245
|
* @category async
|
|
@@ -238,11 +249,11 @@ const buildProviderRequest = (params, apiInfo, apiFilename) => {
|
|
|
238
249
|
* @requires fs
|
|
239
250
|
* @requires js-yaml
|
|
240
251
|
* @requires path
|
|
241
|
-
* @param {PATH
|
|
242
|
-
* @param {UUID
|
|
252
|
+
* @param {PATH} apiFilename - Name of the file where the API file will be stored.
|
|
253
|
+
* @param {UUID} correlationId - CorrelationId when logging activities.
|
|
243
254
|
* @param {object} options - Options associated with the call. Use to pass `metrics` to `rpRetry` and `apiInfo` to access the api file in the api provider.
|
|
244
255
|
* @return {Promise.<object>} The API file itself.
|
|
245
|
-
* @throws {
|
|
256
|
+
* @throws {Error} Rejects with an error if the apiFilename resolution generates an error or the request to the API provider fails or the file cannot be saved.
|
|
246
257
|
*
|
|
247
258
|
* `apiInfo` options has the following format:
|
|
248
259
|
* ``` javascript
|
|
@@ -368,9 +379,9 @@ export const getAPIFile = (apiFilename, correlationId, options) => {
|
|
|
368
379
|
* @requires @mimik/sumologic-winston-logger
|
|
369
380
|
* @requires @mimik/response-helper
|
|
370
381
|
* @param {object} apiDefinition - JSON object containing the API definition.
|
|
371
|
-
* @param {UUID
|
|
382
|
+
* @param {UUID} correlationId - CorrelationId when logging activities.
|
|
372
383
|
* @return {Array.<string>} An array of the known securitySchemes that are in the API definition.
|
|
373
|
-
* @throws An error is thrown if a validation fails.
|
|
384
|
+
* @throws {Error} An error is thrown if a validation fails.
|
|
374
385
|
*/
|
|
375
386
|
export const validateSecuritySchemes = (apiDefinition, correlationId) => {
|
|
376
387
|
const existingSecuritySchemes = [];
|
|
@@ -390,7 +401,7 @@ export const validateSecuritySchemes = (apiDefinition, correlationId) => {
|
|
|
390
401
|
|
|
391
402
|
/**
|
|
392
403
|
*
|
|
393
|
-
* Extracts the properties from API definition and creates a file binding the handler with the controller operations.
|
|
404
|
+
* Extracts the properties from API definition and creates a `register.js` file in the build directory binding the handler with the controller operations.
|
|
394
405
|
*
|
|
395
406
|
* @function extractProperties
|
|
396
407
|
* @category sync
|
|
@@ -398,11 +409,11 @@ export const validateSecuritySchemes = (apiDefinition, correlationId) => {
|
|
|
398
409
|
* @requires @mimik/sumologic-winston-logger
|
|
399
410
|
* @requires fs
|
|
400
411
|
* @param {object} apiDefinition - JSON object containing the API definition.
|
|
401
|
-
* @param {PATH
|
|
402
|
-
* @param {PATH
|
|
403
|
-
* @param {UUID
|
|
412
|
+
* @param {PATH} controllersDirectory - Directory to find the controller files.
|
|
413
|
+
* @param {PATH} buildDirectory - Directory where the register file will be stored.
|
|
414
|
+
* @param {UUID} correlationId - CorrelationId when logging activities.
|
|
404
415
|
* @return {void}
|
|
405
|
-
* @throws An error is thrown for many reasons, like operationId does not exist in controllers, controller does not exist...
|
|
416
|
+
* @throws {Error} An error is thrown for many reasons, like operationId does not exist in controllers, controller does not exist...
|
|
406
417
|
*/
|
|
407
418
|
export const extractProperties = (apiDefinition, controllersDirectory, buildDirectory, correlationId) => {
|
|
408
419
|
const result = {};
|
|
@@ -447,17 +458,19 @@ export const extractProperties = (apiDefinition, controllersDirectory, buildDire
|
|
|
447
458
|
catch (err) {
|
|
448
459
|
throw getRichError('System', 'file system error', { controllerFilename }, err);
|
|
449
460
|
}
|
|
461
|
+
let file;
|
|
462
|
+
|
|
450
463
|
try {
|
|
451
|
-
|
|
452
|
-
if (!file.includes(`${operation.operationId},`)
|
|
453
|
-
&& !file.includes(`${operation.operationId}:`)
|
|
454
|
-
&& !file.includes(`export ${operation.operationId}`)) { // code must be linted before
|
|
455
|
-
throw getRichError('System', 'missing operationId in controller file', { controllerFilename, operationId: operation.operationId });
|
|
456
|
-
}
|
|
464
|
+
file = fs.readFileSync(controllerFilename, 'utf8');
|
|
457
465
|
}
|
|
458
466
|
catch (err) {
|
|
459
467
|
throw getRichError('System', 'file system error', { controllerFilename, operationId: operation.operationId }, err);
|
|
460
468
|
}
|
|
469
|
+
if (!file.includes(`${operation.operationId},`)
|
|
470
|
+
&& !file.includes(`${operation.operationId}:`)
|
|
471
|
+
&& !file.includes(`export ${operation.operationId}`)) { // code must be linted before
|
|
472
|
+
throw getRichError('System', 'missing operationId in controller file', { controllerFilename, operationId: operation.operationId });
|
|
473
|
+
}
|
|
461
474
|
if (result[controller]) result[controller].push(operation.operationId);
|
|
462
475
|
else result[controller] = [operation.operationId];
|
|
463
476
|
}
|
|
@@ -473,7 +486,7 @@ export const extractProperties = (apiDefinition, controllersDirectory, buildDire
|
|
|
473
486
|
|
|
474
487
|
/**
|
|
475
488
|
*
|
|
476
|
-
*
|
|
489
|
+
* Sets up and validates files for the server
|
|
477
490
|
*
|
|
478
491
|
* @function setupServerFiles
|
|
479
492
|
* @category async
|
|
@@ -483,13 +496,13 @@ export const extractProperties = (apiDefinition, controllersDirectory, buildDire
|
|
|
483
496
|
* @requires fs
|
|
484
497
|
* @requires js-yaml
|
|
485
498
|
* @requires path
|
|
486
|
-
* @param {PATH
|
|
487
|
-
* @param {PATH
|
|
488
|
-
* @param {PATH
|
|
489
|
-
* @param {UUID
|
|
499
|
+
* @param {PATH} apiFilename - Name of the file where the API file will be stored.
|
|
500
|
+
* @param {PATH} controllersDirectory - Directory to find the controller files.
|
|
501
|
+
* @param {PATH} buildDirectory - Directory where the register file will be stored.
|
|
502
|
+
* @param {UUID} correlationId - CorrelationId when logging activities.
|
|
490
503
|
* @param {object} options - Options associated with the call. Use to pass `metrics` to `rpRetry` and `apiKey` to access private API.
|
|
491
504
|
* @return {Promise.<object>} The API file, the API filename, the existing known security schemes and the defined security schemes.
|
|
492
|
-
* @throws {
|
|
505
|
+
* @throws {Error} Rejects with an error for many reasons associated with getAPIFile or validateSecuritySchemes or extractProperties.
|
|
493
506
|
*/
|
|
494
507
|
export const setupServerFiles = (apiFilename, controllersDirectory, buildDirectory, correlationId, options) => getAPIFile(apiFilename, correlationId, options)
|
|
495
508
|
.then((apiDefinition) => {
|
package/lib/baseHandlers.js
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
|
+
import { ERROR_CODE } from '@mimik/response-helper';
|
|
1
2
|
import { rejectRequest } from '@mimik/swagger-helper';
|
|
2
3
|
|
|
3
|
-
const PARAMETER_ERROR = 400;
|
|
4
|
-
const NOT_FOUND_ERROR = 404;
|
|
5
|
-
const UNAUTHORIZED_ERROR = 401;
|
|
6
|
-
const NOT_IMPLEMENTED_ERROR = 501;
|
|
7
|
-
|
|
8
4
|
const validationFail = (con, req, res) => {
|
|
9
5
|
const error = new Error('Failed schema validation');
|
|
10
6
|
|
|
11
|
-
error.statusCode =
|
|
7
|
+
error.statusCode = ERROR_CODE.PARAMETER;
|
|
12
8
|
error.info = {
|
|
13
9
|
method: req.method,
|
|
14
10
|
path: req.url,
|
|
@@ -22,7 +18,7 @@ const notFound = (con, req, res) => {
|
|
|
22
18
|
const path = req.url;
|
|
23
19
|
const error = new Error(`path ${path} not defined in Swagger specification`);
|
|
24
20
|
|
|
25
|
-
error.statusCode =
|
|
21
|
+
error.statusCode = ERROR_CODE.NOT_FOUND;
|
|
26
22
|
error.info = {
|
|
27
23
|
method: req.method,
|
|
28
24
|
path,
|
|
@@ -33,7 +29,7 @@ const notFound = (con, req, res) => {
|
|
|
33
29
|
const unauthorizedHandler = (con, req, res) => {
|
|
34
30
|
let error = new Error('Unauthorized');
|
|
35
31
|
|
|
36
|
-
error.statusCode =
|
|
32
|
+
error.statusCode = ERROR_CODE.UNAUTHORIZED;
|
|
37
33
|
const schemes = Object.keys(con.security).filter(key => key !== 'authorized');
|
|
38
34
|
|
|
39
35
|
schemes.forEach((scheme) => {
|
|
@@ -50,7 +46,7 @@ const notImplemented = (con, req, res) => {
|
|
|
50
46
|
const path = req.url;
|
|
51
47
|
const error = new Error(`${method} ${path} defined in Swagger specification, but not implemented`);
|
|
52
48
|
|
|
53
|
-
error.statusCode =
|
|
49
|
+
error.statusCode = ERROR_CODE.NOT_IMPLEMENTED;
|
|
54
50
|
error.info = {
|
|
55
51
|
method,
|
|
56
52
|
path,
|
|
@@ -64,7 +60,7 @@ const methodNotAllowed = (con, req, res) => {
|
|
|
64
60
|
const path = req.url;
|
|
65
61
|
const error = new Error(`path ${path} defined in Swagger specification, but the method ${method} is not defined`);
|
|
66
62
|
|
|
67
|
-
error.statusCode =
|
|
63
|
+
error.statusCode = ERROR_CODE.NOT_ALLOWED;
|
|
68
64
|
error.info = {
|
|
69
65
|
method,
|
|
70
66
|
path,
|
|
@@ -72,24 +68,10 @@ const methodNotAllowed = (con, req, res) => {
|
|
|
72
68
|
rejectRequest(error, con, res);
|
|
73
69
|
};
|
|
74
70
|
|
|
75
|
-
/*
|
|
76
|
-
const postResponseHandler = (con, req, res) => {
|
|
77
|
-
const valid = con.api.validateResponse(con.response, con.operation);
|
|
78
|
-
console.log('----->', con.response);
|
|
79
|
-
console.log('----->', valid);
|
|
80
|
-
if (valid.errors) {
|
|
81
|
-
// response validation failed
|
|
82
|
-
return res.status(502).json({ status: 502, err: valid.errors });
|
|
83
|
-
}
|
|
84
|
-
return res.status(200).json(con.response);
|
|
85
|
-
};
|
|
86
|
-
*/
|
|
87
|
-
|
|
88
71
|
export default {
|
|
89
72
|
validationFail,
|
|
90
73
|
notFound,
|
|
91
74
|
unauthorizedHandler,
|
|
92
75
|
notImplemented,
|
|
93
76
|
methodNotAllowed,
|
|
94
|
-
// postResponseHandler,
|
|
95
77
|
};
|
package/lib/common.js
CHANGED
|
@@ -50,7 +50,7 @@ const CLAIMS_SEPARATOR = ',';
|
|
|
50
50
|
const BEARERS = ['bearer', 'Bearer'];
|
|
51
51
|
const USER = 'user';
|
|
52
52
|
const CLUSTER = 'cluster';
|
|
53
|
-
const ESLINT_HEAD = '/* eslint sort-imports:
|
|
53
|
+
const ESLINT_HEAD = '/* eslint sort-imports: off */\n';
|
|
54
54
|
|
|
55
55
|
export {
|
|
56
56
|
X_ROUTER_CONTROLLER,
|
package/lib/extract-helper.js
CHANGED
|
@@ -25,23 +25,18 @@ const saveProperties = (extractResult, buildDirectory, controllersDirectoryName,
|
|
|
25
25
|
}
|
|
26
26
|
const controllers = Object.keys(extractResult);
|
|
27
27
|
const operationIds = [];
|
|
28
|
-
|
|
29
|
-
let itemToSave;
|
|
28
|
+
const imports = [];
|
|
30
29
|
|
|
31
30
|
controllers.forEach((controller) => {
|
|
32
|
-
|
|
33
|
-
extractResult[controller].forEach((operationId) => {
|
|
34
|
-
itemToSave += ` ${operationId},\n`;
|
|
31
|
+
const items = extractResult[controller].map((operationId) => {
|
|
35
32
|
operationIds.push(operationId);
|
|
33
|
+
return ` ${operationId},`;
|
|
36
34
|
});
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
stringToSave += '\nexport {\n';
|
|
40
|
-
itemToSave = '';
|
|
41
|
-
operationIds.forEach((operationId) => {
|
|
42
|
-
itemToSave += ` ${operationId},\n`;
|
|
35
|
+
|
|
36
|
+
imports.push(`import {\n${items.join('\n')}\n} from '../${controllersDirectoryName}/${controller}${EXTENSION}';`);
|
|
43
37
|
});
|
|
44
|
-
|
|
38
|
+
const exportLines = operationIds.map(id => ` ${id},\n`).join('');
|
|
39
|
+
const stringToSave = `${ESLINT_HEAD}${imports.join('\n')}\n\nexport {\n${exportLines}};\n`;
|
|
45
40
|
logger.info(`creating ${filename}`, { filename }, correlationId);
|
|
46
41
|
try {
|
|
47
42
|
fs.writeFileSync(filename, stringToSave);
|
|
@@ -28,10 +28,10 @@ const validateApiKey = (securitySchemes, securityType) => {
|
|
|
28
28
|
|
|
29
29
|
if (security) {
|
|
30
30
|
if (security.in !== API_KEY_IN) {
|
|
31
|
-
throw getRichError('System', `
|
|
31
|
+
throw getRichError('System', `API key security must be in ${API_KEY_IN}`, { securityType, receivedIn: security.in, expectedIn: API_KEY_IN });
|
|
32
32
|
}
|
|
33
33
|
if (security.name !== API_KEY_NAME) {
|
|
34
|
-
throw getRichError('System', `
|
|
34
|
+
throw getRichError('System', `API key security must be named ${API_KEY_NAME}`, { securityType, receivedName: security.name, expectedName: API_KEY_NAME });
|
|
35
35
|
}
|
|
36
36
|
return securityType;
|
|
37
37
|
}
|