axe-api 0.20.3 → 0.21.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 +14 -0
- package/build/src/Builders/RouterBuilder.js +16 -7
- package/build/src/Handlers/AllHandler.d.ts +0 -1
- package/build/src/Handlers/DestroyHandler.d.ts +0 -1
- package/build/src/Handlers/PaginateHandler.d.ts +0 -1
- package/build/src/Handlers/PatchHandler.d.ts +0 -1
- package/build/src/Handlers/PatchHandler.js +3 -0
- package/build/src/Handlers/ShowHandler.d.ts +0 -1
- package/build/src/Handlers/StoreHandler.d.ts +0 -1
- package/build/src/Handlers/StoreHandler.js +3 -0
- package/build/src/Handlers/UpdateHandler.d.ts +0 -1
- package/build/src/Handlers/UpdateHandler.js +3 -0
- package/build/src/Interfaces.d.ts +11 -0
- package/build/src/Middlewares/acceptLanguageMiddleware.d.ts +3 -0
- package/build/src/Middlewares/acceptLanguageMiddleware.js +24 -0
- package/build/src/Middlewares/index.d.ts +2 -0
- package/build/src/Middlewares/index.js +8 -0
- package/build/src/Resolvers/AcceptLanguageResolver.d.ts +7 -0
- package/build/src/Resolvers/AcceptLanguageResolver.js +66 -0
- package/build/src/Resolvers/index.d.ts +2 -1
- package/build/src/Resolvers/index.js +3 -1
- package/build/src/Services/QueryService.js +11 -1
- package/package.json +10 -5
- package/readme.md +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Release Notes
|
|
2
2
|
|
|
3
|
+
## [0.21.0 (2022-12-28)](https://github.com/axe-api/axe-api/compare/0.21.0...0.20.4)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- Added `i18n` support. [#44](https://github.com/axe-api/axe-api/issues/44)
|
|
8
|
+
|
|
9
|
+
## [0.20.4 (2022-12-24)](https://github.com/axe-api/axe-api/compare/0.20.4...0.20.3)
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Fixed [#124](https://github.com/axe-api/axe-api/issues/124)
|
|
14
|
+
- Throwing errors in the `development` environment has been fixed.
|
|
15
|
+
- Unbuilt integration test issue has been fixed.
|
|
16
|
+
|
|
3
17
|
## [0.20.3 (2022-12-24)](https://github.com/axe-api/axe-api/compare/0.20.3...0.20.0)
|
|
4
18
|
|
|
5
19
|
### Fixed
|
|
@@ -19,6 +19,7 @@ const Resolvers_1 = require("../Resolvers");
|
|
|
19
19
|
const constants_1 = require("../constants");
|
|
20
20
|
const Enums_1 = require("../Enums");
|
|
21
21
|
const Services_1 = require("../Services");
|
|
22
|
+
const Middlewares_1 = require("../Middlewares");
|
|
22
23
|
class RouterBuilder {
|
|
23
24
|
constructor() {
|
|
24
25
|
this.getPrimaryKeyName = (model) => {
|
|
@@ -52,10 +53,10 @@ class RouterBuilder {
|
|
|
52
53
|
generalHooks.onBeforeInit(app);
|
|
53
54
|
}
|
|
54
55
|
yield this.createRoutesByModelTree(modelTree, modelList);
|
|
56
|
+
logger.info("Express routes have been created.");
|
|
55
57
|
if (generalHooks.onAfterInit) {
|
|
56
58
|
generalHooks.onAfterInit(app);
|
|
57
59
|
}
|
|
58
|
-
logger.info("Express routes have been created.");
|
|
59
60
|
});
|
|
60
61
|
}
|
|
61
62
|
createRoutesByModelTree(modelTree, modelList) {
|
|
@@ -79,8 +80,13 @@ class RouterBuilder {
|
|
|
79
80
|
}
|
|
80
81
|
const urlCreator = constants_1.API_ROUTE_TEMPLATES[handlerType];
|
|
81
82
|
const url = urlCreator(yield this.getRootPrefix(), urlPrefix, resource, model.instance.primaryKey);
|
|
82
|
-
//
|
|
83
|
-
|
|
83
|
+
// Creating the middleware list for the route. As default, we support some
|
|
84
|
+
// internal middlewares such as `Accept Language Middleware` which parse
|
|
85
|
+
// the "accept-language" header to use in the application general.
|
|
86
|
+
const middlewares = [
|
|
87
|
+
Middlewares_1.acceptLanguageMiddleware,
|
|
88
|
+
...model.instance.getMiddlewares(handlerType),
|
|
89
|
+
];
|
|
84
90
|
// Adding the route to the express
|
|
85
91
|
yield this.addExpressRoute(handlerType, url, middlewares, model, parentModel, relation);
|
|
86
92
|
}
|
|
@@ -204,10 +210,13 @@ class RouterBuilder {
|
|
|
204
210
|
});
|
|
205
211
|
break;
|
|
206
212
|
default:
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
213
|
+
// We should not show the real errors on production
|
|
214
|
+
if (process.env.NODE_ENV === "production") {
|
|
215
|
+
res.status(http_status_codes_1.StatusCodes.INTERNAL_SERVER_ERROR).json({
|
|
216
|
+
error: "An error occurredxx.",
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
throw error;
|
|
211
220
|
}
|
|
212
221
|
}
|
|
213
222
|
getResourcePath(model, relation) {
|
|
@@ -35,6 +35,9 @@ exports.default = (pack) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
35
35
|
const formData = Object.assign(Object.assign({}, item), (0, Helpers_1.getMergedFormData)(req, fillables));
|
|
36
36
|
const validationRules = model.instance.getValidationRules(requestMethod);
|
|
37
37
|
if (validationRules) {
|
|
38
|
+
// The validation language should be set
|
|
39
|
+
validatorjs_1.default.useLang(req.currentLanguage.language);
|
|
40
|
+
// Validate the data
|
|
38
41
|
const validation = new validatorjs_1.default(formData, validationRules);
|
|
39
42
|
if (validation.fails()) {
|
|
40
43
|
return res.status(400).json(validation.errors);
|
|
@@ -22,6 +22,9 @@ exports.default = (pack) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
22
22
|
const formData = (0, Helpers_1.getMergedFormData)(req, fillables);
|
|
23
23
|
const validationRules = model.instance.getValidationRules(requestMethod);
|
|
24
24
|
if (validationRules) {
|
|
25
|
+
// The validation language should be set
|
|
26
|
+
validatorjs_1.default.useLang(req.currentLanguage.language);
|
|
27
|
+
// Validate the data
|
|
25
28
|
const validation = new validatorjs_1.default(formData, validationRules);
|
|
26
29
|
if (validation.fails()) {
|
|
27
30
|
return res.status(400).json(validation.errors);
|
|
@@ -35,6 +35,9 @@ exports.default = (pack) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
35
35
|
const formData = (0, Helpers_1.getMergedFormData)(req, fillables);
|
|
36
36
|
const validationRules = model.instance.getValidationRules(requestMethod);
|
|
37
37
|
if (validationRules) {
|
|
38
|
+
// The validation language should be set
|
|
39
|
+
validatorjs_1.default.useLang(req.currentLanguage.language);
|
|
40
|
+
// Validate the data
|
|
38
41
|
const validation = new validatorjs_1.default(formData, validationRules);
|
|
39
42
|
if (validation.fails()) {
|
|
40
43
|
return res.status(400).json(validation.errors);
|
|
@@ -23,6 +23,17 @@ export interface IApplicationConfig extends IConfig {
|
|
|
23
23
|
prefix: string;
|
|
24
24
|
transaction: boolean | IHandlerBasedTransactionConfig | IHandlerBasedTransactionConfig[];
|
|
25
25
|
serializers: ((data: any, request: Request) => void)[] | IHandlerBasedSerializer[];
|
|
26
|
+
supportedLanguages: string[];
|
|
27
|
+
defaultLanguage: string;
|
|
28
|
+
}
|
|
29
|
+
export interface ILanguage {
|
|
30
|
+
title: string;
|
|
31
|
+
language: string;
|
|
32
|
+
region?: string | null;
|
|
33
|
+
}
|
|
34
|
+
export interface IAcceptedLanguage {
|
|
35
|
+
language: ILanguage;
|
|
36
|
+
quality: number;
|
|
26
37
|
}
|
|
27
38
|
export declare type IDatabaseConfig = Knex.Config;
|
|
28
39
|
export interface IFolders {
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
const Resolvers_1 = require("../Resolvers");
|
|
14
|
+
exports.default = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
15
|
+
// Application configuration is need for the default setting.
|
|
16
|
+
const configs = yield Services_1.IoCService.use("Config");
|
|
17
|
+
const application = configs.Application;
|
|
18
|
+
const { supportedLanguages, defaultLanguage } = application;
|
|
19
|
+
// Setting the current language by the supported, default and the client prefences
|
|
20
|
+
req.currentLanguage = Resolvers_1.AcceptLanguageResolver.resolve(req.get("accept-language") || "", supportedLanguages || ["en"], defaultLanguage || "en");
|
|
21
|
+
// Adding the `Content-Language` header to the response object
|
|
22
|
+
res.setHeader("Content-Language", req.currentLanguage.title);
|
|
23
|
+
next();
|
|
24
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.acceptLanguageMiddleware = void 0;
|
|
7
|
+
const acceptLanguageMiddleware_1 = __importDefault(require("./acceptLanguageMiddleware"));
|
|
8
|
+
exports.acceptLanguageMiddleware = acceptLanguageMiddleware_1.default;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ILanguage } from "../Interfaces";
|
|
2
|
+
declare class AcceptLanguageResolver {
|
|
3
|
+
static resolve(value: string, supportedLanguages: string[], defaultLanguage: string): ILanguage;
|
|
4
|
+
static toLanguageObject(key?: string): ILanguage;
|
|
5
|
+
private static toSortedPreferences;
|
|
6
|
+
}
|
|
7
|
+
export default AcceptLanguageResolver;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
class AcceptLanguageResolver {
|
|
4
|
+
static resolve(value, supportedLanguages, defaultLanguage) {
|
|
5
|
+
value = value.trim();
|
|
6
|
+
if (value === "*") {
|
|
7
|
+
return this.toLanguageObject(defaultLanguage);
|
|
8
|
+
}
|
|
9
|
+
const languages = this.toSortedPreferences(value);
|
|
10
|
+
const perfectMatch = languages.find((item) => supportedLanguages.includes(item.language.title));
|
|
11
|
+
const anyMatch = languages.find((item) => supportedLanguages.includes(item.language.language));
|
|
12
|
+
if (perfectMatch && !anyMatch) {
|
|
13
|
+
return perfectMatch.language;
|
|
14
|
+
}
|
|
15
|
+
if (!perfectMatch && anyMatch) {
|
|
16
|
+
return anyMatch.language;
|
|
17
|
+
}
|
|
18
|
+
if (perfectMatch && anyMatch) {
|
|
19
|
+
if (perfectMatch.quality >= anyMatch.quality) {
|
|
20
|
+
return perfectMatch.language;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
return this.toLanguageObject(anyMatch.language.language);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return this.toLanguageObject(defaultLanguage);
|
|
27
|
+
}
|
|
28
|
+
static toLanguageObject(key = "") {
|
|
29
|
+
const [language, region] = key.split("-");
|
|
30
|
+
return {
|
|
31
|
+
title: key,
|
|
32
|
+
language,
|
|
33
|
+
region: region || null,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
static toSortedPreferences(value) {
|
|
37
|
+
// Splitting by language definitons
|
|
38
|
+
const keys = value.split(",").map((key) => key.trim());
|
|
39
|
+
const languages = [];
|
|
40
|
+
for (const key of keys) {
|
|
41
|
+
// Splitting by the quality values
|
|
42
|
+
const [code, quality] = key.split(";");
|
|
43
|
+
// Parsing the language code and the quality value
|
|
44
|
+
const item = {
|
|
45
|
+
language: this.toLanguageObject(code),
|
|
46
|
+
quality: quality ? parseFloat(quality.replace("q=", "")) : 1,
|
|
47
|
+
};
|
|
48
|
+
languages.push(item);
|
|
49
|
+
}
|
|
50
|
+
// Sorting ASC
|
|
51
|
+
languages.sort((a, b) => {
|
|
52
|
+
if (a.quality === b.quality) {
|
|
53
|
+
return 0;
|
|
54
|
+
}
|
|
55
|
+
if (a.quality === null) {
|
|
56
|
+
return 1;
|
|
57
|
+
}
|
|
58
|
+
if (b.quality === null) {
|
|
59
|
+
return -1;
|
|
60
|
+
}
|
|
61
|
+
return a.quality < b.quality ? 1 : -1;
|
|
62
|
+
});
|
|
63
|
+
return languages;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
exports.default = AcceptLanguageResolver;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import AcceptLanguageResolver from "./AcceptLanguageResolver";
|
|
1
2
|
import FileResolver from "./FileResolver";
|
|
2
3
|
import FolderResolver from "./FolderResolver";
|
|
3
4
|
import GeneralHookResolver from "./GeneralHookResolver";
|
|
4
5
|
import ModelResolver from "./ModelResolver";
|
|
5
6
|
import TransactionResolver from "./TransactionResolver";
|
|
6
7
|
import WithQueryResolver from "./WithQueryResolver";
|
|
7
|
-
export { FileResolver, FolderResolver, GeneralHookResolver, ModelResolver, TransactionResolver, WithQueryResolver, };
|
|
8
|
+
export { AcceptLanguageResolver, FileResolver, FolderResolver, GeneralHookResolver, ModelResolver, TransactionResolver, WithQueryResolver, };
|
|
@@ -3,7 +3,9 @@ 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.WithQueryResolver = exports.TransactionResolver = exports.ModelResolver = exports.GeneralHookResolver = exports.FolderResolver = exports.FileResolver = void 0;
|
|
6
|
+
exports.WithQueryResolver = exports.TransactionResolver = exports.ModelResolver = exports.GeneralHookResolver = exports.FolderResolver = exports.FileResolver = exports.AcceptLanguageResolver = void 0;
|
|
7
|
+
const AcceptLanguageResolver_1 = __importDefault(require("./AcceptLanguageResolver"));
|
|
8
|
+
exports.AcceptLanguageResolver = AcceptLanguageResolver_1.default;
|
|
7
9
|
const FileResolver_1 = __importDefault(require("./FileResolver"));
|
|
8
10
|
exports.FileResolver = FileResolver_1.default;
|
|
9
11
|
const FolderResolver_1 = __importDefault(require("./FolderResolver"));
|
|
@@ -346,7 +346,17 @@ class QueryService {
|
|
|
346
346
|
if (!relation) {
|
|
347
347
|
throw new ApiError_1.default(`Undefined relation: ${item.relationship}`);
|
|
348
348
|
}
|
|
349
|
-
|
|
349
|
+
// We should add the field by the relation type. Otherwise it can cause
|
|
350
|
+
// an error something like this; `users.user_id`. Foreign and primary keys
|
|
351
|
+
// are relative.
|
|
352
|
+
let columnName = "";
|
|
353
|
+
if (relation.type === Enums_1.Relationships.HAS_MANY) {
|
|
354
|
+
columnName = relation.primaryKey;
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
357
|
+
columnName = relation.foreignKey;
|
|
358
|
+
}
|
|
359
|
+
this.relationColumns.push(`${this.model.instance.table}.${columnName}`);
|
|
350
360
|
});
|
|
351
361
|
}
|
|
352
362
|
getConditionMethodName(ruleSet) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "axe-api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"description": "AXE API is a simple tool which has been created based on Express and Knex.js to create Rest APIs quickly.",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -15,15 +15,18 @@
|
|
|
15
15
|
"scripts": {
|
|
16
16
|
"build": "tsc",
|
|
17
17
|
"build:watch": "tsc -w",
|
|
18
|
-
"dev": "ts-node-dev --respawn --clear index.ts",
|
|
18
|
+
"dev": "ts-node-dev --files --respawn --clear index.ts",
|
|
19
|
+
"dev-kit": "ts-node-dev --respawn --clear dev-kit.ts",
|
|
20
|
+
"dev-kit:install": "sh ./scripts/dev-kit-install.sh",
|
|
21
|
+
"dev-kit:remove": "sh ./scripts/dev-kit-remove.sh",
|
|
19
22
|
"test": "jest --runInBand",
|
|
20
23
|
"test:dev": "jest --watch",
|
|
21
24
|
"lint": "eslint src/**",
|
|
22
25
|
"lint:watch": "esw --watch --color",
|
|
23
26
|
"prepare:integration": "nodemon --ignore \"./tests/**\" ./scripts/run-integration-test.js",
|
|
24
|
-
"test:
|
|
25
|
-
"test:
|
|
26
|
-
"test:
|
|
27
|
+
"test:postgres": "sh ./scripts/test-postgres.sh",
|
|
28
|
+
"test:mysql57": "sh ./scripts/test-mysql57.sh",
|
|
29
|
+
"test:mysql8": "sh ./scripts/test-mysql8.sh"
|
|
27
30
|
},
|
|
28
31
|
"dependencies": {
|
|
29
32
|
"@types/express": "^4.17.15",
|
|
@@ -41,6 +44,7 @@
|
|
|
41
44
|
"@babel/core": "^7.19.1",
|
|
42
45
|
"@babel/preset-env": "^7.19.1",
|
|
43
46
|
"@babel/preset-typescript": "^7.18.6",
|
|
47
|
+
"@types/accept-language-parser": "^1.5.3",
|
|
44
48
|
"@types/pluralize": "^0.0.29",
|
|
45
49
|
"@types/validatorjs": "^3.15.0",
|
|
46
50
|
"@typescript-eslint/eslint-plugin": "^5.37.0",
|
|
@@ -56,6 +60,7 @@
|
|
|
56
60
|
"glob": "^8.0.3",
|
|
57
61
|
"jest": "^29.0.3",
|
|
58
62
|
"mysql": "^2.18.1",
|
|
63
|
+
"node-color-log": "^10.0.2",
|
|
59
64
|
"nodemon": "^2.0.15",
|
|
60
65
|
"pg": "^8.7.1",
|
|
61
66
|
"set-value": ">=4.1.0",
|
package/readme.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<h1 align="center">
|
|
2
2
|
<br>
|
|
3
|
-
<a href="https://axe-api.
|
|
4
|
-
<img src="https://axe-api.
|
|
3
|
+
<a href="https://axe-api.com/">
|
|
4
|
+
<img src="https://axe-api.com/axe.png" alt="Markdownify" width="200">
|
|
5
5
|
</a>
|
|
6
6
|
<br>
|
|
7
7
|
Axe API
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
Next Generation Rest API Framework
|
|
27
27
|
|
|
28
|
-
> Axe API has great documentation. Please [check it out in here](https://axe-api.
|
|
28
|
+
> Axe API has great documentation. Please [check it out in here](https://axe-api.com/).
|
|
29
29
|
|
|
30
30
|
## What Is Axe API?
|
|
31
31
|
|
|
@@ -143,7 +143,7 @@ If you can see that response, it means that your project is running properly.
|
|
|
143
143
|
|
|
144
144
|
## Documentation
|
|
145
145
|
|
|
146
|
-
Axe API has great documentation. Please [check it out in here](https://axe-api.
|
|
146
|
+
Axe API has great documentation. Please [check it out in here](https://axe-api.com/).
|
|
147
147
|
|
|
148
148
|
## How To Run Integration Tests
|
|
149
149
|
|