@fjell/express-router 4.4.1 → 4.4.3
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/dist/CItemRouter.cjs +20 -4
- package/dist/CItemRouter.cjs.map +1 -1
- package/dist/CItemRouter.d.ts +2 -2
- package/dist/CItemRouter.js +20 -4
- package/dist/CItemRouter.js.map +1 -1
- package/dist/ItemRouter.cjs +79 -36
- package/dist/ItemRouter.cjs.map +1 -1
- package/dist/ItemRouter.d.ts +8 -12
- package/dist/ItemRouter.js +79 -36
- package/dist/ItemRouter.js.map +1 -1
- package/dist/PItemRouter.cjs +14 -5
- package/dist/PItemRouter.cjs.map +1 -1
- package/dist/PItemRouter.d.ts +2 -2
- package/dist/PItemRouter.js +14 -5
- package/dist/PItemRouter.js.map +1 -1
- package/dist/index.cjs +113 -45
- package/dist/index.cjs.map +1 -1
- package/dist/logger.cjs.map +1 -1
- package/dist/logger.js.map +1 -1
- package/package.json +8 -31
- package/src/CItemRouter.ts +14 -7
- package/src/ItemRouter.ts +64 -55
- package/src/PItemRouter.ts +14 -8
package/src/ItemRouter.ts
CHANGED
|
@@ -11,25 +11,11 @@ import {
|
|
|
11
11
|
} from "@fjell/core";
|
|
12
12
|
import { NotFoundError, Operations } from "@fjell/lib";
|
|
13
13
|
import deepmerge from "deepmerge";
|
|
14
|
-
import { Request,
|
|
14
|
+
import { Request, Response, Router } from "express";
|
|
15
15
|
import LibLogger from "./logger";
|
|
16
16
|
|
|
17
17
|
export type ItemRouterOptions = Record<string, never>;
|
|
18
18
|
|
|
19
|
-
// TODO: body is in the request, it's not needed in the parameters
|
|
20
|
-
export type ActionMethod = <
|
|
21
|
-
S extends string,
|
|
22
|
-
L1 extends string = never,
|
|
23
|
-
L2 extends string = never,
|
|
24
|
-
L3 extends string = never,
|
|
25
|
-
L4 extends string = never,
|
|
26
|
-
L5 extends string = never
|
|
27
|
-
>(req: Request, res: Response, item: Item<S, L1, L2, L3, L4, L5>, params: any, body: any) =>
|
|
28
|
-
Promise<Item<S, L1, L2, L3, L4, L5>>;
|
|
29
|
-
|
|
30
|
-
// TODO: body is in the request, it's not needed in the parameters
|
|
31
|
-
export type AllActionMethods = Array<RequestHandler>;
|
|
32
|
-
|
|
33
19
|
export class ItemRouter<
|
|
34
20
|
S extends string,
|
|
35
21
|
L1 extends string = never,
|
|
@@ -44,7 +30,6 @@ export class ItemRouter<
|
|
|
44
30
|
protected options: ItemRouterOptions;
|
|
45
31
|
private childRouters: Record<string, Router> = {};
|
|
46
32
|
private logger;
|
|
47
|
-
private itemActions: Record<string, ActionMethod> | undefined;
|
|
48
33
|
|
|
49
34
|
constructor(
|
|
50
35
|
lib: Operations<Item<S, L1, L2, L3, L4, L5>, S, L1, L2, L3, L4, L5>,
|
|
@@ -94,17 +79,45 @@ export class ItemRouter<
|
|
|
94
79
|
this.logger.default('Getting Item', { query: req?.query, params: req?.params, locals: res?.locals });
|
|
95
80
|
const ik = this.getIk(res);
|
|
96
81
|
const actionKey = req.path.substring(req.path.lastIndexOf('/') + 1);
|
|
97
|
-
if (!this.
|
|
82
|
+
if (!this.lib.actions) {
|
|
98
83
|
this.logger.error('Item Actions are not configured');
|
|
99
|
-
|
|
84
|
+
res.status(500).json({ error: 'Item Actions are not configured' });
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const action = this.lib.actions[actionKey];
|
|
88
|
+
if (!action) {
|
|
89
|
+
this.logger.error('Item Action is not configured', { actionKey });
|
|
90
|
+
res.status(500).json({ error: 'Item Action is not configured' });
|
|
91
|
+
return;
|
|
100
92
|
}
|
|
101
93
|
try {
|
|
102
|
-
|
|
103
|
-
validatePK(await this.lib.get(ik), this.getPkType()) as Item<S, L1, L2, L3, L4, L5>;
|
|
104
|
-
return res.json(await this.itemActions[actionKey](req, res, item, req.params, req.body));
|
|
94
|
+
res.json(await this.lib.action(ik, actionKey, req.body));
|
|
105
95
|
} catch (err: any) {
|
|
106
96
|
this.logger.error('Error in Item Action', { message: err?.message, stack: err?.stack });
|
|
107
|
-
|
|
97
|
+
res.status(500).json(err);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
protected getItemFacet = async (req: Request, res: Response) => {
|
|
102
|
+
this.logger.default('Getting Item', { query: req?.query, params: req?.params, locals: res?.locals });
|
|
103
|
+
const ik = this.getIk(res);
|
|
104
|
+
const facetKey = req.path.substring(req.path.lastIndexOf('/') + 1);
|
|
105
|
+
if (!this.lib.facets) {
|
|
106
|
+
this.logger.error('Item Facets are not configured');
|
|
107
|
+
res.status(500).json({ error: 'Item Facets are not configured' });
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const facet = this.lib.facets[facetKey];
|
|
111
|
+
if (!facet) {
|
|
112
|
+
this.logger.error('Item Facet is not configured', { facetKey });
|
|
113
|
+
res.status(500).json({ error: 'Item Facet is not configured' });
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
res.json(await this.lib.facet(ik, facetKey, req.params));
|
|
118
|
+
} catch (err: any) {
|
|
119
|
+
this.logger.error('Error in Item Facet', { message: err?.message, stack: err?.stack });
|
|
120
|
+
res.status(500).json(err);
|
|
108
121
|
}
|
|
109
122
|
}
|
|
110
123
|
|
|
@@ -113,31 +126,39 @@ export class ItemRouter<
|
|
|
113
126
|
router.get('/', this.findItems);
|
|
114
127
|
router.post('/', this.createItem);
|
|
115
128
|
|
|
116
|
-
const allActions = this.configureAllActions();
|
|
117
|
-
this.logger.debug('All Actions supplied to Router', { allActions });
|
|
118
|
-
if (allActions) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
129
|
+
// const allActions = this.configureAllActions();
|
|
130
|
+
// this.logger.debug('All Actions supplied to Router', { allActions });
|
|
131
|
+
// if (allActions) {
|
|
132
|
+
// Object.keys(allActions).forEach((actionKey) => {
|
|
133
|
+
// this.logger.default('Configuring All Action', { actionKey });
|
|
134
|
+
// // TODO: Ok, this is a bit of a hack, but we need to customize the types of the request handlers
|
|
135
|
+
// router.post(`/${actionKey}`, ...allActions[actionKey]);
|
|
136
|
+
// });
|
|
137
|
+
// }
|
|
125
138
|
|
|
126
139
|
const itemRouter = Router();
|
|
127
140
|
itemRouter.get('/', this.getItem);
|
|
128
141
|
itemRouter.put('/', this.updateItem);
|
|
129
142
|
itemRouter.delete('/', this.deleteItem);
|
|
130
143
|
|
|
131
|
-
this.itemActions
|
|
132
|
-
this.
|
|
133
|
-
|
|
134
|
-
Object.keys(this.itemActions).forEach((actionKey) => {
|
|
144
|
+
this.logger.debug('Item Actions supplied to Router', { itemActions: this.lib.actions });
|
|
145
|
+
if (this.lib.actions) {
|
|
146
|
+
Object.keys(this.lib.actions).forEach((actionKey) => {
|
|
135
147
|
this.logger.default('Configuring Item Action', { actionKey });
|
|
136
148
|
// TODO: Ok, this is a bit of a hack, but we need to customize the types of the request handlers
|
|
137
149
|
itemRouter.post(`/${actionKey}`, this.postItemAction)
|
|
138
150
|
});
|
|
139
151
|
}
|
|
140
152
|
|
|
153
|
+
this.logger.debug('Item Facets supplied to Router', { itemFacets: this.lib.facets });
|
|
154
|
+
if (this.lib.facets) {
|
|
155
|
+
Object.keys(this.lib.facets).forEach((facetKey) => {
|
|
156
|
+
this.logger.default('Configuring Item Facet', { facetKey });
|
|
157
|
+
// TODO: Ok, this is a bit of a hack, but we need to customize the types of the request handlers
|
|
158
|
+
itemRouter.get(`/${facetKey}`, this.getItemFacet)
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
141
162
|
this.logger.default('Configuring Item Operations under PK Param', { pkParam: this.getPkParam() });
|
|
142
163
|
router.use(`/:${this.getPkParam()}`, this.validatePrimaryKeyValue, itemRouter);
|
|
143
164
|
|
|
@@ -171,18 +192,6 @@ export class ItemRouter<
|
|
|
171
192
|
this.childRouters[path] = router;
|
|
172
193
|
}
|
|
173
194
|
|
|
174
|
-
/* istanbul ignore next */
|
|
175
|
-
protected configureItemActions(): Record<string, ActionMethod> {
|
|
176
|
-
this.logger.debug('ARouter - No Item Actions Configured');
|
|
177
|
-
return {};
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/* istanbul ignore next */
|
|
181
|
-
protected configureAllActions(): Record<string, AllActionMethods> {
|
|
182
|
-
this.logger.debug('ARouter - No All Actions Configured');
|
|
183
|
-
return {};
|
|
184
|
-
}
|
|
185
|
-
|
|
186
195
|
/* istanbul ignore next */
|
|
187
196
|
public getRouter(): Router {
|
|
188
197
|
const router = Router();
|
|
@@ -192,7 +201,7 @@ export class ItemRouter<
|
|
|
192
201
|
|
|
193
202
|
/* istanbul ignore next */
|
|
194
203
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
195
|
-
protected createItem = async (req: Request, res: Response): Promise<
|
|
204
|
+
protected createItem = async (req: Request, res: Response): Promise<void> => {
|
|
196
205
|
throw new Error('Method not implemented in an abstract router');
|
|
197
206
|
};
|
|
198
207
|
|
|
@@ -203,17 +212,17 @@ export class ItemRouter<
|
|
|
203
212
|
return item;
|
|
204
213
|
};
|
|
205
214
|
|
|
206
|
-
protected deleteItem = async (req: Request, res: Response): Promise<
|
|
215
|
+
protected deleteItem = async (req: Request, res: Response): Promise<void> => {
|
|
207
216
|
this.logger.default('Deleting Item', { query: req.query, params: req.params, locals: res.locals });
|
|
208
217
|
const ik = this.getIk(res);
|
|
209
218
|
const removedItem = await this.lib.remove(ik);
|
|
210
219
|
const item = validatePK(removedItem, this.getPkType());
|
|
211
|
-
|
|
220
|
+
res.json(item);
|
|
212
221
|
};
|
|
213
222
|
|
|
214
223
|
/* eslint-disable */
|
|
215
224
|
/* istanbul ignore next */
|
|
216
|
-
protected findItems = async (req: Request, res: Response): Promise<
|
|
225
|
+
protected findItems = async (req: Request, res: Response): Promise<void> => {
|
|
217
226
|
throw new Error('Method not implemented in an abstract router');
|
|
218
227
|
};
|
|
219
228
|
/* eslint-enable */
|
|
@@ -224,17 +233,17 @@ export class ItemRouter<
|
|
|
224
233
|
try {
|
|
225
234
|
// TODO: What error does validate PK throw, when can that fail?
|
|
226
235
|
const item = validatePK(await this.lib.get(ik), this.getPkType());
|
|
227
|
-
|
|
236
|
+
res.json(item);
|
|
228
237
|
} catch (err: any) {
|
|
229
238
|
if (err instanceof NotFoundError) {
|
|
230
239
|
this.logger.error('Item Not Found', { ik, message: err?.message, stack: err?.stack });
|
|
231
|
-
|
|
240
|
+
res.status(404).json({
|
|
232
241
|
ik,
|
|
233
242
|
message: "Item Not Found",
|
|
234
243
|
});
|
|
235
244
|
} else {
|
|
236
245
|
this.logger.error('General Error', { ik, message: err?.message, stack: err?.stack });
|
|
237
|
-
|
|
246
|
+
res.status(500).json({
|
|
238
247
|
ik,
|
|
239
248
|
message: "General Error",
|
|
240
249
|
});
|
|
@@ -248,7 +257,7 @@ export class ItemRouter<
|
|
|
248
257
|
const ik = this.getIk(res);
|
|
249
258
|
const itemToUpdate = this.convertDates(req.body as ItemProperties<S, L1, L2, L3, L4, L5>);
|
|
250
259
|
const retItem = validatePK(await this.lib.update(ik, itemToUpdate), this.getPkType());
|
|
251
|
-
|
|
260
|
+
res.json(retItem);
|
|
252
261
|
};
|
|
253
262
|
|
|
254
263
|
public convertDates = (item: Item<S, L1, L2, L3, L4, L5> | ItemProperties<S, L1, L2, L3, L4, L5>):
|
package/src/PItemRouter.ts
CHANGED
|
@@ -13,7 +13,7 @@ interface ParsedQuery {
|
|
|
13
13
|
export class PItemRouter<T extends Item<S>, S extends string> extends ItemRouter<S> {
|
|
14
14
|
|
|
15
15
|
constructor(lib: Primary.Operations<T, S>, keyType: S, options: ItemRouterOptions = {}) {
|
|
16
|
-
super(lib, keyType, options);
|
|
16
|
+
super(lib as any, keyType, options);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
public getIk(res: Response): PriKey<S> {
|
|
@@ -27,10 +27,9 @@ export class PItemRouter<T extends Item<S>, S extends string> extends ItemRouter
|
|
|
27
27
|
let item =
|
|
28
28
|
validatePK(await this.lib.create(itemToCreate), this.getPkType()) as Item<S>;
|
|
29
29
|
item = await this.postCreateItem(item);
|
|
30
|
-
|
|
30
|
+
res.json(item);
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
/* eslint-disable */
|
|
34
33
|
protected findItems = async (req: Request, res: Response) => {
|
|
35
34
|
logger.default('Finding Items', { query: req.query, params: req.params, locals: res.locals });
|
|
36
35
|
|
|
@@ -39,11 +38,18 @@ export class PItemRouter<T extends Item<S>, S extends string> extends ItemRouter
|
|
|
39
38
|
const query: ParsedQuery = req.query as unknown as ParsedQuery;
|
|
40
39
|
const finder = query['finder'] as string;
|
|
41
40
|
const finderParams = query['finderParams'] as string;
|
|
41
|
+
const one = query['one'] as string;
|
|
42
42
|
|
|
43
|
-
if(
|
|
43
|
+
if (finder) {
|
|
44
44
|
// If finder is defined? Call a finder.
|
|
45
|
-
logger.default('Finding Items with a finder', { finder, finderParams });
|
|
46
|
-
|
|
45
|
+
logger.default('Finding Items with a finder', { finder, finderParams, one });
|
|
46
|
+
|
|
47
|
+
if (one === 'true') {
|
|
48
|
+
const item = await (this.lib as any).findOne(finder, JSON.parse(finderParams));
|
|
49
|
+
items = item ? [item] : [];
|
|
50
|
+
} else {
|
|
51
|
+
items = await this.lib.find(finder, JSON.parse(finderParams));
|
|
52
|
+
}
|
|
47
53
|
} else {
|
|
48
54
|
logger.default('Finding Items with a query', { query: req.query });
|
|
49
55
|
// TODO: This is once of the more important places to perform some validaation and feedback
|
|
@@ -51,7 +57,7 @@ export class PItemRouter<T extends Item<S>, S extends string> extends ItemRouter
|
|
|
51
57
|
items = await this.lib.all(itemQuery);
|
|
52
58
|
}
|
|
53
59
|
|
|
54
|
-
|
|
60
|
+
res.json(items.map((item: Item<S>) => validatePK(item, this.getPkType())));
|
|
55
61
|
};
|
|
56
|
-
|
|
62
|
+
|
|
57
63
|
}
|