@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/app.ts CHANGED
@@ -1,235 +1,235 @@
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 RuntimeRequestBody {
38
- path: string;
39
- body: any;
40
- method: SupportedMethod;
41
- status?: number;
42
- }
43
-
44
- export const isRuntimeRequestBody = (obj: any): obj is RuntimeRequestBody => {
45
- try {
46
- return typeof obj.path === 'string'
47
- && obj.hasOwnProperty('body')
48
- && (obj.status === undefined || !isNaN(Number(obj.status)))
49
- && isSupportedMethod(obj.method)
50
- } catch (_) { return false; }
51
- }
52
-
53
- export interface RuntimeRequestCollection {
54
- [path: string]: RuntimeRequestBody
55
- }
56
-
57
- export const isRuntimeRequestCollection = (obj: any): obj is RuntimeRequestCollection => {
58
- try { return !Object.keys(obj).some(k => !isRuntimeRequestBody(obj[k])) }
59
- catch (_) {
60
- return false
61
- }
62
- }
63
-
64
- export type MethodBasedRuntimeRequestCollection = Partial<Record<SupportedMethod, RuntimeRequestCollection>>;
65
-
66
- export const isMethodBasedRuntimeRequestCollection = (obj: any): obj is MethodBasedRuntimeRequestCollection => {
67
- try {
68
- return !Object.keys(obj).some(k => !(isSupportedMethod(k) && isRuntimeRequestCollection(obj[k])))
69
- } catch (_) {
70
- return false
71
- }
72
- }
73
-
74
- interface CleanRuntimeRequestCollectionParams {
75
- collection: RuntimeRequestCollection;
76
- method: SupportedMethod;
77
- }
78
- export const cleanRuntimeRequestCollection = (params: CleanRuntimeRequestCollectionParams): RuntimeRequestCollection => {
79
- return Object.keys(params.collection).reduce(
80
- (acc, curr) => {
81
- const sanitizedPath = `/${curr}`.replace(/\/\//g, '/')
82
- const fixedRequest: RuntimeRequestBody = {
83
- ...params.collection[curr],
84
- path: sanitizedPath,
85
- method: params.method
86
- }
87
- return {
88
- ...acc,
89
- [sanitizedPath]: fixedRequest
90
- }
91
- },
92
- {} as RuntimeRequestCollection
93
- );
94
- };
95
-
96
- export const cleanMethodBasedRuntimeRequestCollection = (obj: MethodBasedRuntimeRequestCollection): MethodBasedRuntimeRequestCollection => {
97
- return Object.keys(obj).reduce((acc, curr) => {
98
- const method = curr as SupportedMethod;
99
- const collection: RuntimeRequestCollection = obj[curr];
100
- return {
101
- ...acc,
102
- [curr]: cleanRuntimeRequestCollection({ method, collection })
103
- }
104
- },
105
- {} as MethodBasedRuntimeRequestCollection);
106
- };
107
-
108
- export const singleQueryParam = (obj: any) => Array.isArray(obj) ? `${obj[0]}` : `${obj}`;
109
-
110
- export const appFactory = (runtimeCollection?: MethodBasedRuntimeRequestCollection) => {
111
- let runtimeRequestCollection: MethodBasedRuntimeRequestCollection = runtimeCollection || {};
112
- if (!isMethodBasedRuntimeRequestCollection(runtimeRequestCollection)) {
113
- throw new Error('Intial requests JSON is invalid')
114
- }
115
-
116
- runtimeRequestCollection = cleanMethodBasedRuntimeRequestCollection(runtimeRequestCollection);
117
-
118
- const app = express();
119
-
120
- app.use(cors());
121
- app.use(bodyParser.json());
122
-
123
- app.get('/', (_req, res) => res.send(sortKeys(runtimeRequestCollection, { deep: true })));
124
-
125
- app.post('/', (req, res) => {
126
- const { body } = req;
127
- if (isRuntimeRequestBody(body)) {
128
- const fixedPath = `/${body.path}`.replace(/\/\//g, '/');
129
- body.path = fixedPath;
130
- const method = body.method;
131
- runtimeRequestCollection = {
132
- ...runtimeRequestCollection,
133
- [method]: {
134
- ...(runtimeRequestCollection[method] || {}),
135
- [fixedPath]: body
136
- }
137
- }
138
- return res.status(204).send();
139
- }
140
- return res.status(400).send();
141
- })
142
-
143
- app.delete('/', (req, res) => {
144
- let { path, method } = req.query;
145
-
146
- if (!path || !method) {
147
- return res.status(400).send();
148
- }
149
-
150
- const cleanPath = singleQueryParam(path);
151
- const cleanMethod = singleQueryParam(method);
152
-
153
- if (!isSupportedMethod(cleanMethod)) {
154
- return res.status(400).send();
155
- }
156
-
157
- if (!Object.keys(runtimeRequestCollection).includes(cleanMethod)) {
158
- return res.status(204).send();
159
- }
160
-
161
- const { [cleanMethod]: oldCollection, ...otherMetods } = runtimeRequestCollection;
162
- const { [cleanPath]: _, ...newCollection } = oldCollection;
163
-
164
- runtimeRequestCollection = {
165
- ...otherMetods,
166
- [cleanMethod]: newCollection
167
- };
168
-
169
- return res.status(204).send();
170
- });
171
-
172
- const catchAllHandler = (req, res) => {
173
- const method = req.method;
174
- if (!isSupportedMethod(method)) {
175
- return res.status(400).send();
176
- }
177
- const collection = runtimeRequestCollection[method];
178
- if (!collection) {
179
- return res.status(404).send();
180
- }
181
- const matcher = createMatcher(collection);
182
-
183
- const routeMatch = matcher(req.path);
184
-
185
- if (routeMatch) {
186
- const reqInfo: RuntimeRequestBody = routeMatch.value;
187
- const params = routeMatch.params;
188
-
189
- const tokenParams = {
190
- query: req.query,
191
- params,
192
- body: req.body
193
- }
194
-
195
- if (reqInfo.status) {
196
- res.status(reqInfo.status);
197
- }
198
-
199
- const { body } = reqInfo;
200
-
201
- if (typeof body !== 'string') {
202
- return res.send(body);
203
- }
204
-
205
- const template = Handlebars.compile(body);
206
- const result = template(tokenParams)
207
-
208
- try {
209
- const jsonResult = JSON.parse(result);
210
- return res.send(jsonResult);
211
- } catch (_) {
212
- return res.send(result)
213
- }
214
- }
215
-
216
- return res.status(404).send();
217
- }
218
-
219
- app.get('/*', catchAllHandler);
220
- app.post('/*', catchAllHandler);
221
- app.put('/*', catchAllHandler);
222
- app.patch('/*', catchAllHandler);
223
- app.delete('/*', catchAllHandler);
224
-
225
- Object.defineProperty(app, 'runtimeRequestCollection', {
226
- get: () => {
227
- return cloneDeep(runtimeRequestCollection);
228
- }
229
- })
230
-
231
- return app;
232
- }
233
-
234
- const app = appFactory();
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 RuntimeRequestBody {
38
+ path: string;
39
+ body: any;
40
+ method: SupportedMethod;
41
+ status?: number;
42
+ }
43
+
44
+ export const isRuntimeRequestBody = (obj: any): obj is RuntimeRequestBody => {
45
+ try {
46
+ return typeof obj.path === 'string'
47
+ && obj.hasOwnProperty('body')
48
+ && (obj.status === undefined || !isNaN(Number(obj.status)))
49
+ && isSupportedMethod(obj.method)
50
+ } catch (_) { return false; }
51
+ }
52
+
53
+ export interface RuntimeRequestCollection {
54
+ [path: string]: RuntimeRequestBody
55
+ }
56
+
57
+ export const isRuntimeRequestCollection = (obj: any): obj is RuntimeRequestCollection => {
58
+ try { return !Object.keys(obj).some(k => !isRuntimeRequestBody(obj[k])) }
59
+ catch (_) {
60
+ return false
61
+ }
62
+ }
63
+
64
+ export type MethodBasedRuntimeRequestCollection = Partial<Record<SupportedMethod, RuntimeRequestCollection>>;
65
+
66
+ export const isMethodBasedRuntimeRequestCollection = (obj: any): obj is MethodBasedRuntimeRequestCollection => {
67
+ try {
68
+ return !Object.keys(obj).some(k => !(isSupportedMethod(k) && isRuntimeRequestCollection(obj[k])))
69
+ } catch (_) {
70
+ return false
71
+ }
72
+ }
73
+
74
+ interface CleanRuntimeRequestCollectionParams {
75
+ collection: RuntimeRequestCollection;
76
+ method: SupportedMethod;
77
+ }
78
+ export const cleanRuntimeRequestCollection = (params: CleanRuntimeRequestCollectionParams): RuntimeRequestCollection => {
79
+ return Object.keys(params.collection).reduce(
80
+ (acc, curr) => {
81
+ const sanitizedPath = `/${curr}`.replace(/\/\//g, '/')
82
+ const fixedRequest: RuntimeRequestBody = {
83
+ ...params.collection[curr],
84
+ path: sanitizedPath,
85
+ method: params.method
86
+ }
87
+ return {
88
+ ...acc,
89
+ [sanitizedPath]: fixedRequest
90
+ }
91
+ },
92
+ {} as RuntimeRequestCollection
93
+ );
94
+ };
95
+
96
+ export const cleanMethodBasedRuntimeRequestCollection = (obj: MethodBasedRuntimeRequestCollection): MethodBasedRuntimeRequestCollection => {
97
+ return Object.keys(obj).reduce((acc, curr) => {
98
+ const method = curr as SupportedMethod;
99
+ const collection: RuntimeRequestCollection = obj[curr];
100
+ return {
101
+ ...acc,
102
+ [curr]: cleanRuntimeRequestCollection({ method, collection })
103
+ }
104
+ },
105
+ {} as MethodBasedRuntimeRequestCollection);
106
+ };
107
+
108
+ export const singleQueryParam = (obj: any) => Array.isArray(obj) ? `${obj[0]}` : `${obj}`;
109
+
110
+ export const appFactory = (runtimeCollection?: MethodBasedRuntimeRequestCollection) => {
111
+ let runtimeRequestCollection: MethodBasedRuntimeRequestCollection = runtimeCollection || {};
112
+ if (!isMethodBasedRuntimeRequestCollection(runtimeRequestCollection)) {
113
+ throw new Error('Intial requests JSON is invalid')
114
+ }
115
+
116
+ runtimeRequestCollection = cleanMethodBasedRuntimeRequestCollection(runtimeRequestCollection);
117
+
118
+ const app = express();
119
+
120
+ app.use(cors());
121
+ app.use(bodyParser.json());
122
+
123
+ app.get('/', (_req, res) => res.send(sortKeys(runtimeRequestCollection, { deep: true })));
124
+
125
+ app.post('/', (req, res) => {
126
+ const { body } = req;
127
+ if (isRuntimeRequestBody(body)) {
128
+ const fixedPath = `/${body.path}`.replace(/\/\//g, '/');
129
+ body.path = fixedPath;
130
+ const method = body.method;
131
+ runtimeRequestCollection = {
132
+ ...runtimeRequestCollection,
133
+ [method]: {
134
+ ...(runtimeRequestCollection[method] || {}),
135
+ [fixedPath]: body
136
+ }
137
+ }
138
+ return res.status(204).send();
139
+ }
140
+ return res.status(400).send();
141
+ })
142
+
143
+ app.delete('/', (req, res) => {
144
+ let { path, method } = req.query;
145
+
146
+ if (!path || !method) {
147
+ return res.status(400).send();
148
+ }
149
+
150
+ const cleanPath = singleQueryParam(path);
151
+ const cleanMethod = singleQueryParam(method);
152
+
153
+ if (!isSupportedMethod(cleanMethod)) {
154
+ return res.status(400).send();
155
+ }
156
+
157
+ if (!Object.keys(runtimeRequestCollection).includes(cleanMethod)) {
158
+ return res.status(204).send();
159
+ }
160
+
161
+ const { [cleanMethod]: oldCollection, ...otherMetods } = runtimeRequestCollection;
162
+ const { [cleanPath]: _, ...newCollection } = oldCollection;
163
+
164
+ runtimeRequestCollection = {
165
+ ...otherMetods,
166
+ [cleanMethod]: newCollection
167
+ };
168
+
169
+ return res.status(204).send();
170
+ });
171
+
172
+ const catchAllHandler = (req, res) => {
173
+ const method = req.method;
174
+ if (!isSupportedMethod(method)) {
175
+ return res.status(400).send();
176
+ }
177
+ const collection = runtimeRequestCollection[method];
178
+ if (!collection) {
179
+ return res.status(404).send();
180
+ }
181
+ const matcher = createMatcher(collection);
182
+
183
+ const routeMatch = matcher(req.path);
184
+
185
+ if (routeMatch) {
186
+ const reqInfo: RuntimeRequestBody = routeMatch.value;
187
+ const params = routeMatch.params;
188
+
189
+ const tokenParams = {
190
+ query: req.query,
191
+ params,
192
+ body: req.body
193
+ }
194
+
195
+ if (reqInfo.status) {
196
+ res.status(reqInfo.status);
197
+ }
198
+
199
+ const { body } = reqInfo;
200
+
201
+ if (typeof body !== 'string') {
202
+ return res.send(body);
203
+ }
204
+
205
+ const template = Handlebars.compile(body);
206
+ const result = template(tokenParams)
207
+
208
+ try {
209
+ const jsonResult = JSON.parse(result);
210
+ return res.send(jsonResult);
211
+ } catch (_) {
212
+ return res.send(result)
213
+ }
214
+ }
215
+
216
+ return res.status(404).send();
217
+ }
218
+
219
+ app.get('/*', catchAllHandler);
220
+ app.post('/*', catchAllHandler);
221
+ app.put('/*', catchAllHandler);
222
+ app.patch('/*', catchAllHandler);
223
+ app.delete('/*', catchAllHandler);
224
+
225
+ Object.defineProperty(app, 'runtimeRequestCollection', {
226
+ get: () => {
227
+ return cloneDeep(runtimeRequestCollection);
228
+ }
229
+ })
230
+
231
+ return app;
232
+ }
233
+
234
+ const app = appFactory();
235
235
  export default app;