axe-api 0.18.0 → 0.19.2
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/.github/workflows/test-integration.yml +1 -1
- package/.github/workflows/test-unit.yml +1 -1
- package/CHANGELOG.md +28 -0
- package/package.json +17 -17
- package/readme.md +89 -12
- package/src/constants.js +14 -4
- package/src/core/Model.js +2 -3
- package/src/handlers/all.js +73 -0
- package/src/handlers/index.js +3 -2
- package/src/handlers/paginate.js +3 -3
- package/src/handlers/{autosave.js → patch.js} +1 -1
- package/src/handlers/show.js +3 -3
- package/src/handlers/store.js +7 -2
- package/src/resolvers/setExpressRoutes.js +15 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Release Notes
|
|
2
2
|
|
|
3
|
+
## [0.19.2 (2022-01-22)](https://github.com/axe-api/axe-api/compare/0.19.2...0.19.1)
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Fixed the calling `onBeforePaginate` and `onBeforeShow` hooks bug.
|
|
8
|
+
|
|
9
|
+
## [0.19.1 (2022-01-22)](https://github.com/axe-api/axe-api/compare/0.19.1...0.19.0)
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- knex.js version update.
|
|
14
|
+
|
|
15
|
+
## [0.19.0 (2021-12-05)](https://github.com/axe-api/axe-api/compare/0.19.0...0.18.1)
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- [#110](https://github.com/axe-api/axe-api/issues/110)
|
|
20
|
+
|
|
21
|
+
### Enhancements
|
|
22
|
+
|
|
23
|
+
- [#106](https://github.com/axe-api/axe-api/issues/106)
|
|
24
|
+
|
|
25
|
+
## [0.18.1 (2021-12-02)](https://github.com/axe-api/axe-api/compare/0.18.1...0.18.0)
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- [#117](https://github.com/axe-api/axe-api/issues/117)
|
|
30
|
+
|
|
3
31
|
## [0.18.0 (2021-11-30)](https://github.com/axe-api/axe-api/compare/0.18.0...0.17.5)
|
|
4
32
|
|
|
5
33
|
### Fixed
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "axe-api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.2",
|
|
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": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -20,37 +20,37 @@
|
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"change-case": "^4.1.2",
|
|
23
|
-
"dotenv": "^
|
|
24
|
-
"express": "^4.17.
|
|
25
|
-
"knex": "^0.
|
|
23
|
+
"dotenv": "^14.2.0",
|
|
24
|
+
"express": "^4.17.2",
|
|
25
|
+
"knex": "^1.0.1",
|
|
26
26
|
"knex-paginate": "^3.0.0",
|
|
27
|
-
"knex-schema-inspector": "^1.
|
|
27
|
+
"knex-schema-inspector": "^1.7.1",
|
|
28
28
|
"pluralize": "^8.0.0",
|
|
29
29
|
"validatorjs": "^3.22.1"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@babel/cli": "^7.
|
|
33
|
-
"@babel/core": "^7.
|
|
34
|
-
"@babel/node": "^7.
|
|
35
|
-
"@babel/preset-env": "^7.
|
|
36
|
-
"@babel/runtime": "^7.
|
|
37
|
-
"babel-jest": "^27.
|
|
38
|
-
"babel-loader": "^8.2.
|
|
32
|
+
"@babel/cli": "^7.16.8",
|
|
33
|
+
"@babel/core": "^7.16.10",
|
|
34
|
+
"@babel/node": "^7.16.8",
|
|
35
|
+
"@babel/preset-env": "^7.16.11",
|
|
36
|
+
"@babel/runtime": "^7.16.7",
|
|
37
|
+
"babel-jest": "^27.4.6",
|
|
38
|
+
"babel-loader": "^8.2.3",
|
|
39
39
|
"babel-plugin-module-resolver": "^4.1.0",
|
|
40
40
|
"babel-preset-minify": "^0.5.1",
|
|
41
41
|
"eslint": "^7.31.0",
|
|
42
42
|
"eslint-config-standard": "^16.0.3",
|
|
43
|
-
"eslint-plugin-import": "^2.
|
|
43
|
+
"eslint-plugin-import": "^2.25.4",
|
|
44
44
|
"eslint-plugin-node": "^11.1.0",
|
|
45
45
|
"eslint-plugin-promise": "^5.1.0",
|
|
46
46
|
"eslint-plugin-standard": "^5.0.0",
|
|
47
47
|
"eslint-plugin-unicorn": "^33.0.1",
|
|
48
48
|
"eslint-watch": "^7.0.0",
|
|
49
|
-
"jest": "^27.
|
|
49
|
+
"jest": "^27.4.7",
|
|
50
50
|
"mysql": "^2.18.1",
|
|
51
|
-
"nodemon": "^2.0.
|
|
52
|
-
"pg": "^8.
|
|
53
|
-
"set-value": ">=4.
|
|
51
|
+
"nodemon": "^2.0.15",
|
|
52
|
+
"pg": "^8.7.1",
|
|
53
|
+
"set-value": ">=4.1.0",
|
|
54
54
|
"sqlite3": "^5.0.2"
|
|
55
55
|
}
|
|
56
56
|
}
|
package/readme.md
CHANGED
|
@@ -23,21 +23,98 @@
|
|
|
23
23
|
</a>
|
|
24
24
|
</h1>
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
The fastest way to create Rest API, by defining database models and relations.
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
> Axe API has great documentation. Please [check it out in here](https://axe-api.github.io/).
|
|
29
29
|
|
|
30
|
-
##
|
|
30
|
+
## What Is Axe API?
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
-
|
|
32
|
+
**Axe API** is the _fastest_ way to create **Rest API** by defining only database models and relationships between them. It is built on [Knex.js](http://knexjs.org), and its awesome active records pattern. On the other hand, you have another familiar thing, [Express](https://expressjs.com/).
|
|
33
|
+
|
|
34
|
+
You are going to be able to develop an API **10 times faster** with **Axe API**!
|
|
35
|
+
|
|
36
|
+
## How It Works?
|
|
37
|
+
|
|
38
|
+
[Express](https://expressjs.com/) and [Knex.js](http://knexjs.org) are great tools to create [Node.js](https://nodejs.org) based applications. But usually, we code too much the same things to design an API. We aim to reduce code duplication and give you speed by using Axe API.
|
|
39
|
+
|
|
40
|
+
Axe API provides you the ability to separate your common tasks to build an API from your business logic. **Axe API** expects model definitions to analyze your routing structure. After you created your models and their relations between them, Axe API can handle all _well-known_ API requests. Creating an API with 5 tables takes almost 15 minutes.
|
|
41
|
+
|
|
42
|
+
Shortly, **Axe API** performs three basic functions;
|
|
43
|
+
|
|
44
|
+
- **Analyzes** your models and their relationships to create routes.
|
|
45
|
+
- **Handles** all HTTP requests.
|
|
46
|
+
- **Separate** your business logic from API best practices.
|
|
47
|
+
|
|
48
|
+
Let's assume that you have a model like this;
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
import { Model } from "axe-api";
|
|
52
|
+
|
|
53
|
+
class User extends Model {}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
With this model, you will have all of the basic API routes for **User** resources. **Axe API** will create **CRUD** routes for you in the _booting_ process and these routes would be completely ready to be handled and processed by Axe API. The following routes will be handled automatically;
|
|
57
|
+
|
|
58
|
+
- `POST api/users`
|
|
59
|
+
- `GET api/users`
|
|
60
|
+
- `GET api/users/:id`
|
|
61
|
+
- `PUT api/users/:id`
|
|
62
|
+
- `DELETE api/users/:id`
|
|
63
|
+
|
|
64
|
+
This is the magic of **Axe API**!
|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
Using **Axe API** in an application is very easy. We've created a CLI tool for you; [axe-magic](https://github.com/axe-api/axe-magic).
|
|
69
|
+
|
|
70
|
+
You can create a new Axe API project by using [axe-magic](https://github.com/axe-api/axe-magic). But first, you can install it in your development environment. When you installed it, you can be able to access **axe-magic** command via CLI. You can use the following command to install **axe-magic** to your machine;
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
$ npm i -g axe-magic
|
|
74
|
+
$ axe-magic --version
|
|
75
|
+
1.0.0
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
After that, creating a new project is very easy. Just you can execute the following command;
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
$ axe-magic new my-api
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
This command will pull [axe-api-template](https://github.com/axe-api/axe-api-template) project to your current directory with a new name, **my-api**.
|
|
85
|
+
|
|
86
|
+
To install your project's depencies, you can execute the following commands in the root directory;
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
$ cd my-api
|
|
90
|
+
$ npm install
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
To serve this application, you can execute the following command;
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
$ npm run start:dev
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
> `start:dev` command use [nodemon](https://www.npmjs.com/package/nodemon). If you haven't installed it yet, we suggest you install it first.
|
|
100
|
+
|
|
101
|
+
After that, your first **Axe API** application will be running in `localhost:3000`.
|
|
102
|
+
|
|
103
|
+
You will see the following API response if you visit [localhost:3000](http://localhost:3000).
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"name": "AXE API",
|
|
108
|
+
"description": "The best API creation tool in the world.",
|
|
109
|
+
"aim": "To kill them all!"
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
If you can see that response, it means that your project is running properly.
|
|
114
|
+
|
|
115
|
+
## Documentation
|
|
116
|
+
|
|
117
|
+
Axe API has great documentation. Please [check it out in here](https://axe-api.github.io/).
|
|
41
118
|
|
|
42
119
|
## How To Run Integration Tests
|
|
43
120
|
|
package/src/constants.js
CHANGED
|
@@ -13,6 +13,7 @@ const HOOK_FUNCTIONS = {
|
|
|
13
13
|
onBeforeDeleteQuery: "onBeforeDeleteQuery",
|
|
14
14
|
onBeforeDelete: "onBeforeDelete",
|
|
15
15
|
onBeforePaginate: "onBeforePaginate",
|
|
16
|
+
onBeforeAll: "onBeforeAll",
|
|
16
17
|
onBeforeShow: "onBeforeShow",
|
|
17
18
|
onAfterInsert: "onAfterInsert",
|
|
18
19
|
onAfterUpdateQuery: "onAfterUpdateQuery",
|
|
@@ -20,6 +21,7 @@ const HOOK_FUNCTIONS = {
|
|
|
20
21
|
onAfterDeleteQuery: "onAfterDeleteQuery",
|
|
21
22
|
onAfterDelete: "onAfterDelete",
|
|
22
23
|
onAfterPaginate: "onAfterPaginate",
|
|
24
|
+
onAfterAll: "onAfterAll",
|
|
23
25
|
onAfterShow: "onAfterShow",
|
|
24
26
|
};
|
|
25
27
|
|
|
@@ -52,7 +54,8 @@ const HANDLERS = {
|
|
|
52
54
|
SHOW: "show",
|
|
53
55
|
UPDATE: "update",
|
|
54
56
|
DELETE: "destroy",
|
|
55
|
-
|
|
57
|
+
PATCH: "patch",
|
|
58
|
+
ALL: "all",
|
|
56
59
|
};
|
|
57
60
|
|
|
58
61
|
const DEFAULT_HANDLERS = [
|
|
@@ -60,6 +63,7 @@ const DEFAULT_HANDLERS = [
|
|
|
60
63
|
HANDLERS.PAGINATE,
|
|
61
64
|
HANDLERS.SHOW,
|
|
62
65
|
HANDLERS.UPDATE,
|
|
66
|
+
HANDLERS.PATCH,
|
|
63
67
|
HANDLERS.DELETE,
|
|
64
68
|
];
|
|
65
69
|
|
|
@@ -68,6 +72,7 @@ const HTTP_METHODS = {
|
|
|
68
72
|
GET: "GET",
|
|
69
73
|
PUT: "PUT",
|
|
70
74
|
DELETE: "DELETE",
|
|
75
|
+
PATCH: "PATCH",
|
|
71
76
|
};
|
|
72
77
|
|
|
73
78
|
const API_ROUTE_TEMPLATES = {
|
|
@@ -79,6 +84,11 @@ const API_ROUTE_TEMPLATES = {
|
|
|
79
84
|
url: (prefix, parentUrl, resource) => `/${prefix}/${parentUrl}${resource}`,
|
|
80
85
|
method: HTTP_METHODS.GET,
|
|
81
86
|
},
|
|
87
|
+
[HANDLERS.ALL]: {
|
|
88
|
+
url: (prefix, parentUrl, resource) =>
|
|
89
|
+
`/${prefix}/${parentUrl}${resource}/all`,
|
|
90
|
+
method: HTTP_METHODS.GET,
|
|
91
|
+
},
|
|
82
92
|
[HANDLERS.SHOW]: {
|
|
83
93
|
url: (prefix, parentUrl, resource, primaryKey) =>
|
|
84
94
|
`/${prefix}/${parentUrl}${resource}/:${primaryKey}`,
|
|
@@ -89,10 +99,10 @@ const API_ROUTE_TEMPLATES = {
|
|
|
89
99
|
`/${prefix}/${parentUrl}${resource}/:${primaryKey}`,
|
|
90
100
|
method: HTTP_METHODS.PUT,
|
|
91
101
|
},
|
|
92
|
-
[HANDLERS.
|
|
102
|
+
[HANDLERS.PATCH]: {
|
|
93
103
|
url: (prefix, parentUrl, resource, primaryKey) =>
|
|
94
|
-
`/${prefix}/${parentUrl}${resource}/:${primaryKey}
|
|
95
|
-
method: HTTP_METHODS.
|
|
104
|
+
`/${prefix}/${parentUrl}${resource}/:${primaryKey}`,
|
|
105
|
+
method: HTTP_METHODS.PATCH,
|
|
96
106
|
},
|
|
97
107
|
[HANDLERS.DELETE]: {
|
|
98
108
|
url: (prefix, parentUrl, resource, primaryKey) =>
|
package/src/core/Model.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import pluralize from "pluralize";
|
|
2
2
|
import { snakeCase } from "snake-case";
|
|
3
|
-
import { RELATIONSHIPS,
|
|
4
|
-
const { INSERT, SHOW, UPDATE, PAGINATE, DELETE } = HANDLERS;
|
|
3
|
+
import { RELATIONSHIPS, DEFAULT_HANDLERS } from "./../constants.js";
|
|
5
4
|
|
|
6
5
|
class Model {
|
|
7
6
|
constructor() {
|
|
@@ -25,7 +24,7 @@ class Model {
|
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
get handlers() {
|
|
28
|
-
return [
|
|
27
|
+
return [...DEFAULT_HANDLERS];
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
get middlewares() {
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import {
|
|
2
|
+
callHooks,
|
|
3
|
+
getRelatedData,
|
|
4
|
+
filterHiddenFields,
|
|
5
|
+
serializeData,
|
|
6
|
+
addForeignKeyQuery,
|
|
7
|
+
} from "./helpers.js";
|
|
8
|
+
import { HOOK_FUNCTIONS, HANDLERS } from "./../constants.js";
|
|
9
|
+
import QueryParser from "./../core/QueryParser.js";
|
|
10
|
+
|
|
11
|
+
export default async (context) => {
|
|
12
|
+
const { request, response, model, models, trx, relation, parentModel } =
|
|
13
|
+
context;
|
|
14
|
+
|
|
15
|
+
const queryParser = new QueryParser({ model, models });
|
|
16
|
+
|
|
17
|
+
// We should parse URL query string to use as condition in Lucid query
|
|
18
|
+
const conditions = queryParser.get(request.query);
|
|
19
|
+
|
|
20
|
+
// Creating a new database query
|
|
21
|
+
const query = trx.from(model.instance.table);
|
|
22
|
+
|
|
23
|
+
// Users should be able to select some fields to show.
|
|
24
|
+
queryParser.applyFields(query, conditions.fields);
|
|
25
|
+
|
|
26
|
+
// Binding parent id if there is.
|
|
27
|
+
addForeignKeyQuery(request, query, relation, parentModel);
|
|
28
|
+
|
|
29
|
+
// Users should be able to filter records
|
|
30
|
+
queryParser.applyWheres(query, conditions.q);
|
|
31
|
+
|
|
32
|
+
await callHooks(model, HOOK_FUNCTIONS.onBeforeAll, {
|
|
33
|
+
...context,
|
|
34
|
+
conditions,
|
|
35
|
+
query,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// User should be able to select sorting fields and types
|
|
39
|
+
queryParser.applySorting(query, conditions.sort);
|
|
40
|
+
|
|
41
|
+
const result = await query;
|
|
42
|
+
|
|
43
|
+
// We should try to get related data if there is any
|
|
44
|
+
await getRelatedData(
|
|
45
|
+
result.data,
|
|
46
|
+
conditions.with,
|
|
47
|
+
model,
|
|
48
|
+
models,
|
|
49
|
+
trx,
|
|
50
|
+
HANDLERS.ALL,
|
|
51
|
+
request
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
await callHooks(model, HOOK_FUNCTIONS.onAfterAll, {
|
|
55
|
+
...context,
|
|
56
|
+
result,
|
|
57
|
+
conditions,
|
|
58
|
+
query,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Serializing the data by the model's serialize method
|
|
62
|
+
result.data = await serializeData(
|
|
63
|
+
result.data,
|
|
64
|
+
model.instance.serialize,
|
|
65
|
+
HANDLERS.ALL,
|
|
66
|
+
request
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
// Filtering hidden fields from the response data.
|
|
70
|
+
filterHiddenFields(result.data, model.instance.hiddens);
|
|
71
|
+
|
|
72
|
+
return response.json(result);
|
|
73
|
+
};
|
package/src/handlers/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import all from "./all.js";
|
|
2
|
+
import patch from "./patch.js";
|
|
2
3
|
import store from "./store.js";
|
|
3
4
|
import show from "./show.js";
|
|
4
5
|
import paginate from "./paginate.js";
|
|
5
6
|
import update from "./update.js";
|
|
6
7
|
import destroy from "./destroy.js";
|
|
7
8
|
|
|
8
|
-
export default {
|
|
9
|
+
export default { all, patch, store, show, paginate, update, destroy };
|
package/src/handlers/paginate.js
CHANGED
|
@@ -26,15 +26,15 @@ export default async (context) => {
|
|
|
26
26
|
// Binding parent id if there is.
|
|
27
27
|
addForeignKeyQuery(request, query, relation, parentModel);
|
|
28
28
|
|
|
29
|
-
// Users should be able to filter records
|
|
30
|
-
queryParser.applyWheres(query, conditions.q);
|
|
31
|
-
|
|
32
29
|
await callHooks(model, HOOK_FUNCTIONS.onBeforePaginate, {
|
|
33
30
|
...context,
|
|
34
31
|
conditions,
|
|
35
32
|
query,
|
|
36
33
|
});
|
|
37
34
|
|
|
35
|
+
// Users should be able to filter records
|
|
36
|
+
queryParser.applyWheres(query, conditions.q);
|
|
37
|
+
|
|
38
38
|
// User should be able to select sorting fields and types
|
|
39
39
|
queryParser.applySorting(query, conditions.sort);
|
|
40
40
|
|
package/src/handlers/show.js
CHANGED
|
@@ -26,9 +26,6 @@ export default async (context) => {
|
|
|
26
26
|
// If there is a relation, we should bind it
|
|
27
27
|
addForeignKeyQuery(request, query, relation, parentModel);
|
|
28
28
|
|
|
29
|
-
// Users should be able to filter records
|
|
30
|
-
queryParser.applyWheres(query, conditions.q);
|
|
31
|
-
|
|
32
29
|
// We should add this condition in here because of performance.
|
|
33
30
|
query.where(
|
|
34
31
|
model.instance.primaryKey,
|
|
@@ -41,6 +38,9 @@ export default async (context) => {
|
|
|
41
38
|
conditions,
|
|
42
39
|
});
|
|
43
40
|
|
|
41
|
+
// Users should be able to filter records
|
|
42
|
+
queryParser.applyWheres(query, conditions.q);
|
|
43
|
+
|
|
44
44
|
let item = await query.first();
|
|
45
45
|
if (!item) {
|
|
46
46
|
throw new HttpResponse(404, {
|
package/src/handlers/store.js
CHANGED
|
@@ -43,9 +43,14 @@ export default async (context) => {
|
|
|
43
43
|
formData,
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
const [returningResult] = await trx(model.instance.table)
|
|
47
47
|
.insert(formData)
|
|
48
|
-
.returning(
|
|
48
|
+
.returning(model.instance.primaryKey);
|
|
49
|
+
|
|
50
|
+
let insertedPrimaryKeyValue =
|
|
51
|
+
typeof returningResult === "number"
|
|
52
|
+
? returningResult
|
|
53
|
+
: returningResult[model.instance.primaryKey];
|
|
49
54
|
|
|
50
55
|
// If the user use a special primary key value, we should use that value
|
|
51
56
|
if (insertedPrimaryKeyValue === 0) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import IoC from "./../core/IoC.js";
|
|
2
2
|
import pluralize from "pluralize";
|
|
3
|
-
import { paramCase } from "change-case";
|
|
3
|
+
import { paramCase, camelCase } from "change-case";
|
|
4
4
|
import { RELATIONSHIPS, API_ROUTE_TEMPLATES } from "./../constants.js";
|
|
5
5
|
import Handlers from "./../handlers/index.js";
|
|
6
6
|
|
|
@@ -122,7 +122,7 @@ const createNestedRoutes = async (
|
|
|
122
122
|
await createRouteByModel(
|
|
123
123
|
model,
|
|
124
124
|
models,
|
|
125
|
-
`${urlPrefix}${resource}/:${
|
|
125
|
+
`${urlPrefix}${resource}/:${camelCase(relation.foreignKey)}/`,
|
|
126
126
|
model,
|
|
127
127
|
relation,
|
|
128
128
|
false
|
|
@@ -164,11 +164,19 @@ const getModelMiddlewares = (model, handler) => {
|
|
|
164
164
|
return middlewares;
|
|
165
165
|
};
|
|
166
166
|
|
|
167
|
-
const getRootPrefix = () => {
|
|
168
|
-
|
|
169
|
-
|
|
167
|
+
export const getRootPrefix = async () => {
|
|
168
|
+
const config = await IoC.use("Config");
|
|
169
|
+
let prefix = config?.Application?.prefix || "api";
|
|
170
|
+
|
|
171
|
+
if (prefix.substr(0, 1) === "/") {
|
|
172
|
+
prefix = prefix.substr(1);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (prefix.substr(prefix.length - 1) === "/") {
|
|
176
|
+
prefix = prefix.substr(0, prefix.length - 1);
|
|
170
177
|
}
|
|
171
|
-
|
|
178
|
+
|
|
179
|
+
return prefix;
|
|
172
180
|
};
|
|
173
181
|
|
|
174
182
|
const createRouteByModel = async (
|
|
@@ -208,7 +216,7 @@ const createRouteByModel = async (
|
|
|
208
216
|
|
|
209
217
|
const routeTemplate = API_ROUTE_TEMPLATES[handler];
|
|
210
218
|
const url = routeTemplate.url(
|
|
211
|
-
getRootPrefix(),
|
|
219
|
+
await getRootPrefix(),
|
|
212
220
|
urlPrefix,
|
|
213
221
|
resource,
|
|
214
222
|
model.instance.primaryKey
|