@centeredgesoft/runtime-mock-routes 2.1.0 → 2.5.0

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/src/appV2.ts CHANGED
@@ -1,228 +1,258 @@
1
- import bodyParser from 'body-parser';
2
- import Chance from 'chance';
3
- import cors from 'cors';
4
- import express from 'express';
5
- import faker from 'faker';
6
- import createMatcher from 'feather-route-matcher';
7
- import Handlebars from 'handlebars';
8
- import { cloneDeep, get } from 'lodash';
9
- import sortKeys from 'sort-keys';
10
-
11
- const chance = new Chance();
12
-
13
- Handlebars.registerHelper('faker', (funcName: string, ...rest: any[]) => {
14
- try {
15
- const func = get(faker, funcName, () => '');
16
- return func(...rest);
17
- } catch (err) {
18
- return err;
19
- }
20
- });
21
-
22
- Handlebars.registerHelper('chance', (funcName: string, ...rest: any[]) => {
23
- try {
24
- const func = get(chance, funcName, () => '');
25
- return func.call(chance, ...rest);
26
- } catch (err) {
27
- return err
28
- }
29
- })
30
-
31
- type SupportedMethodsType = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];
32
- export const SupportedMethodsColection: SupportedMethodsType = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];
33
- export type SupportedMethod = SupportedMethodsType[number];
34
-
35
- export const isSupportedMethod = (obj: any): obj is SupportedMethod => SupportedMethodsColection.includes(obj);
36
-
37
- export interface RuntimeRequestMethodBody {
38
- body: any,
39
- status?: number
40
- }
41
-
42
- export const isRuntimeRequestMethodBody = (obj: any): obj is RuntimeRequestMethodBody => {
43
- try {
44
- return !!obj.body && (!obj.status || !isNaN(Number(obj.status)))
45
- } catch (_) {
46
- return false;
47
- }
48
- }
49
-
50
- export type RuntimeRequestMethodBodyCollection = Partial<Record<SupportedMethod, RuntimeRequestMethodBody>>;
51
-
52
- export const isRuntimeRequestMethodBodyCollection = (obj: any): obj is RuntimeRequestMethodBodyCollection => {
53
- try {
54
- return !Object.keys(obj).some(k => !(isSupportedMethod(k) && isRuntimeRequestMethodBody(obj[k])))
55
- } catch (_) { return false; }
56
- }
57
-
58
- export interface RuntimeRequestBody {
59
- path: string;
60
- methods: RuntimeRequestMethodBodyCollection;
61
- }
62
-
63
- export const isRuntimeRequestBody = (obj: any): obj is RuntimeRequestBody => {
64
- try {
65
- return typeof obj.path === 'string'
66
- && isRuntimeRequestMethodBodyCollection(obj.methods)
67
- } catch (_) { return false; }
68
- }
69
-
70
- export interface RuntimeRequestCollection {
71
- [path: string]: RuntimeRequestBody
72
- }
73
-
74
- export const isRuntimeRequestCollection = (obj: any): obj is RuntimeRequestCollection => {
75
- try { return !Object.keys(obj).some(k => !isRuntimeRequestBody(obj[k])) }
76
- catch (_) {
77
- return false
78
- }
79
- }
80
-
81
- export const appFactory = (runtimeCollection?: RuntimeRequestCollection) => {
82
- let runtimeRequestCollection: RuntimeRequestCollection = runtimeCollection || {};
83
- if (!isRuntimeRequestCollection(runtimeRequestCollection)) {
84
- throw new Error('Intial requests JSON is invalid')
85
- }
86
-
87
- runtimeRequestCollection = Object.keys(runtimeRequestCollection).reduce(
88
- (acc, curr) => {
89
- const fixedPath = `/${curr}`.replace(/\/\//g, '/');
90
- const body = {
91
- ...runtimeCollection[curr],
92
- path: fixedPath
93
- }
94
- return {
95
- ...acc,
96
- [fixedPath]: body
97
- };
98
- },
99
- {} as RuntimeRequestCollection
100
- );
101
-
102
- const app = express();
103
-
104
- app.use(cors());
105
- app.use(bodyParser.json());
106
-
107
- app.get('/', (_req, res) => res.send(sortKeys(runtimeRequestCollection, { deep: true })));
108
-
109
- app.post('/', (req, res) => {
110
- const { body } = req;
111
- if (isRuntimeRequestBody(body)) {
112
- const fixedPath = `/${body.path}`.replace(/\/\//g, '/');
113
- body.path = fixedPath;
114
-
115
- runtimeRequestCollection = {
116
- ...runtimeRequestCollection,
117
- [fixedPath]: body
118
- }
119
- return res.status(204).send();
120
- }
121
- return res.status(400).send();
122
- });
123
-
124
- app.put('/', (req, res) => {
125
- const { body } = req;
126
- if(!isRuntimeRequestCollection(body)){
127
- return res.status(400).send('BAD_REQUEST_BODY')
128
- }
129
-
130
- const cleanBody = Object.keys(body).reduce(
131
- (acc, curr) => {
132
- const fixedPath = `/${curr}`.replace(/\/\//g, '/');
133
- const newBody = {
134
- ...body[curr],
135
- path: fixedPath
136
- }
137
- return {
138
- ...acc,
139
- [fixedPath]: newBody
140
- };
141
- },
142
- {} as RuntimeRequestCollection
143
- );
144
-
145
- runtimeRequestCollection = cleanBody;
146
- return res.status(204).send();
147
- });
148
-
149
- app.delete('/', (req, res) => {
150
- let { path } = req.query;
151
-
152
- if (!path) {
153
- return res.status(400).send();
154
- }
155
-
156
- const cleanPath = Array.isArray(path) ? (path as any[]).map(p => `${p}`) : [`${path}`]
157
-
158
- runtimeRequestCollection = cleanPath.reduce(
159
- (acc, curr) => {
160
- const { [curr]: _, ...rest } = acc;
161
- return rest;
162
- },
163
- runtimeRequestCollection
164
- );
165
-
166
- return res.status(204).send();
167
- });
168
-
169
- const catchAllHandler = (req, res) => {
170
- const matcher = createMatcher(runtimeRequestCollection);
171
- const routeMatch = matcher(req.path);
172
-
173
- if (routeMatch) {
174
- const reqInfo: RuntimeRequestBody = routeMatch.value;
175
- const params = routeMatch.params;
176
-
177
- const method: RuntimeRequestMethodBody = reqInfo.methods[req.method];
178
- if (!method) {
179
- return res.status(404).send()
180
- }
181
-
182
- const tokenParams = {
183
- query: req.query,
184
- params,
185
- body: req.body
186
- }
187
-
188
- if (method.status) {
189
- res.status(method.status);
190
- }
191
-
192
- const { body } = method;
193
-
194
- if (typeof body !== 'string') {
195
- return res.send(body);
196
- }
197
-
198
- const template = Handlebars.compile(body);
199
- const result = template(tokenParams)
200
-
201
- try {
202
- const jsonResult = JSON.parse(result);
203
- return res.send(jsonResult);
204
- } catch (_) {
205
- return res.send(result)
206
- }
207
- }
208
-
209
- return res.status(404).send();
210
- }
211
-
212
- app.get('/*', catchAllHandler);
213
- app.post('/*', catchAllHandler);
214
- app.put('/*', catchAllHandler);
215
- app.patch('/*', catchAllHandler);
216
- app.delete('/*', catchAllHandler);
217
-
218
- Object.defineProperty(app, 'runtimeRequestCollection', {
219
- get: () => {
220
- return cloneDeep(runtimeRequestCollection);
221
- }
222
- })
223
-
224
- return app;
225
- }
226
-
227
- const app = appFactory();
1
+ import Chance from 'chance';
2
+ import cors from 'cors';
3
+ import express, { Request, Response } from 'express';
4
+ import faker from 'faker';
5
+ import createMatcher from 'feather-route-matcher';
6
+ import Handlebars from 'handlebars';
7
+ import { cloneDeep, get } from 'lodash';
8
+ import sortKeys from 'sort-keys';
9
+
10
+ const chance = new Chance();
11
+
12
+ Handlebars.registerHelper('faker', (funcName: string, ...rest: any[]) => {
13
+ try {
14
+ const func = get(faker, funcName, () => '');
15
+ return func(...rest);
16
+ } catch (err) {
17
+ return err;
18
+ }
19
+ });
20
+
21
+ Handlebars.registerHelper('chance', (funcName: string, ...rest: any[]) => {
22
+ try {
23
+ const func = get(chance, funcName, () => '');
24
+ return func.call(chance, ...rest);
25
+ } catch (err) {
26
+ return err
27
+ }
28
+ })
29
+
30
+ type SupportedMethodsType = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];
31
+ export const SupportedMethodsColection: SupportedMethodsType = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];
32
+ export type SupportedMethod = SupportedMethodsType[number];
33
+
34
+ export const isSupportedMethod = (obj: any): obj is SupportedMethod => SupportedMethodsColection.includes(obj);
35
+
36
+ export interface RuntimeRequestMethodBody {
37
+ body: any;
38
+ status?: number | ((...args: any[])=>number);
39
+ headers?: Record<string, string>;
40
+ }
41
+
42
+ export interface RequestParameters {
43
+ query: any,
44
+ params: any,
45
+ body: any,
46
+ headers: any
47
+ }
48
+
49
+ export const isRuntimeRequestMethodBody = (obj: any): obj is RuntimeRequestMethodBody => {
50
+ try {
51
+ return !!obj.body && (!obj.status || !isNaN(Number(obj.status)))
52
+ } catch (_) {
53
+ return false;
54
+ }
55
+ }
56
+
57
+ export type RuntimeRequestMethodBodyCollection = Partial<Record<SupportedMethod, RuntimeRequestMethodBody>>;
58
+
59
+ export const isRuntimeRequestMethodBodyCollection = (obj: any): obj is RuntimeRequestMethodBodyCollection => {
60
+ try {
61
+ return !Object.keys(obj).some(k => !(isSupportedMethod(k) && isRuntimeRequestMethodBody(obj[k])))
62
+ } catch (_) { return false; }
63
+ }
64
+
65
+ export interface RuntimeRequestBody {
66
+ path: string;
67
+ methods: RuntimeRequestMethodBodyCollection;
68
+ }
69
+
70
+ export const isRuntimeRequestBody = (obj: any): obj is RuntimeRequestBody => {
71
+ try {
72
+ return typeof obj.path === 'string'
73
+ && isRuntimeRequestMethodBodyCollection(obj.methods)
74
+ } catch (_) { return false; }
75
+ }
76
+
77
+ export interface RuntimeRequestCollection {
78
+ [path: string]: RuntimeRequestBody
79
+ }
80
+
81
+ export const isRuntimeRequestCollection = (obj: any): obj is RuntimeRequestCollection => {
82
+ try { return !Object.keys(obj).some(k => !isRuntimeRequestBody(obj[k])) }
83
+ catch (_) {
84
+ return false
85
+ }
86
+ }
87
+
88
+ export const appFactory = (runtimeCollection?: RuntimeRequestCollection) => {
89
+ let runtimeRequestCollection: RuntimeRequestCollection = runtimeCollection || {};
90
+ if (!isRuntimeRequestCollection(runtimeRequestCollection)) {
91
+ throw new Error('Intial requests JSON is invalid')
92
+ }
93
+
94
+ runtimeRequestCollection = Object.keys(runtimeRequestCollection).reduce(
95
+ (acc, curr) => {
96
+ const fixedPath = `/${curr}`.replace(/\/\//g, '/');
97
+ const body = {
98
+ ...runtimeCollection[curr],
99
+ path: fixedPath
100
+ }
101
+ return {
102
+ ...acc,
103
+ [fixedPath]: body
104
+ };
105
+ },
106
+ {} as RuntimeRequestCollection
107
+ );
108
+
109
+ const app = express();
110
+
111
+ app.use(cors());
112
+ app.use(express.json({
113
+ strict: false
114
+ }));
115
+
116
+ app.get('/', (_req, res) => res.send(sortKeys(runtimeRequestCollection, { deep: true })));
117
+
118
+ app.post('/', (req, res) => {
119
+ const { body } = req;
120
+ if (isRuntimeRequestBody(body)) {
121
+ const fixedPath = `/${body.path}`.replace(/\/\//g, '/');
122
+ body.path = fixedPath;
123
+
124
+ runtimeRequestCollection = {
125
+ ...runtimeRequestCollection,
126
+ [fixedPath]: body
127
+ }
128
+ return res.status(204).send();
129
+ }
130
+ return res.status(400).send();
131
+ });
132
+
133
+ app.put('/', (req, res) => {
134
+ const { body } = req;
135
+ if (!isRuntimeRequestCollection(body)) {
136
+ return res.status(400).send('BAD_REQUEST_BODY')
137
+ }
138
+
139
+ const cleanBody = Object.keys(body).reduce(
140
+ (acc, curr) => {
141
+ const fixedPath = `/${curr}`.replace(/\/\//g, '/');
142
+ const newBody = {
143
+ ...body[curr],
144
+ path: fixedPath
145
+ }
146
+ return {
147
+ ...acc,
148
+ [fixedPath]: newBody
149
+ };
150
+ },
151
+ {} as RuntimeRequestCollection
152
+ );
153
+
154
+ runtimeRequestCollection = cleanBody;
155
+ return res.status(204).send();
156
+ });
157
+
158
+ app.delete('/', (req, res) => {
159
+ let { path } = req.query;
160
+
161
+ if (!path) {
162
+ return res.status(400).send();
163
+ }
164
+
165
+ const cleanPath = Array.isArray(path) ? (path as any[]).map(p => `${p}`) : [`${path}`]
166
+
167
+ runtimeRequestCollection = cleanPath.reduce(
168
+ (acc, curr) => {
169
+ const { [curr]: _, ...rest } = acc;
170
+ return rest;
171
+ },
172
+ runtimeRequestCollection
173
+ );
174
+
175
+ return res.status(204).send();
176
+ });
177
+
178
+ const catchAllHandler = (req: Request, res: Response) => {
179
+ const matcher = createMatcher(runtimeRequestCollection);
180
+ const routeMatch = matcher(req.path);
181
+
182
+ if (routeMatch) {
183
+ const reqInfo: RuntimeRequestBody = routeMatch.value;
184
+ const params = routeMatch.params;
185
+
186
+ const method: RuntimeRequestMethodBody = reqInfo.methods[req.method];
187
+ if (!method) {
188
+ return res.status(404).send()
189
+ }
190
+
191
+ const tokenParams = {
192
+ query: req.query,
193
+ params,
194
+ body: req.body,
195
+ headers: req.headers
196
+ }
197
+
198
+ if (method.status) {
199
+ const status = typeof method.status === 'function'
200
+ ? method.status(tokenParams)
201
+ : method.status
202
+
203
+ res.status(status);
204
+ }
205
+
206
+ if (method.headers) {
207
+ const processedHeaders = Object.keys(method.headers).reduce(
208
+ (acc, curr) => ({
209
+ ...acc,
210
+ [curr]: Handlebars.compile(method.headers[curr])(tokenParams)
211
+ }),
212
+ {} as Record<string, string>
213
+ );
214
+ res.set(processedHeaders);
215
+ }
216
+
217
+ let { body } = method;
218
+
219
+ // if body is a function, execute and then process the response
220
+ if (typeof body === 'function') {
221
+ body = body(tokenParams);
222
+ }
223
+
224
+ if (typeof body !== 'string') {
225
+ return res.send(body);
226
+ }
227
+
228
+ const template = Handlebars.compile(body);
229
+ const result = template(tokenParams)
230
+
231
+ try {
232
+ const jsonResult = JSON.parse(result);
233
+ return res.send(jsonResult);
234
+ } catch (_) {
235
+ return res.send(result)
236
+ }
237
+ }
238
+
239
+ return res.status(404).send();
240
+ }
241
+
242
+ app.get('/*', catchAllHandler);
243
+ app.post('/*', catchAllHandler);
244
+ app.put('/*', catchAllHandler);
245
+ app.patch('/*', catchAllHandler);
246
+ app.delete('/*', catchAllHandler);
247
+
248
+ Object.defineProperty(app, 'runtimeRequestCollection', {
249
+ get: () => {
250
+ return cloneDeep(runtimeRequestCollection);
251
+ }
252
+ })
253
+
254
+ return app;
255
+ }
256
+
257
+ const app = appFactory();
228
258
  export default app;
package/tsconfig.json CHANGED
@@ -1,16 +1,16 @@
1
- {
2
- "compilerOptions": {
3
- "target": "es6",
4
- "module": "commonjs",
5
- "rootDir": "./",
6
- "outDir": "./build",
7
- "declaration": true,
8
- "esModuleInterop": true,
9
- "strict": false,
10
- },
11
- "exclude": [
12
- "**/*.spec.ts",
13
- "**/*.test.ts",
14
- "./build/**/*"
15
- ]
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es6",
4
+ "module": "commonjs",
5
+ "rootDir": "./",
6
+ "outDir": "./build",
7
+ "declaration": true,
8
+ "esModuleInterop": true,
9
+ "strict": false,
10
+ },
11
+ "exclude": [
12
+ "**/*.spec.ts",
13
+ "**/*.test.ts",
14
+ "./build/**/*"
15
+ ]
16
16
  }
package/.env DELETED
File without changes