axe-api 0.17.5 → 0.18.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/CHANGELOG.md +13 -0
- package/package.json +1 -1
- package/src/constants.js +10 -10
- package/src/core/QueryParser.js +59 -62
- package/src/handlers/autosave.js +10 -2
- package/src/handlers/destroy.js +3 -1
- package/src/handlers/helpers.js +39 -30
- package/src/handlers/paginate.js +15 -2
- package/src/handlers/show.js +18 -3
- package/src/handlers/store.js +6 -1
- package/src/handlers/update.js +9 -2
- package/src/resolvers/setExpressRoutes.js +12 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Release Notes
|
|
2
2
|
|
|
3
|
+
## [0.18.0 (2021-11-30)](https://github.com/axe-api/axe-api/compare/0.18.0...0.17.5)
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- [#115](https://github.com/axe-api/axe-api/issues/115)
|
|
8
|
+
- [#114](https://github.com/axe-api/axe-api/issues/114)
|
|
9
|
+
|
|
10
|
+
### Enhancements
|
|
11
|
+
|
|
12
|
+
- [#113](https://github.com/axe-api/axe-api/issues/113)
|
|
13
|
+
- [#107](https://github.com/axe-api/axe-api/issues/107)
|
|
14
|
+
- [#108](https://github.com/axe-api/axe-api/issues/108)
|
|
15
|
+
|
|
3
16
|
## [0.17.5 (2021-11-27)](https://github.com/axe-api/axe-api/compare/0.17.5...0.17.4)
|
|
4
17
|
|
|
5
18
|
### Fixed
|
package/package.json
CHANGED
package/src/constants.js
CHANGED
|
@@ -72,31 +72,31 @@ const HTTP_METHODS = {
|
|
|
72
72
|
|
|
73
73
|
const API_ROUTE_TEMPLATES = {
|
|
74
74
|
[HANDLERS.INSERT]: {
|
|
75
|
-
url: (parentUrl, resource) =>
|
|
75
|
+
url: (prefix, parentUrl, resource) => `/${prefix}/${parentUrl}${resource}`,
|
|
76
76
|
method: HTTP_METHODS.POST,
|
|
77
77
|
},
|
|
78
78
|
[HANDLERS.PAGINATE]: {
|
|
79
|
-
url: (parentUrl, resource) =>
|
|
79
|
+
url: (prefix, parentUrl, resource) => `/${prefix}/${parentUrl}${resource}`,
|
|
80
80
|
method: HTTP_METHODS.GET,
|
|
81
81
|
},
|
|
82
82
|
[HANDLERS.SHOW]: {
|
|
83
|
-
url: (parentUrl, resource, primaryKey) =>
|
|
84
|
-
|
|
83
|
+
url: (prefix, parentUrl, resource, primaryKey) =>
|
|
84
|
+
`/${prefix}/${parentUrl}${resource}/:${primaryKey}`,
|
|
85
85
|
method: HTTP_METHODS.GET,
|
|
86
86
|
},
|
|
87
87
|
[HANDLERS.UPDATE]: {
|
|
88
|
-
url: (parentUrl, resource, primaryKey) =>
|
|
89
|
-
|
|
88
|
+
url: (prefix, parentUrl, resource, primaryKey) =>
|
|
89
|
+
`/${prefix}/${parentUrl}${resource}/:${primaryKey}`,
|
|
90
90
|
method: HTTP_METHODS.PUT,
|
|
91
91
|
},
|
|
92
92
|
[HANDLERS.AUTOSAVE]: {
|
|
93
|
-
url: (parentUrl, resource, primaryKey) =>
|
|
94
|
-
|
|
93
|
+
url: (prefix, parentUrl, resource, primaryKey) =>
|
|
94
|
+
`/${prefix}/${parentUrl}${resource}/:${primaryKey}/autosave`,
|
|
95
95
|
method: HTTP_METHODS.PUT,
|
|
96
96
|
},
|
|
97
97
|
[HANDLERS.DELETE]: {
|
|
98
|
-
url: (parentUrl, resource, primaryKey) =>
|
|
99
|
-
|
|
98
|
+
url: (prefix, parentUrl, resource, primaryKey) =>
|
|
99
|
+
`/${prefix}/${parentUrl}${resource}/:${primaryKey}`,
|
|
100
100
|
method: HTTP_METHODS.DELETE,
|
|
101
101
|
},
|
|
102
102
|
};
|
package/src/core/QueryParser.js
CHANGED
|
@@ -1,31 +1,13 @@
|
|
|
1
1
|
import HttpResponse from "./../core/HttpResponse.js";
|
|
2
2
|
import { RELATIONSHIPS } from "../constants.js";
|
|
3
3
|
|
|
4
|
-
const DEFAULT_OPTIONS = {
|
|
5
|
-
min_per_page: 1,
|
|
6
|
-
max_per_page: 1000,
|
|
7
|
-
};
|
|
8
|
-
|
|
9
4
|
class QueryParser {
|
|
10
|
-
constructor({ model, models
|
|
5
|
+
constructor({ model, models }) {
|
|
11
6
|
this.model = model;
|
|
12
7
|
this.models = models;
|
|
13
8
|
this.createdJoins = [];
|
|
14
9
|
this.relationColumns = [];
|
|
15
10
|
this.usedConditionColumns = new Set();
|
|
16
|
-
this.options = { ...DEFAULT_OPTIONS, ...options };
|
|
17
|
-
|
|
18
|
-
if (isNaN(this.options.min_per_page) || this.options.min_per_page < 1) {
|
|
19
|
-
throw new Error(
|
|
20
|
-
`You set unacceptable query parse option (min_per_page): ${this.options.min_per_page}`
|
|
21
|
-
);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (isNaN(this.options.max_per_page) || this.options.max_per_page > 10000) {
|
|
25
|
-
throw new Error(
|
|
26
|
-
`You set unacceptable query parse option (max_per_page): ${this.options.max_per_page}`
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
11
|
}
|
|
30
12
|
|
|
31
13
|
applyFields(query, fields) {
|
|
@@ -109,10 +91,9 @@ class QueryParser {
|
|
|
109
91
|
});
|
|
110
92
|
|
|
111
93
|
if (undefinedColumns.length > 0) {
|
|
112
|
-
throw new HttpResponse(
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
);
|
|
94
|
+
throw new HttpResponse(400, {
|
|
95
|
+
message: `Undefined column names: ${undefinedColumns.join(",")}`,
|
|
96
|
+
});
|
|
116
97
|
}
|
|
117
98
|
|
|
118
99
|
return conditions;
|
|
@@ -215,7 +196,9 @@ class QueryParser {
|
|
|
215
196
|
try {
|
|
216
197
|
sections.q = JSON.parse(queryContent);
|
|
217
198
|
} catch (err) {
|
|
218
|
-
throw new
|
|
199
|
+
throw new HttpResponse(400, {
|
|
200
|
+
message: `Unacceptable query string: ${queryContent}`,
|
|
201
|
+
});
|
|
219
202
|
}
|
|
220
203
|
}
|
|
221
204
|
|
|
@@ -247,16 +230,8 @@ class QueryParser {
|
|
|
247
230
|
_parsePerPage(content) {
|
|
248
231
|
const value = parseInt(content);
|
|
249
232
|
|
|
250
|
-
if (isNaN(value)) {
|
|
251
|
-
return
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
if (value <= this.options.min_per_page) {
|
|
255
|
-
return this.options.min_per_page;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
if (value > this.options.max_per_page) {
|
|
259
|
-
return this.options.max_per_page;
|
|
233
|
+
if (isNaN(value) || value <= 1 || value > 10000) {
|
|
234
|
+
return 10;
|
|
260
235
|
}
|
|
261
236
|
|
|
262
237
|
return value;
|
|
@@ -325,19 +300,24 @@ class QueryParser {
|
|
|
325
300
|
return null;
|
|
326
301
|
}
|
|
327
302
|
|
|
303
|
+
const wheres = [];
|
|
304
|
+
for (const key in content) {
|
|
305
|
+
wheres.push(this._parseConditionObject(content, key));
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return wheres;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
_parseConditionObject(content, key) {
|
|
328
312
|
const where = {
|
|
329
313
|
prefix: null,
|
|
330
314
|
model: this.model,
|
|
331
315
|
table: this.model.instance.table,
|
|
332
|
-
field:
|
|
316
|
+
field: key,
|
|
333
317
|
condition: "=",
|
|
334
|
-
value:
|
|
318
|
+
value: content[key],
|
|
335
319
|
};
|
|
336
320
|
|
|
337
|
-
const key = Object.keys(content)[0];
|
|
338
|
-
where.field = key;
|
|
339
|
-
where.value = content[key];
|
|
340
|
-
|
|
341
321
|
// Sometimes we can have basic OR operations for queries
|
|
342
322
|
if (where.field.indexOf("$or.") === 0) {
|
|
343
323
|
where.prefix = "or";
|
|
@@ -349,19 +329,30 @@ class QueryParser {
|
|
|
349
329
|
where.field = where.field.replace("$and.", "");
|
|
350
330
|
}
|
|
351
331
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
332
|
+
// If there is not any value, it means that we should check nullable values
|
|
333
|
+
if (where.value === null) {
|
|
334
|
+
// If the client wants to see not nullable values
|
|
335
|
+
if (this._hasSpecialStructure(where.field, ".$not")) {
|
|
336
|
+
where.field = where.field.replace(".$not", "");
|
|
337
|
+
where.condition = "NotNull";
|
|
338
|
+
} else {
|
|
339
|
+
// So, it means that the clients wants to see null valus
|
|
340
|
+
where.condition = "Null";
|
|
341
|
+
}
|
|
342
|
+
} else {
|
|
343
|
+
// If there is value, we should check it
|
|
344
|
+
this._applySpecialCondition(where, "$not", "<>");
|
|
345
|
+
this._applySpecialCondition(where, "$gt", ">");
|
|
346
|
+
this._applySpecialCondition(where, "$gte", ">=");
|
|
347
|
+
this._applySpecialCondition(where, "$lt", "<");
|
|
348
|
+
this._applySpecialCondition(where, "$lte", "<=");
|
|
349
|
+
this._applySpecialCondition(where, "$like", "LIKE");
|
|
350
|
+
this._applySpecialCondition(where, "$notLike", "NOT LIKE");
|
|
351
|
+
this._applySpecialCondition(where, "$in", "In");
|
|
352
|
+
this._applySpecialCondition(where, "$notIn", "NotIn");
|
|
353
|
+
this._applySpecialCondition(where, "$between", "Between");
|
|
354
|
+
this._applySpecialCondition(where, "$notBetween", "NotBetween");
|
|
355
|
+
}
|
|
365
356
|
|
|
366
357
|
if (where.condition === "In" || where.condition === "NotIn") {
|
|
367
358
|
where.value = where.value.split(",");
|
|
@@ -371,10 +362,6 @@ class QueryParser {
|
|
|
371
362
|
where.value = where.value.split(":");
|
|
372
363
|
}
|
|
373
364
|
|
|
374
|
-
if (where.condition === "Null" || where.condition === "NotNull") {
|
|
375
|
-
where.value = null;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
365
|
if (where.condition === "LIKE" || where.condition === "NOT LIKE") {
|
|
379
366
|
where.value = where.value.replace(/\*/g, "%");
|
|
380
367
|
}
|
|
@@ -389,7 +376,9 @@ class QueryParser {
|
|
|
389
376
|
);
|
|
390
377
|
|
|
391
378
|
if (!relation) {
|
|
392
|
-
throw new
|
|
379
|
+
throw new HttpResponse(400, {
|
|
380
|
+
message: `Unacceptable query field: ${relationName}.${field}`,
|
|
381
|
+
});
|
|
393
382
|
}
|
|
394
383
|
|
|
395
384
|
const relatedModel = this.models.find(
|
|
@@ -397,7 +386,9 @@ class QueryParser {
|
|
|
397
386
|
);
|
|
398
387
|
|
|
399
388
|
if (!relatedModel) {
|
|
400
|
-
throw new
|
|
389
|
+
throw new HttpResponse(400, {
|
|
390
|
+
message: `Undefined model name: ${relation.model}`,
|
|
391
|
+
});
|
|
401
392
|
}
|
|
402
393
|
|
|
403
394
|
where.model = relatedModel;
|
|
@@ -504,7 +495,9 @@ class QueryParser {
|
|
|
504
495
|
(i) => i.name === item.relationship
|
|
505
496
|
);
|
|
506
497
|
if (!relation) {
|
|
507
|
-
throw new
|
|
498
|
+
throw new HttpResponse(400, {
|
|
499
|
+
message: `Undefined relation: ${item.relationship}`,
|
|
500
|
+
});
|
|
508
501
|
}
|
|
509
502
|
|
|
510
503
|
this.relationColumns.push(
|
|
@@ -535,11 +528,15 @@ class QueryParser {
|
|
|
535
528
|
_shouldBeAcceptableColumn(field) {
|
|
536
529
|
const regex = /^[0-9,a-z,A-Z_.]+$/;
|
|
537
530
|
if (!field.match(regex)) {
|
|
538
|
-
throw new
|
|
531
|
+
throw new HttpResponse(400, {
|
|
532
|
+
message: `Unacceptable field name: ${field}`,
|
|
533
|
+
});
|
|
539
534
|
}
|
|
540
535
|
|
|
541
536
|
if (field.indexOf(".") === 0 || field.indexOf(".") === field.length - 1) {
|
|
542
|
-
throw new
|
|
537
|
+
throw new HttpResponse(400, {
|
|
538
|
+
message: `You have to define the column specefically: ${field}`,
|
|
539
|
+
});
|
|
543
540
|
}
|
|
544
541
|
}
|
|
545
542
|
}
|
package/src/handlers/autosave.js
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
import Validator from "validatorjs";
|
|
12
12
|
import { HOOK_FUNCTIONS, TIMESTAMP_COLUMNS } from "./../constants.js";
|
|
13
13
|
import HttpResponse from "./../core/HttpResponse.js";
|
|
14
|
+
import { HANDLERS } from "./../constants.js";
|
|
14
15
|
|
|
15
16
|
export default async (context) => {
|
|
16
17
|
const { request, response, model, trx, relation, parentModel } = context;
|
|
@@ -29,7 +30,9 @@ export default async (context) => {
|
|
|
29
30
|
.where(model.instance.primaryKey, request.params[model.instance.primaryKey])
|
|
30
31
|
.first();
|
|
31
32
|
if (!item) {
|
|
32
|
-
throw new HttpResponse(404,
|
|
33
|
+
throw new HttpResponse(404, {
|
|
34
|
+
message: `The item is not found on ${model.name}.`,
|
|
35
|
+
});
|
|
33
36
|
}
|
|
34
37
|
|
|
35
38
|
await callHooks(model, HOOK_FUNCTIONS.onAfterUpdateQuery, {
|
|
@@ -78,7 +81,12 @@ export default async (context) => {
|
|
|
78
81
|
});
|
|
79
82
|
|
|
80
83
|
// Serializing the data by the model's serialize method
|
|
81
|
-
item = await serializeData(
|
|
84
|
+
item = await serializeData(
|
|
85
|
+
item,
|
|
86
|
+
model.instance.serialize,
|
|
87
|
+
HANDLERS.AUTOSAVE,
|
|
88
|
+
request
|
|
89
|
+
);
|
|
82
90
|
|
|
83
91
|
// Filtering hidden fields from the response data.
|
|
84
92
|
filterHiddenFields([item], model.instance.hiddens);
|
package/src/handlers/destroy.js
CHANGED
|
@@ -22,7 +22,9 @@ export default async (context) => {
|
|
|
22
22
|
|
|
23
23
|
let item = await query.first();
|
|
24
24
|
if (!item) {
|
|
25
|
-
throw new HttpResponse(404,
|
|
25
|
+
throw new HttpResponse(404, {
|
|
26
|
+
message: `The item is not found on ${model.name}.`,
|
|
27
|
+
});
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
await callHooks(model, HOOK_FUNCTIONS.onAfterDeleteQuery, {
|
package/src/handlers/helpers.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { RELATIONSHIPS } from "./../constants.js";
|
|
2
2
|
import { camelCase } from "change-case";
|
|
3
3
|
import HttpResponse from "./../core/HttpResponse.js";
|
|
4
|
-
import IoC from
|
|
4
|
+
import IoC from "../core/IoC.js";
|
|
5
5
|
|
|
6
6
|
const getInputFromBody = (body, field) => {
|
|
7
7
|
if (!body) {
|
|
@@ -83,7 +83,8 @@ export const getRelatedData = async (
|
|
|
83
83
|
model,
|
|
84
84
|
models,
|
|
85
85
|
database,
|
|
86
|
-
handler
|
|
86
|
+
handler,
|
|
87
|
+
request
|
|
87
88
|
) => {
|
|
88
89
|
if (withArray.length === 0) {
|
|
89
90
|
return;
|
|
@@ -96,10 +97,9 @@ export const getRelatedData = async (
|
|
|
96
97
|
(relation) => relation.name === clientQuery.relationship
|
|
97
98
|
);
|
|
98
99
|
if (!definedRelation) {
|
|
99
|
-
throw new HttpResponse(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
);
|
|
100
|
+
throw new HttpResponse(400, {
|
|
101
|
+
message: `Undefined relation: ${clientQuery.relationship}`,
|
|
102
|
+
});
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
// Find the foreign model by the relationship
|
|
@@ -164,10 +164,9 @@ export const getRelatedData = async (
|
|
|
164
164
|
(column) => !foreignModel.instance.columnNames.includes(column)
|
|
165
165
|
);
|
|
166
166
|
if (undefinedColumns.length > 0) {
|
|
167
|
-
throw new HttpResponse(
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
);
|
|
167
|
+
throw new HttpResponse(400, {
|
|
168
|
+
message: `Undefined columns: ${undefinedColumns.join(", ")}`,
|
|
169
|
+
});
|
|
171
170
|
}
|
|
172
171
|
}
|
|
173
172
|
|
|
@@ -189,7 +188,8 @@ export const getRelatedData = async (
|
|
|
189
188
|
relatedRecords = await serializeData(
|
|
190
189
|
relatedRecords,
|
|
191
190
|
foreignModel.instance.serialize,
|
|
192
|
-
handler
|
|
191
|
+
handler,
|
|
192
|
+
request
|
|
193
193
|
);
|
|
194
194
|
|
|
195
195
|
// We should hide hidden fields if there is any
|
|
@@ -203,7 +203,8 @@ export const getRelatedData = async (
|
|
|
203
203
|
foreignModel,
|
|
204
204
|
models,
|
|
205
205
|
database,
|
|
206
|
-
handler
|
|
206
|
+
handler,
|
|
207
|
+
request
|
|
207
208
|
);
|
|
208
209
|
}
|
|
209
210
|
|
|
@@ -243,19 +244,19 @@ export const bindTimestampValues = (formData, columnTypes = [], model) => {
|
|
|
243
244
|
}
|
|
244
245
|
};
|
|
245
246
|
|
|
246
|
-
const serialize = async (data, callback) => {
|
|
247
|
+
const serialize = async (data, callback, request) => {
|
|
247
248
|
if (!callback) {
|
|
248
249
|
return data;
|
|
249
250
|
}
|
|
250
251
|
|
|
251
252
|
if (Array.isArray(data)) {
|
|
252
|
-
return data.map(callback);
|
|
253
|
+
return data.map((item) => callback(item, request));
|
|
253
254
|
}
|
|
254
255
|
|
|
255
|
-
return
|
|
256
|
-
}
|
|
256
|
+
return callback(data, request);
|
|
257
|
+
};
|
|
257
258
|
|
|
258
|
-
const globalSerializer = async (itemArray, handler) => {
|
|
259
|
+
const globalSerializer = async (itemArray, handler, request) => {
|
|
259
260
|
const { Application } = await IoC.use("Config");
|
|
260
261
|
|
|
261
262
|
if (!Application.serializers) {
|
|
@@ -263,35 +264,43 @@ const globalSerializer = async (itemArray, handler) => {
|
|
|
263
264
|
}
|
|
264
265
|
|
|
265
266
|
let callbacks = [];
|
|
266
|
-
// Push all runable serializer into callbacks.
|
|
267
|
-
Application.serializers.map(configSerializer => {
|
|
267
|
+
// Push all runable serializer into callbacks.
|
|
268
|
+
Application.serializers.map((configSerializer) => {
|
|
268
269
|
// Serialize data for all requests types.
|
|
269
270
|
if (typeof configSerializer === "function") {
|
|
270
271
|
callbacks.push(configSerializer);
|
|
271
|
-
return
|
|
272
|
+
return;
|
|
272
273
|
}
|
|
273
274
|
|
|
274
275
|
// Serialize data with specific handler like "PAGINATE" or "SHOW".
|
|
275
|
-
if (
|
|
276
|
+
if (
|
|
277
|
+
typeof configSerializer === "object" &&
|
|
278
|
+
configSerializer.handler.includes(handler)
|
|
279
|
+
) {
|
|
276
280
|
// Handle multiple serializer.
|
|
277
281
|
if (Array.isArray(configSerializer.serializer)) {
|
|
278
|
-
configSerializer.serializer.forEach(fn => callbacks.push(fn));
|
|
279
|
-
return
|
|
282
|
+
configSerializer.serializer.forEach((fn) => callbacks.push(fn));
|
|
283
|
+
return;
|
|
280
284
|
}
|
|
281
|
-
callbacks.push(configSerializer.serializer)
|
|
282
|
-
return
|
|
285
|
+
callbacks.push(configSerializer.serializer);
|
|
286
|
+
return;
|
|
283
287
|
}
|
|
284
|
-
})
|
|
288
|
+
});
|
|
285
289
|
|
|
286
290
|
while (callbacks.length !== 0) {
|
|
287
|
-
itemArray =
|
|
291
|
+
itemArray = serialize(itemArray, callbacks.shift(), request);
|
|
288
292
|
}
|
|
289
293
|
return itemArray;
|
|
290
294
|
};
|
|
291
295
|
|
|
292
|
-
export const serializeData = async (
|
|
293
|
-
itemArray
|
|
294
|
-
|
|
296
|
+
export const serializeData = async (
|
|
297
|
+
itemArray,
|
|
298
|
+
modelSerializer,
|
|
299
|
+
handler,
|
|
300
|
+
request
|
|
301
|
+
) => {
|
|
302
|
+
itemArray = serialize(itemArray, modelSerializer, request);
|
|
303
|
+
itemArray = await globalSerializer(itemArray, handler, request);
|
|
295
304
|
return itemArray;
|
|
296
305
|
};
|
|
297
306
|
|
package/src/handlers/paginate.js
CHANGED
|
@@ -45,7 +45,15 @@ export default async (context) => {
|
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
// We should try to get related data if there is any
|
|
48
|
-
await getRelatedData(
|
|
48
|
+
await getRelatedData(
|
|
49
|
+
result.data,
|
|
50
|
+
conditions.with,
|
|
51
|
+
model,
|
|
52
|
+
models,
|
|
53
|
+
trx,
|
|
54
|
+
HANDLERS.PAGINATE,
|
|
55
|
+
request
|
|
56
|
+
);
|
|
49
57
|
|
|
50
58
|
await callHooks(model, HOOK_FUNCTIONS.onAfterPaginate, {
|
|
51
59
|
...context,
|
|
@@ -55,7 +63,12 @@ export default async (context) => {
|
|
|
55
63
|
});
|
|
56
64
|
|
|
57
65
|
// Serializing the data by the model's serialize method
|
|
58
|
-
result.data = await serializeData(
|
|
66
|
+
result.data = await serializeData(
|
|
67
|
+
result.data,
|
|
68
|
+
model.instance.serialize,
|
|
69
|
+
HANDLERS.PAGINATE,
|
|
70
|
+
request
|
|
71
|
+
);
|
|
59
72
|
|
|
60
73
|
// Filtering hidden fields from the response data.
|
|
61
74
|
filterHiddenFields(result.data, model.instance.hiddens);
|
package/src/handlers/show.js
CHANGED
|
@@ -43,11 +43,21 @@ export default async (context) => {
|
|
|
43
43
|
|
|
44
44
|
let item = await query.first();
|
|
45
45
|
if (!item) {
|
|
46
|
-
throw new HttpResponse(404,
|
|
46
|
+
throw new HttpResponse(404, {
|
|
47
|
+
message: `The item is not found on ${model.name}.`,
|
|
48
|
+
});
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
// We should try to get related data if there is any
|
|
50
|
-
await getRelatedData(
|
|
52
|
+
await getRelatedData(
|
|
53
|
+
[item],
|
|
54
|
+
conditions.with,
|
|
55
|
+
model,
|
|
56
|
+
models,
|
|
57
|
+
trx,
|
|
58
|
+
HANDLERS.SHOW,
|
|
59
|
+
request
|
|
60
|
+
);
|
|
51
61
|
|
|
52
62
|
await callHooks(model, HOOK_FUNCTIONS.onAfterShow, {
|
|
53
63
|
...context,
|
|
@@ -57,7 +67,12 @@ export default async (context) => {
|
|
|
57
67
|
});
|
|
58
68
|
|
|
59
69
|
// Serializing the data by the model's serialize method
|
|
60
|
-
item = await serializeData(
|
|
70
|
+
item = await serializeData(
|
|
71
|
+
item,
|
|
72
|
+
model.instance.serialize,
|
|
73
|
+
HANDLERS.SHOW,
|
|
74
|
+
request
|
|
75
|
+
);
|
|
61
76
|
|
|
62
77
|
// Filtering hidden fields from the response data.
|
|
63
78
|
filterHiddenFields([item], model.instance.hiddens);
|
package/src/handlers/store.js
CHANGED
|
@@ -63,7 +63,12 @@ export default async (context) => {
|
|
|
63
63
|
});
|
|
64
64
|
|
|
65
65
|
// Serializing the data by the model's serialize method
|
|
66
|
-
item = await serializeData(
|
|
66
|
+
item = await serializeData(
|
|
67
|
+
item,
|
|
68
|
+
model.instance.serialize,
|
|
69
|
+
HANDLERS.INSERT,
|
|
70
|
+
request
|
|
71
|
+
);
|
|
67
72
|
|
|
68
73
|
// Filtering hidden fields from the response data.
|
|
69
74
|
filterHiddenFields([item], model.instance.hiddens);
|
package/src/handlers/update.js
CHANGED
|
@@ -28,7 +28,9 @@ export default async (context) => {
|
|
|
28
28
|
.where(model.instance.primaryKey, request.params[model.instance.primaryKey])
|
|
29
29
|
.first();
|
|
30
30
|
if (!item) {
|
|
31
|
-
throw new HttpResponse(404,
|
|
31
|
+
throw new HttpResponse(404, {
|
|
32
|
+
message: `The item is not found on ${model.name}.`,
|
|
33
|
+
});
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
await callHooks(model, HOOK_FUNCTIONS.onAfterUpdateQuery, {
|
|
@@ -76,7 +78,12 @@ export default async (context) => {
|
|
|
76
78
|
});
|
|
77
79
|
|
|
78
80
|
// Serializing the data by the model's serialize method
|
|
79
|
-
item = await serializeData(
|
|
81
|
+
item = await serializeData(
|
|
82
|
+
item,
|
|
83
|
+
model.instance.serialize,
|
|
84
|
+
HANDLERS.UPDATE,
|
|
85
|
+
request
|
|
86
|
+
);
|
|
80
87
|
|
|
81
88
|
// Filtering hidden fields from the response data.
|
|
82
89
|
filterHiddenFields([item], model.instance.hiddens);
|
|
@@ -54,6 +54,10 @@ const requestHandler = async (handler, req, res, next, context) => {
|
|
|
54
54
|
await context.trx.rollback();
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
if (error.type === "HttpResponse") {
|
|
58
|
+
return res.status(error.status).json(error.content);
|
|
59
|
+
}
|
|
60
|
+
|
|
57
61
|
next(error);
|
|
58
62
|
}
|
|
59
63
|
};
|
|
@@ -160,6 +164,13 @@ const getModelMiddlewares = (model, handler) => {
|
|
|
160
164
|
return middlewares;
|
|
161
165
|
};
|
|
162
166
|
|
|
167
|
+
const getRootPrefix = () => {
|
|
168
|
+
if (Config.Application.prefix) {
|
|
169
|
+
return Config.Application.prefix.replace(/^\/|\/$/g, "");
|
|
170
|
+
}
|
|
171
|
+
return "api";
|
|
172
|
+
};
|
|
173
|
+
|
|
163
174
|
const createRouteByModel = async (
|
|
164
175
|
model,
|
|
165
176
|
models,
|
|
@@ -197,6 +208,7 @@ const createRouteByModel = async (
|
|
|
197
208
|
|
|
198
209
|
const routeTemplate = API_ROUTE_TEMPLATES[handler];
|
|
199
210
|
const url = routeTemplate.url(
|
|
211
|
+
getRootPrefix(),
|
|
200
212
|
urlPrefix,
|
|
201
213
|
resource,
|
|
202
214
|
model.instance.primaryKey
|