axe-api 1.0.0-rc12 → 1.0.0-rc15
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/build/index.d.ts +1 -0
- package/build/index.js +1 -0
- package/build/src/Builders/RouterBuilder.js +5 -3
- package/build/src/Builders/SwaggerBuilder.d.ts +2 -0
- package/build/src/Builders/SwaggerBuilder.js +553 -0
- package/build/src/Handlers/Helpers.d.ts +1 -1
- package/build/src/Handlers/Helpers.js +3 -3
- package/build/src/Handlers/RequestHandler.js +2 -2
- package/build/src/Handlers/{DocsHTMLHandler.js → SwaggerHandler.js} +6 -7
- package/build/src/Interfaces.d.ts +7 -0
- package/build/src/Phases/Store/PreparePhase.js +1 -1
- package/build/src/Resolvers/VersionResolver.js +1 -0
- package/build/src/Server.js +3 -5
- package/build/src/Services/App.d.ts +1 -0
- package/build/src/Services/App.js +8 -0
- package/build/src/Services/AxeRequest.d.ts +1 -1
- package/build/src/Services/AxeResponse.d.ts +1 -0
- package/build/src/Services/AxeResponse.js +3 -0
- package/build/src/Services/DocumentationService.d.ts +5 -2
- package/build/src/Services/DocumentationService.js +13 -1
- package/build/src/Services/QueryService.js +5 -0
- package/build/src/constants.d.ts +1 -0
- package/build/src/constants.js +13 -1
- package/package.json +25 -21
- package/build/src/Handlers/MetadataHandler.d.ts +0 -4
- package/build/src/Handlers/MetadataHandler.js +0 -22
- /package/build/src/Handlers/{DocsHTMLHandler.d.ts → SwaggerHandler.d.ts} +0 -0
package/build/index.d.ts
CHANGED
|
@@ -6,4 +6,5 @@ import { IoCService, allow, deny, App, AxeRequest, AxeResponse } from "./src/Ser
|
|
|
6
6
|
import { rateLimit } from "./src/Middlewares/RateLimit";
|
|
7
7
|
export * from "./src/Enums";
|
|
8
8
|
export * from "./src/Interfaces";
|
|
9
|
+
export * from "./src/Types";
|
|
9
10
|
export { App, AxeRequest, AxeResponse, Server, Model, ApiError, DEFAULT_HANDLERS, DEFAULT_VERSION_CONFIG, IoCService, allow, deny, rateLimit, };
|
package/build/index.js
CHANGED
|
@@ -38,3 +38,4 @@ const RateLimit_1 = require("./src/Middlewares/RateLimit");
|
|
|
38
38
|
Object.defineProperty(exports, "rateLimit", { enumerable: true, get: function () { return RateLimit_1.rateLimit; } });
|
|
39
39
|
__exportStar(require("./src/Enums"), exports);
|
|
40
40
|
__exportStar(require("./src/Interfaces"), exports);
|
|
41
|
+
__exportStar(require("./src/Types"), exports);
|
|
@@ -91,7 +91,8 @@ class RouterBuilder {
|
|
|
91
91
|
const relation = model.relations.find((relation) => relation.model === model.name &&
|
|
92
92
|
relation.type === Enums_1.Relationships.HAS_MANY);
|
|
93
93
|
if (relation) {
|
|
94
|
-
|
|
94
|
+
const paramName = (0, change_case_1.camelCase)(`${model.name}-${relation.primaryKey}`);
|
|
95
|
+
yield this.createRouteByModel(model, `${urlPrefix}${resource}/:${paramName}/`, model, relation, false);
|
|
95
96
|
}
|
|
96
97
|
});
|
|
97
98
|
}
|
|
@@ -106,7 +107,8 @@ class RouterBuilder {
|
|
|
106
107
|
const child = model.children.find((item) => item.name === relation.model);
|
|
107
108
|
// It should be recursive
|
|
108
109
|
if (child) {
|
|
109
|
-
|
|
110
|
+
const paramName = (0, change_case_1.camelCase)(`${model.name}-${relation.primaryKey}`);
|
|
111
|
+
yield this.createRouteByModel(child, `${urlPrefix}${resource}/:${paramName}/`, model, relation);
|
|
110
112
|
}
|
|
111
113
|
}
|
|
112
114
|
});
|
|
@@ -124,7 +126,7 @@ class RouterBuilder {
|
|
|
124
126
|
// Adding the route
|
|
125
127
|
yield URLService_1.default.add(constants_1.HANDLER_METHOD_MAP[handlerType], url, data, middlewares);
|
|
126
128
|
// Documentation
|
|
127
|
-
docs.push(this.version, handlerType, constants_1.HANDLER_METHOD_MAP[handlerType], url, model);
|
|
129
|
+
docs.push(this.version, handlerType, constants_1.HANDLER_METHOD_MAP[handlerType], url, model, parentModel);
|
|
128
130
|
});
|
|
129
131
|
}
|
|
130
132
|
getResourcePath(model, relation) {
|
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
|
+
};
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
/* eslint-disable no-prototype-builtins */
|
|
39
|
+
const path_1 = __importDefault(require("path"));
|
|
40
|
+
const fs_1 = __importDefault(require("fs"));
|
|
41
|
+
const change_case_1 = require("change-case");
|
|
42
|
+
const Enums_1 = require("../Enums");
|
|
43
|
+
const node_cache_1 = __importDefault(require("node-cache"));
|
|
44
|
+
const Services_1 = require("../Services");
|
|
45
|
+
const cache = new node_cache_1.default();
|
|
46
|
+
const DATA_TYPE_MAP = [
|
|
47
|
+
{
|
|
48
|
+
type: "string",
|
|
49
|
+
values: [
|
|
50
|
+
"char",
|
|
51
|
+
"varchar",
|
|
52
|
+
"text",
|
|
53
|
+
"tinytext",
|
|
54
|
+
"mediumtext",
|
|
55
|
+
"longtext",
|
|
56
|
+
"enum",
|
|
57
|
+
"set",
|
|
58
|
+
"varbinary",
|
|
59
|
+
"blob",
|
|
60
|
+
"tinyblob",
|
|
61
|
+
"mediumblob",
|
|
62
|
+
"longblob",
|
|
63
|
+
"date",
|
|
64
|
+
"datetime",
|
|
65
|
+
"timestamp",
|
|
66
|
+
"time",
|
|
67
|
+
"year",
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
type: "number",
|
|
72
|
+
values: [
|
|
73
|
+
"tinyint",
|
|
74
|
+
"smallint",
|
|
75
|
+
"mediumint",
|
|
76
|
+
"int",
|
|
77
|
+
"integer",
|
|
78
|
+
"bigint",
|
|
79
|
+
"float",
|
|
80
|
+
"double",
|
|
81
|
+
"decimal",
|
|
82
|
+
"numeric",
|
|
83
|
+
],
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
type: "boolean",
|
|
87
|
+
values: ["boolean", "binary"],
|
|
88
|
+
},
|
|
89
|
+
];
|
|
90
|
+
const SUMMARY_TEXTS = {
|
|
91
|
+
[Enums_1.HandlerTypes.INSERT]: "Add a new {model}",
|
|
92
|
+
[Enums_1.HandlerTypes.PAGINATE]: "Retrieve a paginated list of {model}s",
|
|
93
|
+
[Enums_1.HandlerTypes.SHOW]: "Retrieve details of a {model}",
|
|
94
|
+
[Enums_1.HandlerTypes.UPDATE]: "Update an existing {model}",
|
|
95
|
+
[Enums_1.HandlerTypes.DELETE]: "Delete a {model}",
|
|
96
|
+
[Enums_1.HandlerTypes.FORCE_DELETE]: "Force delete a {model}",
|
|
97
|
+
[Enums_1.HandlerTypes.PATCH]: "Apply partial updates to a {model}",
|
|
98
|
+
[Enums_1.HandlerTypes.ALL]: "Get all items on {model}",
|
|
99
|
+
};
|
|
100
|
+
const DESCRIPTION_TEXTS = {
|
|
101
|
+
[Enums_1.HandlerTypes.INSERT]: "Add a new {model}",
|
|
102
|
+
[Enums_1.HandlerTypes.PAGINATE]: "Retrieve a paginated list of {model}s",
|
|
103
|
+
[Enums_1.HandlerTypes.SHOW]: "Retrieve details of a {model} by primary key",
|
|
104
|
+
[Enums_1.HandlerTypes.UPDATE]: "Update an existing {model} by primary key",
|
|
105
|
+
[Enums_1.HandlerTypes.DELETE]: "Delete a {model} by primary key",
|
|
106
|
+
[Enums_1.HandlerTypes.FORCE_DELETE]: "Force delete a {model} by primary key",
|
|
107
|
+
[Enums_1.HandlerTypes.PATCH]: "Apply partial updates to a {model} by primary key",
|
|
108
|
+
[Enums_1.HandlerTypes.ALL]: "Get all items on {model}",
|
|
109
|
+
};
|
|
110
|
+
const SINGLE_RETURN_ENDPOINTS = [
|
|
111
|
+
Enums_1.HandlerTypes.INSERT,
|
|
112
|
+
Enums_1.HandlerTypes.PATCH,
|
|
113
|
+
Enums_1.HandlerTypes.SHOW,
|
|
114
|
+
Enums_1.HandlerTypes.UPDATE,
|
|
115
|
+
];
|
|
116
|
+
const ALLOWED_2XX_HANDLERS = [
|
|
117
|
+
Enums_1.HandlerTypes.ALL,
|
|
118
|
+
Enums_1.HandlerTypes.PAGINATE,
|
|
119
|
+
Enums_1.HandlerTypes.PATCH,
|
|
120
|
+
Enums_1.HandlerTypes.SHOW,
|
|
121
|
+
Enums_1.HandlerTypes.UPDATE,
|
|
122
|
+
];
|
|
123
|
+
const POSSIBLE_404_HANDLERS = [
|
|
124
|
+
Enums_1.HandlerTypes.DELETE,
|
|
125
|
+
Enums_1.HandlerTypes.FORCE_DELETE,
|
|
126
|
+
Enums_1.HandlerTypes.PATCH,
|
|
127
|
+
Enums_1.HandlerTypes.SHOW,
|
|
128
|
+
Enums_1.HandlerTypes.UPDATE,
|
|
129
|
+
];
|
|
130
|
+
const NO_CONTENT_HANDLERS = [
|
|
131
|
+
Enums_1.HandlerTypes.DELETE,
|
|
132
|
+
Enums_1.HandlerTypes.FORCE_DELETE,
|
|
133
|
+
];
|
|
134
|
+
const ALLOWED_REQUEST_BODY_HANDLERS = [
|
|
135
|
+
Enums_1.HandlerTypes.INSERT,
|
|
136
|
+
Enums_1.HandlerTypes.UPDATE,
|
|
137
|
+
Enums_1.HandlerTypes.PATCH,
|
|
138
|
+
];
|
|
139
|
+
const ALLOWED_QUERY_HANDLERS = [
|
|
140
|
+
Enums_1.HandlerTypes.ALL,
|
|
141
|
+
Enums_1.HandlerTypes.SHOW,
|
|
142
|
+
Enums_1.HandlerTypes.PAGINATE,
|
|
143
|
+
];
|
|
144
|
+
const PAGINATION_SCHEMA = {
|
|
145
|
+
type: "object",
|
|
146
|
+
properties: {
|
|
147
|
+
total: {
|
|
148
|
+
type: "integer",
|
|
149
|
+
default: 1,
|
|
150
|
+
},
|
|
151
|
+
lastPage: {
|
|
152
|
+
type: "integer",
|
|
153
|
+
default: 1,
|
|
154
|
+
},
|
|
155
|
+
perPage: {
|
|
156
|
+
type: "integer",
|
|
157
|
+
default: 10,
|
|
158
|
+
},
|
|
159
|
+
currentPage: {
|
|
160
|
+
type: "integer",
|
|
161
|
+
default: 1,
|
|
162
|
+
},
|
|
163
|
+
from: {
|
|
164
|
+
type: "integer",
|
|
165
|
+
default: 0,
|
|
166
|
+
},
|
|
167
|
+
to: {
|
|
168
|
+
type: "integer",
|
|
169
|
+
default: 10,
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
const ERROR_SCHEMA = {
|
|
174
|
+
type: "object",
|
|
175
|
+
properties: {
|
|
176
|
+
error: {
|
|
177
|
+
type: "string",
|
|
178
|
+
default: "An error occorred",
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
const VALIDATION_ERROR_SCHEMA = {
|
|
183
|
+
type: "object",
|
|
184
|
+
properties: {
|
|
185
|
+
errors: {
|
|
186
|
+
type: "object",
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
const toPropertyType = (datatype) => {
|
|
191
|
+
for (const item of DATA_TYPE_MAP) {
|
|
192
|
+
if (item.values.includes(datatype)) {
|
|
193
|
+
return item.type;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return datatype;
|
|
197
|
+
};
|
|
198
|
+
const toEndpointSummary = (endpoint) => {
|
|
199
|
+
const value = SUMMARY_TEXTS[endpoint.handler] || "";
|
|
200
|
+
return value.replace("{model}", endpoint.model.toLowerCase());
|
|
201
|
+
};
|
|
202
|
+
const toEndpointDescription = (endpoint) => {
|
|
203
|
+
const value = DESCRIPTION_TEXTS[endpoint.handler] || "";
|
|
204
|
+
return value.replace("{model}", endpoint.model.toLowerCase());
|
|
205
|
+
};
|
|
206
|
+
const to2XXResponse = (endpoint) => {
|
|
207
|
+
// Single item response
|
|
208
|
+
if (SINGLE_RETURN_ENDPOINTS.includes(endpoint.handler)) {
|
|
209
|
+
return {
|
|
210
|
+
content: {
|
|
211
|
+
"application/json": {
|
|
212
|
+
schema: {
|
|
213
|
+
$ref: `#/components/schemas/${endpoint.model}`,
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
// All response
|
|
220
|
+
if (endpoint.handler === Enums_1.HandlerTypes.ALL) {
|
|
221
|
+
return {
|
|
222
|
+
content: {
|
|
223
|
+
"application/json": {
|
|
224
|
+
schema: {
|
|
225
|
+
type: "array",
|
|
226
|
+
items: {
|
|
227
|
+
$ref: `#/components/schemas/${endpoint.model}`,
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
content: {
|
|
236
|
+
"application/json": {
|
|
237
|
+
schema: {
|
|
238
|
+
type: "object",
|
|
239
|
+
properties: {
|
|
240
|
+
data: {
|
|
241
|
+
type: "array",
|
|
242
|
+
items: {
|
|
243
|
+
$ref: `#/components/schemas/${endpoint.model}`,
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
pagination: {
|
|
247
|
+
$ref: `#/components/schemas/Pagination`,
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
};
|
|
254
|
+
};
|
|
255
|
+
const toEndpointResponse = (endpoint) => {
|
|
256
|
+
const response = {};
|
|
257
|
+
if (ALLOWED_2XX_HANDLERS.includes(endpoint.handler)) {
|
|
258
|
+
response["200"] = Object.assign(Object.assign({}, to2XXResponse(endpoint)), { description: "OK" });
|
|
259
|
+
}
|
|
260
|
+
if (endpoint.handler === Enums_1.HandlerTypes.INSERT) {
|
|
261
|
+
response["201"] = Object.assign(Object.assign({}, to2XXResponse(endpoint)), { description: "Created" });
|
|
262
|
+
response["400"] = {
|
|
263
|
+
description: "Bad request",
|
|
264
|
+
content: {
|
|
265
|
+
"application/json": {
|
|
266
|
+
schema: {
|
|
267
|
+
$ref: `#/components/schemas/ValidationError`,
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
if (NO_CONTENT_HANDLERS.includes(endpoint.handler)) {
|
|
274
|
+
response["204"] = {
|
|
275
|
+
description: "No Content",
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
if (POSSIBLE_404_HANDLERS.includes(endpoint.handler) ||
|
|
279
|
+
endpoint.parentModel) {
|
|
280
|
+
response["404"] = {
|
|
281
|
+
description: "Not Found",
|
|
282
|
+
content: {
|
|
283
|
+
"application/json": {
|
|
284
|
+
schema: {
|
|
285
|
+
$ref: `#/components/schemas/Error`,
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
return response;
|
|
292
|
+
};
|
|
293
|
+
const toFillableFieldProperties = (model) => {
|
|
294
|
+
const fields = model.instance.getFillableFields(Enums_1.HttpMethods.POST);
|
|
295
|
+
const properties = {};
|
|
296
|
+
for (const field of fields) {
|
|
297
|
+
const column = model.columns.find((item) => item.name === field);
|
|
298
|
+
if (column) {
|
|
299
|
+
properties[column.name] = {
|
|
300
|
+
type: toPropertyType(column.data_type),
|
|
301
|
+
format: column.data_type,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return properties;
|
|
306
|
+
};
|
|
307
|
+
const toRequestBody = (endpoint) => {
|
|
308
|
+
if (ALLOWED_REQUEST_BODY_HANDLERS.includes(endpoint.handler) === false) {
|
|
309
|
+
return undefined;
|
|
310
|
+
}
|
|
311
|
+
const bodySchema = `${endpoint.model}${(0, change_case_1.pascalCase)(endpoint.method)}Body`;
|
|
312
|
+
return {
|
|
313
|
+
description: "Update an existent pet in the store",
|
|
314
|
+
content: {
|
|
315
|
+
"application/json": {
|
|
316
|
+
schema: {
|
|
317
|
+
$ref: `#/components/requestBodies/${bodySchema}`,
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
required: true,
|
|
322
|
+
};
|
|
323
|
+
};
|
|
324
|
+
const toRequestParameters = (endpoint) => {
|
|
325
|
+
const parameters = [
|
|
326
|
+
{
|
|
327
|
+
in: "header",
|
|
328
|
+
name: "Accept-Language",
|
|
329
|
+
schema: {
|
|
330
|
+
type: "string",
|
|
331
|
+
example: "en;q=0.8, de;q=0.7, *;q=0.5",
|
|
332
|
+
},
|
|
333
|
+
required: false,
|
|
334
|
+
},
|
|
335
|
+
];
|
|
336
|
+
if (endpoint.url.includes(":")) {
|
|
337
|
+
const sections = endpoint.url
|
|
338
|
+
.split("/")
|
|
339
|
+
.filter((item) => item.includes(":"))
|
|
340
|
+
.map((item) => item.replace(":", ""));
|
|
341
|
+
for (const section of sections) {
|
|
342
|
+
parameters.push({
|
|
343
|
+
in: "path",
|
|
344
|
+
name: section,
|
|
345
|
+
required: true,
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
if (endpoint.handler === Enums_1.HandlerTypes.PAGINATE) {
|
|
350
|
+
parameters.push(...[
|
|
351
|
+
{
|
|
352
|
+
name: "page",
|
|
353
|
+
in: "query",
|
|
354
|
+
description: "The page number to list",
|
|
355
|
+
required: false,
|
|
356
|
+
schema: {
|
|
357
|
+
type: "integer",
|
|
358
|
+
default: 1,
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
name: "per_page",
|
|
363
|
+
in: "query",
|
|
364
|
+
description: "Number of records to list on a page",
|
|
365
|
+
required: false,
|
|
366
|
+
schema: {
|
|
367
|
+
type: "integer",
|
|
368
|
+
default: 10,
|
|
369
|
+
},
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
name: "sort",
|
|
373
|
+
in: "query",
|
|
374
|
+
description: "The field to sort the data (ASC: id, DESC: -id)",
|
|
375
|
+
required: false,
|
|
376
|
+
schema: {
|
|
377
|
+
type: "string",
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
]);
|
|
381
|
+
}
|
|
382
|
+
if (ALLOWED_QUERY_HANDLERS.includes(endpoint.handler)) {
|
|
383
|
+
parameters.push(...[
|
|
384
|
+
{
|
|
385
|
+
name: "fields",
|
|
386
|
+
in: "query",
|
|
387
|
+
description: "The model fields that can be fetched",
|
|
388
|
+
required: false,
|
|
389
|
+
schema: {
|
|
390
|
+
type: "string",
|
|
391
|
+
},
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
name: "with",
|
|
395
|
+
in: "query",
|
|
396
|
+
description: "Listable related models",
|
|
397
|
+
required: false,
|
|
398
|
+
schema: {
|
|
399
|
+
type: "string",
|
|
400
|
+
},
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
name: "trashed",
|
|
404
|
+
in: "query",
|
|
405
|
+
description: "List of deleted data with soft-delete",
|
|
406
|
+
required: false,
|
|
407
|
+
schema: {
|
|
408
|
+
type: "integer",
|
|
409
|
+
default: 0,
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
name: "q",
|
|
414
|
+
in: "query",
|
|
415
|
+
description: "JSON query to filter data",
|
|
416
|
+
required: false,
|
|
417
|
+
schema: {
|
|
418
|
+
type: "string",
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
]);
|
|
422
|
+
}
|
|
423
|
+
return parameters;
|
|
424
|
+
};
|
|
425
|
+
const deepMerge = (base, source) => {
|
|
426
|
+
// Check if either base or source is not an object, or if source is null
|
|
427
|
+
if (typeof base !== "object" ||
|
|
428
|
+
typeof source !== "object" ||
|
|
429
|
+
source === null) {
|
|
430
|
+
return source;
|
|
431
|
+
}
|
|
432
|
+
// Create a copy of the base object to avoid modifying it directly
|
|
433
|
+
const merged = Object.assign({}, base);
|
|
434
|
+
// Loop through all properties in the source object
|
|
435
|
+
for (const key in source) {
|
|
436
|
+
if (source.hasOwnProperty(key)) {
|
|
437
|
+
// If the key exists in the base object and both values are objects, merge recursively
|
|
438
|
+
if (base.hasOwnProperty(key) &&
|
|
439
|
+
typeof base[key] === "object" &&
|
|
440
|
+
typeof source[key] === "object") {
|
|
441
|
+
merged[key] = deepMerge(base[key], source[key]);
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
// If the key does not exist in the base object or one of the values is not an object, assign the source value to the merged object
|
|
445
|
+
merged[key] = source[key];
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return merged;
|
|
450
|
+
};
|
|
451
|
+
const generateDocumentation = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
452
|
+
const docs = Services_1.DocumentationService.getInstance();
|
|
453
|
+
const api = Services_1.APIService.getInstance();
|
|
454
|
+
const swaggerBasePath = path_1.default.join(api.rootFolder, "swagger", "index.ts");
|
|
455
|
+
let baseSchema = {
|
|
456
|
+
info: {
|
|
457
|
+
title: "Axe API",
|
|
458
|
+
description: "Edit your swagger/index.ts file",
|
|
459
|
+
},
|
|
460
|
+
servers: [
|
|
461
|
+
{
|
|
462
|
+
url: "http://localhost:3000",
|
|
463
|
+
},
|
|
464
|
+
],
|
|
465
|
+
};
|
|
466
|
+
if (fs_1.default.existsSync(swaggerBasePath)) {
|
|
467
|
+
const { default: userDefinedSchema } = yield Promise.resolve(`${swaggerBasePath}`).then(s => __importStar(require(s)));
|
|
468
|
+
baseSchema = userDefinedSchema;
|
|
469
|
+
}
|
|
470
|
+
const schemas = {};
|
|
471
|
+
const requestBodies = {};
|
|
472
|
+
const firstVersion = api.versions.at(0);
|
|
473
|
+
if (!firstVersion) {
|
|
474
|
+
throw new Error("The version is not found!");
|
|
475
|
+
}
|
|
476
|
+
for (const model of firstVersion.modelList.get()) {
|
|
477
|
+
const properties = {};
|
|
478
|
+
for (const column of model.columns) {
|
|
479
|
+
properties[column.name] = {
|
|
480
|
+
type: toPropertyType(column.data_type),
|
|
481
|
+
format: column.data_type,
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
schemas[model.name] = {
|
|
485
|
+
type: "object",
|
|
486
|
+
properties,
|
|
487
|
+
};
|
|
488
|
+
if (model.instance.handlers.includes(Enums_1.HandlerTypes.INSERT)) {
|
|
489
|
+
requestBodies[`${model.name}${(0, change_case_1.pascalCase)(Enums_1.HttpMethods.POST)}Body`] = {
|
|
490
|
+
type: "object",
|
|
491
|
+
properties: toFillableFieldProperties(model),
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
if (model.instance.handlers.includes(Enums_1.HandlerTypes.UPDATE)) {
|
|
495
|
+
requestBodies[`${model.name}${(0, change_case_1.pascalCase)(Enums_1.HttpMethods.PUT)}Body`] = {
|
|
496
|
+
type: "object",
|
|
497
|
+
properties: toFillableFieldProperties(model),
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
if (model.instance.handlers.includes(Enums_1.HandlerTypes.PATCH)) {
|
|
501
|
+
requestBodies[`${model.name}${(0, change_case_1.pascalCase)(Enums_1.HttpMethods.PATCH)}Body`] = {
|
|
502
|
+
type: "object",
|
|
503
|
+
properties: toFillableFieldProperties(model),
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
const paths = {};
|
|
508
|
+
for (const endpoint of docs.get()) {
|
|
509
|
+
if (paths[endpoint.url] === undefined) {
|
|
510
|
+
paths[endpoint.url] = {};
|
|
511
|
+
}
|
|
512
|
+
const path = {
|
|
513
|
+
tags: [endpoint.model],
|
|
514
|
+
summary: toEndpointSummary(endpoint),
|
|
515
|
+
description: toEndpointDescription(endpoint),
|
|
516
|
+
operationId: `${endpoint.handler}${endpoint.model}`,
|
|
517
|
+
responses: toEndpointResponse(endpoint),
|
|
518
|
+
parameters: toRequestParameters(endpoint),
|
|
519
|
+
};
|
|
520
|
+
const requestBody = toRequestBody(endpoint);
|
|
521
|
+
if (requestBody) {
|
|
522
|
+
path.requestBody = requestBody;
|
|
523
|
+
}
|
|
524
|
+
paths[endpoint.url][endpoint.method.toLowerCase()] = path;
|
|
525
|
+
}
|
|
526
|
+
// Added custom endpoint
|
|
527
|
+
for (const custom of docs.getCustoms()) {
|
|
528
|
+
if (paths[custom.url] === undefined) {
|
|
529
|
+
paths[custom.url] = {};
|
|
530
|
+
}
|
|
531
|
+
paths[custom.url][custom.method.toLowerCase()] = {
|
|
532
|
+
description: "Custom endpoint",
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
const builded = {
|
|
536
|
+
openapi: "3.1.0",
|
|
537
|
+
paths,
|
|
538
|
+
components: {
|
|
539
|
+
schemas: Object.assign(Object.assign({}, schemas), { Pagination: PAGINATION_SCHEMA, Error: ERROR_SCHEMA, ValidationError: VALIDATION_ERROR_SCHEMA }),
|
|
540
|
+
requestBodies,
|
|
541
|
+
},
|
|
542
|
+
};
|
|
543
|
+
return deepMerge(baseSchema, builded);
|
|
544
|
+
});
|
|
545
|
+
exports.default = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
546
|
+
const cached = cache.get("axe-api-documentation");
|
|
547
|
+
if (cached) {
|
|
548
|
+
return JSON.parse(cached);
|
|
549
|
+
}
|
|
550
|
+
const documentation = yield generateDocumentation();
|
|
551
|
+
cache.set("axe-api-documentation", JSON.stringify(documentation));
|
|
552
|
+
return documentation;
|
|
553
|
+
});
|
|
@@ -7,7 +7,7 @@ import AxeRequest from "src/Services/AxeRequest";
|
|
|
7
7
|
export declare const bindTimestampValues: (formData: Record<string, any>, model: IModelService, columnTypes?: TimestampColumns[]) => void;
|
|
8
8
|
export declare const getMergedFormData: (req: AxeRequest, fillables: string[]) => Record<string, any>;
|
|
9
9
|
export declare const callHooks: (model: IModelService, type: HookFunctionTypes, params: IContext) => Promise<void>;
|
|
10
|
-
export declare const getParentColumn: (relation: IRelation | null) => string | null;
|
|
10
|
+
export declare const getParentColumn: (model: IModelService, relation: IRelation | null) => string | null;
|
|
11
11
|
export declare const checkPrimaryKeyValueType: (model: IModelService, value: any) => void;
|
|
12
12
|
export declare const addForeignKeyQuery: (request: AxeRequest, query: Knex.QueryBuilder, relation: IRelation | null, parentModel: IModelService | null) => void;
|
|
13
13
|
export declare const serializeData: (version: IVersion, itemArray: any, modelSerializer: SerializationFunction | null, handler: HandlerTypes, request: AxeRequest) => Promise<any[]>;
|
|
@@ -57,11 +57,11 @@ const callHooks = (model, type, params) => __awaiter(void 0, void 0, void 0, fun
|
|
|
57
57
|
}
|
|
58
58
|
});
|
|
59
59
|
exports.callHooks = callHooks;
|
|
60
|
-
const getParentColumn = (relation) => {
|
|
60
|
+
const getParentColumn = (model, relation) => {
|
|
61
61
|
if (!relation) {
|
|
62
62
|
return null;
|
|
63
63
|
}
|
|
64
|
-
return (0, change_case_1.camelCase)(relation.
|
|
64
|
+
return (0, change_case_1.camelCase)(`${model.name}-${relation.primaryKey}`);
|
|
65
65
|
};
|
|
66
66
|
exports.getParentColumn = getParentColumn;
|
|
67
67
|
const checkPrimaryKeyValueType = (model, value) => {
|
|
@@ -75,7 +75,7 @@ const checkPrimaryKeyValueType = (model, value) => {
|
|
|
75
75
|
exports.checkPrimaryKeyValueType = checkPrimaryKeyValueType;
|
|
76
76
|
const addForeignKeyQuery = (request, query, relation, parentModel) => {
|
|
77
77
|
if (relation && parentModel) {
|
|
78
|
-
const parentColumn = (0, exports.getParentColumn)(relation);
|
|
78
|
+
const parentColumn = (0, exports.getParentColumn)(parentModel, relation);
|
|
79
79
|
if (parentColumn) {
|
|
80
80
|
query.where(relation.foreignKey, request.params[parentColumn]);
|
|
81
81
|
}
|
|
@@ -22,7 +22,7 @@ const return404 = (response) => {
|
|
|
22
22
|
response.end();
|
|
23
23
|
};
|
|
24
24
|
exports.default = (request, response, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
25
|
-
Services_1.LogService.debug(
|
|
25
|
+
Services_1.LogService.debug(`📥 ${request.method} ${request.url}`);
|
|
26
26
|
const { axeRequest, axeResponse } = (0, ConverterService_1.toAxeRequestResponsePair)(request, response);
|
|
27
27
|
const match = URLService_1.default.match(axeRequest);
|
|
28
28
|
if (!match) {
|
|
@@ -83,7 +83,7 @@ exports.default = (request, response, next) => __awaiter(void 0, void 0, void 0,
|
|
|
83
83
|
Services_1.LogService.debug(`\tResponse ${context.res.statusCode()}`);
|
|
84
84
|
break;
|
|
85
85
|
}
|
|
86
|
-
Services_1.LogService.debug(`\
|
|
86
|
+
Services_1.LogService.debug(`\t🟢 Response ${context.res.statusCode()}`);
|
|
87
87
|
// We should brake the for-loop
|
|
88
88
|
break;
|
|
89
89
|
}
|
|
@@ -8,17 +8,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
11
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
const
|
|
15
|
+
const SwaggerBuilder_1 = __importDefault(require("../Builders/SwaggerBuilder"));
|
|
13
16
|
exports.default = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
14
17
|
try {
|
|
15
|
-
|
|
16
|
-
const content = (yield result.text())
|
|
17
|
-
.replaceAll(`src="`, `src="${CLOUD_FRONT_DOMAIN}`)
|
|
18
|
-
.replaceAll(`href="`, `href="${CLOUD_FRONT_DOMAIN}`);
|
|
19
|
-
res.send(content);
|
|
18
|
+
res.json(yield (0, SwaggerBuilder_1.default)());
|
|
20
19
|
}
|
|
21
20
|
catch (error) {
|
|
22
|
-
res.
|
|
21
|
+
res.status(500).json({ error: "An error occurred!" });
|
|
23
22
|
}
|
|
24
23
|
});
|
|
@@ -77,6 +77,7 @@ export interface AxeConfig extends IConfig {
|
|
|
77
77
|
pino: LoggerOptions;
|
|
78
78
|
rateLimit: IRateLimitConfig;
|
|
79
79
|
errorHandler: ErrorHandleFunction;
|
|
80
|
+
docs: boolean;
|
|
80
81
|
}
|
|
81
82
|
export type IApplicationConfig = Partial<AxeConfig>;
|
|
82
83
|
export interface ILanguage {
|
|
@@ -171,6 +172,8 @@ export interface IContext extends IRouteData {
|
|
|
171
172
|
export interface IRouteDocumentation {
|
|
172
173
|
version: string;
|
|
173
174
|
handler: string;
|
|
175
|
+
modelService: IModelService;
|
|
176
|
+
parentModel: IModelService | null;
|
|
174
177
|
model: string;
|
|
175
178
|
table: string;
|
|
176
179
|
columns: IColumn[];
|
|
@@ -183,6 +186,10 @@ export interface IRouteDocumentation {
|
|
|
183
186
|
queryLimits: IQueryLimitConfig[];
|
|
184
187
|
queryDefaults: IQueryDefaultConfig;
|
|
185
188
|
}
|
|
189
|
+
export interface ICustomRouteDocumentation {
|
|
190
|
+
method: HttpMethods;
|
|
191
|
+
url: string;
|
|
192
|
+
}
|
|
186
193
|
export interface IRawQuery {
|
|
187
194
|
q: string | null;
|
|
188
195
|
page: string | null;
|
|
@@ -32,7 +32,7 @@ exports.default = (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
if (context.relation && context.parentModel) {
|
|
35
|
-
const parentColumn = (0, Helpers_1.getParentColumn)(context.relation);
|
|
35
|
+
const parentColumn = (0, Helpers_1.getParentColumn)(context.parentModel, context.relation);
|
|
36
36
|
if (parentColumn) {
|
|
37
37
|
context.formData[context.relation.foreignKey] =
|
|
38
38
|
context.params[parentColumn];
|
package/build/src/Server.js
CHANGED
|
@@ -43,8 +43,7 @@ const knex_schema_inspector_1 = __importDefault(require("knex-schema-inspector")
|
|
|
43
43
|
const knex_paginate_1 = require("knex-paginate");
|
|
44
44
|
const Builders_1 = require("./Builders");
|
|
45
45
|
const Services_1 = require("./Services");
|
|
46
|
-
const
|
|
47
|
-
const DocsHTMLHandler_1 = __importDefault(require("./Handlers/DocsHTMLHandler"));
|
|
46
|
+
const SwaggerHandler_1 = __importDefault(require("./Handlers/SwaggerHandler"));
|
|
48
47
|
const RoutesHandler_1 = __importDefault(require("./Handlers/RoutesHandler"));
|
|
49
48
|
const http_1 = __importDefault(require("http"));
|
|
50
49
|
const RequestHandler_1 = __importDefault(require("./Handlers/RequestHandler"));
|
|
@@ -131,9 +130,8 @@ class Server {
|
|
|
131
130
|
server.on("error", function (e) {
|
|
132
131
|
Services_1.LogService.error(e.message);
|
|
133
132
|
});
|
|
134
|
-
if (api.config.
|
|
135
|
-
app.get("/
|
|
136
|
-
app.get("/docs", DocsHTMLHandler_1.default);
|
|
133
|
+
if (api.config.docs) {
|
|
134
|
+
app.get("/swagger", SwaggerHandler_1.default);
|
|
137
135
|
app.get("/routes", RoutesHandler_1.default);
|
|
138
136
|
}
|
|
139
137
|
server.listen(api.config.port);
|
|
@@ -33,9 +33,12 @@ const LogService_1 = __importDefault(require("./LogService"));
|
|
|
33
33
|
const RateLimit_1 = __importStar(require("../Middlewares/RateLimit"));
|
|
34
34
|
const APIService_1 = __importDefault(require("./APIService"));
|
|
35
35
|
const ConverterService_1 = require("./ConverterService");
|
|
36
|
+
const DocumentationService_1 = __importDefault(require("./DocumentationService"));
|
|
37
|
+
const Enums_1 = require("../Enums");
|
|
36
38
|
class App {
|
|
37
39
|
constructor() {
|
|
38
40
|
var _a;
|
|
41
|
+
this.docs = DocumentationService_1.default.getInstance();
|
|
39
42
|
this.connect = (0, connect_1.default)();
|
|
40
43
|
LogService_1.default.debug("Created a new connect() instance");
|
|
41
44
|
this.connect.use(body_parser_1.default.urlencoded({ extended: true }));
|
|
@@ -88,6 +91,7 @@ class App {
|
|
|
88
91
|
get(url, ...args) {
|
|
89
92
|
const { handler, middlewares } = (0, ConverterService_1.resolveMiddlewares)(args);
|
|
90
93
|
URLService_1.default.addHandler("GET", url, handler, middlewares);
|
|
94
|
+
this.docs.pushCustom(Enums_1.HttpMethods.GET, url);
|
|
91
95
|
}
|
|
92
96
|
/**
|
|
93
97
|
* Add a POST request handler with middleware support
|
|
@@ -106,6 +110,7 @@ class App {
|
|
|
106
110
|
post(url, ...args) {
|
|
107
111
|
const { handler, middlewares } = (0, ConverterService_1.resolveMiddlewares)(args);
|
|
108
112
|
URLService_1.default.addHandler("POST", url, handler, middlewares);
|
|
113
|
+
this.docs.pushCustom(Enums_1.HttpMethods.POST, url);
|
|
109
114
|
}
|
|
110
115
|
/**
|
|
111
116
|
* Add a PUT request handler with middleware support
|
|
@@ -124,6 +129,7 @@ class App {
|
|
|
124
129
|
put(url, ...args) {
|
|
125
130
|
const { handler, middlewares } = (0, ConverterService_1.resolveMiddlewares)(args);
|
|
126
131
|
URLService_1.default.addHandler("PUT", url, handler, middlewares);
|
|
132
|
+
this.docs.pushCustom(Enums_1.HttpMethods.PUT, url);
|
|
127
133
|
}
|
|
128
134
|
/**
|
|
129
135
|
* Add a PATCH request handler with middleware support
|
|
@@ -142,6 +148,7 @@ class App {
|
|
|
142
148
|
patch(url, ...args) {
|
|
143
149
|
const { handler, middlewares } = (0, ConverterService_1.resolveMiddlewares)(args);
|
|
144
150
|
URLService_1.default.addHandler("PATCH", url, handler, middlewares);
|
|
151
|
+
this.docs.pushCustom(Enums_1.HttpMethods.PATCH, url);
|
|
145
152
|
}
|
|
146
153
|
/**
|
|
147
154
|
* Add a DELETE request handler with middleware support
|
|
@@ -160,6 +167,7 @@ class App {
|
|
|
160
167
|
delete(url, ...args) {
|
|
161
168
|
const { handler, middlewares } = (0, ConverterService_1.resolveMiddlewares)(args);
|
|
162
169
|
URLService_1.default.addHandler("DELETE", url, handler, middlewares);
|
|
170
|
+
this.docs.pushCustom(Enums_1.HttpMethods.DELETE, url);
|
|
163
171
|
}
|
|
164
172
|
}
|
|
165
173
|
exports.default = App;
|
|
@@ -64,7 +64,7 @@ declare class AxeRequest {
|
|
|
64
64
|
* @param options
|
|
65
65
|
* @returns
|
|
66
66
|
*/
|
|
67
|
-
files(options?: FormOptions): Promise<[formidable.Fields
|
|
67
|
+
files(options?: FormOptions): Promise<[formidable.Fields<string>, formidable.Files<string>]>;
|
|
68
68
|
/**
|
|
69
69
|
* Get the original `IncomingMessage` request.
|
|
70
70
|
*
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { IModelService, IRouteDocumentation, IVersion } from "../Interfaces";
|
|
1
|
+
import { ICustomRouteDocumentation, IModelService, IRouteDocumentation, IVersion } from "../Interfaces";
|
|
2
2
|
import { HandlerTypes, HttpMethods } from "../Enums";
|
|
3
3
|
declare class DocumentationService {
|
|
4
4
|
private static instance;
|
|
5
5
|
private routes;
|
|
6
|
+
private customRoutes;
|
|
6
7
|
constructor();
|
|
7
8
|
static getInstance(): DocumentationService;
|
|
8
|
-
push(version: IVersion, handler: HandlerTypes, method: HttpMethods, url: string, model: IModelService): void;
|
|
9
|
+
push(version: IVersion, handler: HandlerTypes, method: HttpMethods, url: string, model: IModelService, parentModel: IModelService | null): void;
|
|
10
|
+
pushCustom(method: HttpMethods, url: string): void;
|
|
9
11
|
get(): IRouteDocumentation[];
|
|
12
|
+
getCustoms(): ICustomRouteDocumentation[];
|
|
10
13
|
}
|
|
11
14
|
export default DocumentationService;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
class DocumentationService {
|
|
4
4
|
constructor() {
|
|
5
5
|
this.routes = [];
|
|
6
|
+
this.customRoutes = [];
|
|
6
7
|
}
|
|
7
8
|
static getInstance() {
|
|
8
9
|
if (!DocumentationService.instance) {
|
|
@@ -10,11 +11,13 @@ class DocumentationService {
|
|
|
10
11
|
}
|
|
11
12
|
return DocumentationService.instance;
|
|
12
13
|
}
|
|
13
|
-
push(version, handler, method, url, model) {
|
|
14
|
+
push(version, handler, method, url, model, parentModel) {
|
|
14
15
|
var _a, _b, _c;
|
|
15
16
|
this.routes.push({
|
|
16
17
|
version: version.name,
|
|
17
18
|
handler,
|
|
19
|
+
modelService: model,
|
|
20
|
+
parentModel,
|
|
18
21
|
model: model.name,
|
|
19
22
|
table: model.instance.table,
|
|
20
23
|
columns: model.columns,
|
|
@@ -28,8 +31,17 @@ class DocumentationService {
|
|
|
28
31
|
queryDefaults: (_c = (_b = (_a = version.config) === null || _a === void 0 ? void 0 : _a.query) === null || _b === void 0 ? void 0 : _b.defaults) !== null && _c !== void 0 ? _c : {},
|
|
29
32
|
});
|
|
30
33
|
}
|
|
34
|
+
pushCustom(method, url) {
|
|
35
|
+
this.customRoutes.push({
|
|
36
|
+
method,
|
|
37
|
+
url,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
31
40
|
get() {
|
|
32
41
|
return this.routes;
|
|
33
42
|
}
|
|
43
|
+
getCustoms() {
|
|
44
|
+
return this.customRoutes;
|
|
45
|
+
}
|
|
34
46
|
}
|
|
35
47
|
exports.default = DocumentationService;
|
|
@@ -331,6 +331,11 @@ class QueryService {
|
|
|
331
331
|
}
|
|
332
332
|
if (where.condition === Enums_1.ConditionTypes.LIKE ||
|
|
333
333
|
where.condition === Enums_1.ConditionTypes["NOT LIKE"]) {
|
|
334
|
+
const queryColumn = where.model.columns.find((column) => column.name === where.field);
|
|
335
|
+
if (queryColumn &&
|
|
336
|
+
!constants_1.STRING_COLUMN_TYPES.includes(queryColumn.data_type.toLowerCase())) {
|
|
337
|
+
throw new ApiError_1.default(`Query field need to be string. Unacceptable query field: ${where.field}`);
|
|
338
|
+
}
|
|
334
339
|
where.value = where.value.replace(/\*/g, "%");
|
|
335
340
|
}
|
|
336
341
|
// This means that the condition is related with another table
|
package/build/src/constants.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export declare const API_ROUTE_TEMPLATES: {
|
|
|
16
16
|
export declare const ConditionQueryFeatureMap: Record<ConditionTypes, QueryFeature>;
|
|
17
17
|
export declare const RelationQueryFeatureMap: Record<Relationships, QueryFeature>;
|
|
18
18
|
export declare const NUMERIC_PRIMARY_KEY_TYPES: string[];
|
|
19
|
+
export declare const STRING_COLUMN_TYPES: string[];
|
|
19
20
|
export declare const HANDLER_METHOD_MAP: Record<HandlerTypes, HttpMethods>;
|
|
20
21
|
export declare const HANDLER_CYLES: Record<HandlerTypes, IStepDefinition[]>;
|
|
21
22
|
export declare const DEFAULT_APP_CONFIG: AxeConfig;
|
package/build/src/constants.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.DEFAULT_VERSION_CONFIG = exports.DEFAULT_APP_CONFIG = exports.HANDLER_CYLES = exports.HANDLER_METHOD_MAP = exports.NUMERIC_PRIMARY_KEY_TYPES = exports.RelationQueryFeatureMap = exports.ConditionQueryFeatureMap = exports.API_ROUTE_TEMPLATES = exports.DEFAULT_METHODS_OF_MODELS = exports.DEFAULT_HANDLERS = exports.RESERVED_KEYWORDS = void 0;
|
|
6
|
+
exports.DEFAULT_VERSION_CONFIG = exports.DEFAULT_APP_CONFIG = exports.HANDLER_CYLES = exports.HANDLER_METHOD_MAP = exports.STRING_COLUMN_TYPES = exports.NUMERIC_PRIMARY_KEY_TYPES = exports.RelationQueryFeatureMap = exports.ConditionQueryFeatureMap = exports.API_ROUTE_TEMPLATES = exports.DEFAULT_METHODS_OF_MODELS = exports.DEFAULT_HANDLERS = exports.RESERVED_KEYWORDS = void 0;
|
|
7
7
|
const Enums_1 = require("./Enums");
|
|
8
8
|
const LimitService_1 = require("./Services/LimitService");
|
|
9
9
|
const Single_1 = __importDefault(require("./Phases/Single"));
|
|
@@ -31,6 +31,7 @@ exports.RESERVED_KEYWORDS = [
|
|
|
31
31
|
"event",
|
|
32
32
|
"events",
|
|
33
33
|
"all",
|
|
34
|
+
"swagger",
|
|
34
35
|
];
|
|
35
36
|
exports.DEFAULT_HANDLERS = [
|
|
36
37
|
Enums_1.HandlerTypes.INSERT,
|
|
@@ -102,6 +103,16 @@ exports.RelationQueryFeatureMap = {
|
|
|
102
103
|
[Enums_1.Relationships.HAS_MANY]: Enums_1.QueryFeature.WithHasMany,
|
|
103
104
|
};
|
|
104
105
|
exports.NUMERIC_PRIMARY_KEY_TYPES = ["integer", "bigint"];
|
|
106
|
+
exports.STRING_COLUMN_TYPES = [
|
|
107
|
+
"CHAR",
|
|
108
|
+
"VARCHAR",
|
|
109
|
+
"BINARY",
|
|
110
|
+
"VARBINARY",
|
|
111
|
+
"BLOB",
|
|
112
|
+
"TEXT",
|
|
113
|
+
"ENUM",
|
|
114
|
+
"SET",
|
|
115
|
+
].map((item) => item.toLowerCase());
|
|
105
116
|
exports.HANDLER_METHOD_MAP = {
|
|
106
117
|
[Enums_1.HandlerTypes.INSERT]: Enums_1.HttpMethods.POST,
|
|
107
118
|
[Enums_1.HandlerTypes.PAGINATE]: Enums_1.HttpMethods.GET,
|
|
@@ -221,6 +232,7 @@ exports.DEFAULT_APP_CONFIG = {
|
|
|
221
232
|
prefix: "api",
|
|
222
233
|
env: "production",
|
|
223
234
|
port: 3000,
|
|
235
|
+
docs: true,
|
|
224
236
|
pino: {
|
|
225
237
|
level: "error",
|
|
226
238
|
transport: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "axe-api",
|
|
3
|
-
"version": "1.0.0-
|
|
3
|
+
"version": "1.0.0-rc15",
|
|
4
4
|
"description": "AXE API is a simple tool to create Rest APIs quickly.",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -33,7 +33,9 @@
|
|
|
33
33
|
"dev-kit": "ts-node-dev --respawn --clear dev-kit.ts",
|
|
34
34
|
"dev-kit:install": "node ./scripts/dev-kit-install.js",
|
|
35
35
|
"dev-kit:remove": "node ./scripts/dev-kit-remove.js",
|
|
36
|
+
"dev-kit:docs": "open-swagger-ui http://localhost:3000/swagger",
|
|
36
37
|
"test": "jest --runInBand",
|
|
38
|
+
"test:all": "npm run lint && npm run prettier:check && npm run test && npm run test:sqlite",
|
|
37
39
|
"test:dev": "jest --watch",
|
|
38
40
|
"lint": "eslint --max-warnings=0 .",
|
|
39
41
|
"lint:watch": "esw --watch --color",
|
|
@@ -49,6 +51,7 @@
|
|
|
49
51
|
"test:mariadb": "sh ./scripts/test-mariadb.sh",
|
|
50
52
|
"test:sqlite": "sh ./scripts/test-sqlite.sh",
|
|
51
53
|
"prettier:check": "prettier --check .",
|
|
54
|
+
"prettier:write": "prettier --write .",
|
|
52
55
|
"prepare": "husky install"
|
|
53
56
|
},
|
|
54
57
|
"dependencies": {
|
|
@@ -56,6 +59,7 @@
|
|
|
56
59
|
"change-case": "^4.1.2",
|
|
57
60
|
"connect": "^3.7.0",
|
|
58
61
|
"dotenv": "^16.3.1",
|
|
62
|
+
"formidable": "^3.5.1",
|
|
59
63
|
"knex": "^2.5.1",
|
|
60
64
|
"knex-paginate": "^3.1.1",
|
|
61
65
|
"knex-schema-inspector": "^3.0.1",
|
|
@@ -66,44 +70,44 @@
|
|
|
66
70
|
"validatorjs": "^3.22.1"
|
|
67
71
|
},
|
|
68
72
|
"devDependencies": {
|
|
69
|
-
"@babel/core": "^7.22.
|
|
70
|
-
"@babel/preset-env": "^7.22.
|
|
71
|
-
"@babel/preset-typescript": "^7.22.
|
|
73
|
+
"@babel/core": "^7.22.11",
|
|
74
|
+
"@babel/preset-env": "^7.22.14",
|
|
75
|
+
"@babel/preset-typescript": "^7.22.11",
|
|
72
76
|
"@types/accept-language-parser": "^1.5.3",
|
|
73
77
|
"@types/aws-lambda": "^8.10.119",
|
|
74
78
|
"@types/cors": "^2.8.13",
|
|
75
|
-
"@types/formidable": "^3.4.
|
|
79
|
+
"@types/formidable": "^3.4.2",
|
|
76
80
|
"@types/multer": "^1.4.7",
|
|
77
81
|
"@types/pluralize": "^0.0.30",
|
|
78
82
|
"@types/validatorjs": "^3.15.0",
|
|
79
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
80
|
-
"@typescript-eslint/parser": "^5.
|
|
81
|
-
"babel-jest": "^29.6.
|
|
83
|
+
"@typescript-eslint/eslint-plugin": "^6.5.0",
|
|
84
|
+
"@typescript-eslint/parser": "^6.5.0",
|
|
85
|
+
"babel-jest": "^29.6.4",
|
|
82
86
|
"cors": "^2.8.5",
|
|
83
|
-
"eslint": "^
|
|
84
|
-
"eslint-config-standard": "^
|
|
87
|
+
"eslint": "^8.48.0",
|
|
88
|
+
"eslint-config-standard": "^17.1.0",
|
|
85
89
|
"eslint-plugin-import": "^2.28.1",
|
|
86
90
|
"eslint-plugin-node": "^11.1.0",
|
|
87
|
-
"eslint-plugin-promise": "^
|
|
88
|
-
"eslint-plugin-unicorn": "^
|
|
89
|
-
"eslint-watch": "^
|
|
90
|
-
"
|
|
91
|
-
"glob": "^9.3.5",
|
|
91
|
+
"eslint-plugin-promise": "^6.1.1",
|
|
92
|
+
"eslint-plugin-unicorn": "^48.0.1",
|
|
93
|
+
"eslint-watch": "^8.0.0",
|
|
94
|
+
"glob": "^10.3.4",
|
|
92
95
|
"husky": "^8.0.3",
|
|
93
|
-
"jest": "^29.6.
|
|
94
|
-
"lint-staged": "^
|
|
96
|
+
"jest": "^29.6.4",
|
|
97
|
+
"lint-staged": "^14.0.1",
|
|
95
98
|
"multer": "^1.4.5-lts.1",
|
|
96
99
|
"mysql": "^2.18.1",
|
|
97
100
|
"node-cache": "^5.1.2",
|
|
98
101
|
"node-color-log": "^10.0.2",
|
|
99
|
-
"nodemon": "^
|
|
102
|
+
"nodemon": "^3.0.1",
|
|
103
|
+
"open-swagger-ui": "^1.2.0",
|
|
100
104
|
"pg": "^8.11.3",
|
|
101
|
-
"prettier": "^
|
|
102
|
-
"redis": "^4.6.
|
|
105
|
+
"prettier": "^3.0.3",
|
|
106
|
+
"redis": "^4.6.8",
|
|
103
107
|
"set-value": ">=4.1.0",
|
|
104
108
|
"sqlite3": "^5.1.6",
|
|
105
109
|
"ts-node": "^10.9.1",
|
|
106
|
-
"typescript": "^5.
|
|
110
|
+
"typescript": "^5.2.2"
|
|
107
111
|
},
|
|
108
112
|
"lint-staged": {
|
|
109
113
|
"**/*": "prettier --write --ignore-unknown"
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
const Services_1 = require("../Services");
|
|
13
|
-
exports.default = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
14
|
-
const docs = Services_1.DocumentationService.getInstance();
|
|
15
|
-
const api = Services_1.APIService.getInstance();
|
|
16
|
-
res.json({
|
|
17
|
-
routes: docs.get(),
|
|
18
|
-
versions: api.versions.map((version) => {
|
|
19
|
-
return Object.assign(Object.assign({}, version), { config: Object.assign(Object.assign({}, version.config), { transaction: undefined }), folders: undefined, modelList: undefined, models: version.modelList.get() });
|
|
20
|
-
}),
|
|
21
|
-
});
|
|
22
|
-
});
|
|
File without changes
|