minimonolith 0.25.23 → 0.26.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/README.md +55 -80
- package/backtest/back.js +54 -0
- package/backtest/backtest.js +131 -0
- package/backtest/handler.js +23 -0
- package/backtest/handlerCompiletimeError.js +10 -0
- package/backtest/handlerCompiletimeError2.js +10 -0
- package/backtest/handlerRuntimeError.js +24 -0
- package/backtest/localDocker/Dockerfile +11 -0
- package/backtest/localDocker/docker-compose.yml +34 -0
- package/backtest/localDocker/run.sh +4 -0
- package/backtest/localDocker/shutdown.sh +2 -0
- package/backtest/localDocker/update.sh +2 -0
- package/backtest/server.js +7 -0
- package/backtest/todo/delete/index.js +7 -0
- package/backtest/todo/delete/valid.js +8 -0
- package/backtest/todo/get/index.js +3 -0
- package/backtest/todo/getAttributes/index.js +5 -0
- package/backtest/todo/getAttributes/valid.js +5 -0
- package/backtest/todo/getOne/index.js +3 -0
- package/backtest/todo/getOne/valid.js +8 -0
- package/backtest/todo/getOneAlias/index.js +3 -0
- package/backtest/todo/getOneAlias/valid.js +3 -0
- package/backtest/todo/index.js +1 -0
- package/backtest/todo/model.js +19 -0
- package/backtest/todo/patch/index.js +6 -0
- package/backtest/todo/patch/valid.js +12 -0
- package/backtest/todo/post/index.js +5 -0
- package/backtest/todo/post/valid.js +5 -0
- package/backtest/todo/postSeed/index.js +9 -0
- package/backtest/todo/postSeed/seed.js +4 -0
- package/backtest/todoCompiletimeError/got/index.js +1 -0
- package/backtest/todoCompiletimeError/index.js +1 -0
- package/backtest/todoList/delete/handler.js +7 -0
- package/backtest/todoList/delete/valid.js +5 -0
- package/backtest/todoList/get/handler.js +5 -0
- package/backtest/todoList/index.js +1 -0
- package/backtest/todoList/model.js +17 -0
- package/backtest/todoList/post/handler.js +9 -0
- package/backtest/todoList/post/valid.js +6 -0
- package/backtest/todoRuntimeError/get/index.js +1 -0
- package/index.js +13 -22
- package/package.json +7 -8
- package/src/api/get/index.js +17 -0
- package/src/api/getNewAPI/index.js +11 -0
- package/src/api/getSyncedHandler/index.js +23 -0
- package/src/api/index.js +4 -0
- package/src/api/postService/index.js +29 -0
- package/src/autotest/getMethodTest/back.index.js +29 -0
- package/{autotest/getMethodTest/handler.js → src/autotest/getMethodTest/index.js} +1 -3
- package/src/autotest/index.js +3 -0
- package/src/database/index.js +4 -0
- package/src/database/post/index.js +38 -0
- package/src/database/postConnection/index.js +25 -0
- package/src/error/index.js +4 -0
- package/src/error/postCompiletime/index.js +13 -0
- package/src/error/postRuntime/index.js +7 -0
- package/src/event/getParsedEvent/index.js +9 -0
- package/src/event/index.js +3 -0
- package/src/log/index.js +5 -0
- package/src/log/post/index.js +3 -0
- package/src/log/postERROR/index.js +3 -0
- package/src/log/postINFO/index.js +3 -0
- package/src/method/getParsedCode/index.js +13 -0
- package/{service/getResponseCode/handler.js → src/method/getResponseCode/index.js} +1 -3
- package/src/method/getRouteCode/index.js +12 -0
- package/src/method/getType/index.js +9 -0
- package/src/method/index.js +7 -0
- package/src/method/post/index.js +44 -0
- package/src/method/postResponse/index.js +29 -0
- package/src/middleware/index.js +4 -0
- package/src/middleware/postCors/index.js +20 -0
- package/src/middleware/postError/index.js +10 -0
- package/src/model/getSynced/index.js +23 -0
- package/src/model/index.js +4 -0
- package/src/model/post/index.js +16 -0
- package/{server → src/server}/getNodejsServerHandler/index.js +13 -7
- package/src/server/getServerFactory/index.js +12 -0
- package/src/server/index.js +3 -0
- package/api/api.js +0 -5
- package/api/getModels/handler.js +0 -5
- package/api/getModels/out.js +0 -3
- package/api/getNewAPI/handler.js +0 -46
- package/api/getNewAPI/in.js +0 -8
- package/api/getNewAPI/out.js +0 -3
- package/api/getORM/handler.js +0 -5
- package/api/getORM/out.js +0 -3
- package/api/getSchemas/handler.js +0 -5
- package/api/getSchemas/out.js +0 -3
- package/api/getService/handler.js +0 -8
- package/api/getService/in.js +0 -6
- package/api/getService/out.js +0 -3
- package/api/getServices/handler.js +0 -5
- package/api/getServices/out.js +0 -3
- package/api/getSyncedHandler/handler.js +0 -28
- package/api/getSyncedHandler/in.js +0 -3
- package/api/getSyncedHandler/out.js +0 -3
- package/api/postDebug/handler.js +0 -5
- package/api/postDebug/in.js +0 -3
- package/api/postError/handler.js +0 -5
- package/api/postError/in.js +0 -3
- package/api/postInfo/handler.js +0 -5
- package/api/postInfo/in.js +0 -3
- package/api/postModel/handler.js +0 -8
- package/api/postModel/in.js +0 -6
- package/api/postModule/handler.js +0 -31
- package/api/postModule/in.js +0 -7
- package/api/postORM/handler.js +0 -7
- package/api/postORM/in.js +0 -5
- package/api/postRawModule/handler.js +0 -9
- package/api/postRawModule/in.js +0 -9
- package/api/postRoute/handler.js +0 -9
- package/api/postRoute/in.js +0 -7
- package/api/postSchema/handler.js +0 -8
- package/api/postSchema/in.js +0 -6
- package/api/services.js +0 -18
- package/autotest/getMethodTest/in.js +0 -3
- package/autotest/getMethodTest/out.js +0 -3
- package/autotest/services.js +0 -1
- package/control/get/handler.js +0 -8
- package/control/get/in.js +0 -6
- package/control/get/out.js +0 -3
- package/database/post/handler.js +0 -24
- package/database/post/in.js +0 -12
- package/database/postConnection/handler.js +0 -25
- package/database/postConnection/in.js +0 -5
- package/database/postConnection/out.js +0 -3
- package/database/services.js +0 -1
- package/environment/getDBEnvVars/handler.js +0 -6
- package/environment/getDBEnvVars/in.js +0 -3
- package/environment/getDBEnvVars/out.js +0 -3
- package/environment/getENVEnvVars/handler.js +0 -7
- package/environment/getENVEnvVars/in.js +0 -3
- package/environment/getENVEnvVars/out.js +0 -3
- package/environment/postEnvFile/handler.js +0 -16
- package/environment/postEnvFile/in.js +0 -6
- package/environment/postTestEnvironment/index.js +0 -6
- package/environment/services.js +0 -5
- package/health/post/handler.js +0 -11
- package/health/services.js +0 -1
- package/model/getSynced/handler.js +0 -29
- package/model/post/handler.js +0 -14
- package/model/post/in.js +0 -6
- package/model/services.js +0 -1
- package/modules.js +0 -19
- package/server/getServerFactory/handler.js +0 -17
- package/server/getServerFactory/in.js +0 -8
- package/server/getServerFactory/out.js +0 -3
- package/server/services.js +0 -1
- package/service/getParsedCode/handler.js +0 -19
- package/service/getParsedCode/in.js +0 -6
- package/service/getParsedCode/out.js +0 -6
- package/service/getParsedEvent/handler.js +0 -12
- package/service/getParsedEvent/in.js +0 -5
- package/service/getParsedEvent/out.js +0 -6
- package/service/getResponseCode/in.js +0 -3
- package/service/getResponseCode/out.js +0 -3
- package/service/getRouteCode/handler.js +0 -15
- package/service/getRouteCode/in.js +0 -6
- package/service/getRouteCode/out.js +0 -3
- package/service/getType/handler.js +0 -11
- package/service/getType/in.js +0 -5
- package/service/getType/out.js +0 -3
- package/service/postRoute/handler.js +0 -105
- package/service/postRoute/in.js +0 -6
- package/service/services.js +0 -9
- package/setupTesting.js +0 -17
- package/validation/getParsedAsync/handler.js +0 -37
- package/validation/getParsedAsync/in.js +0 -9
- package/validation/getParsedAsync/out.js +0 -6
- package/validation/services.js +0 -1
- package/zdb/components.js +0 -1
- package/zdb/getAssertExists/handler.js +0 -16
- package/zdb/getAssertExists/in.js +0 -6
- package/zdb/getAssertExists/out.js +0 -3
- package/zdb/getAssertNotExists/handler.js +0 -16
- package/zdb/getAssertNotExists/in.js +0 -6
- package/zdb/getAssertNotExists/out.js +0 -3
- package/zdb/getAssertSafeInt/handler.js +0 -15
- package/zdb/getAssertSafeInt/in.js +0 -6
- package/zdb/getAssertSafeInt/out.js +0 -3
- /package/{control/services.js → backtest/todoRuntimeError/index.js} +0 -0
- /package/{autotest → src/autotest}/getTestServerResponse/index.js +0 -0
- /package/{api → src/middleware/postCors}/corsHeaders.js +0 -0
package/README.md
CHANGED
|
@@ -18,12 +18,10 @@ Here's an example project using `minimonolith`:
|
|
|
18
18
|
├── server.js // For local development
|
|
19
19
|
├── index.js // Root of the code in a deployed AWS Lambda
|
|
20
20
|
└── todo
|
|
21
|
-
├──
|
|
22
|
-
├── model.js // Optional: Sequelize model for
|
|
21
|
+
├── index.js // Service 'todo' exported method handlers are declared here
|
|
22
|
+
├── model.js // Optional: Sequelize model for service 'todo' is declared here
|
|
23
23
|
└── get
|
|
24
|
-
|
|
25
|
-
└── in.js // Optional: Service 'get' input validation, if body not empty
|
|
26
|
-
└── out.js // Optional: Service 'get' output validation, if body not empty
|
|
24
|
+
└─── handler.js // Service 'todo' method 'get' handler
|
|
27
25
|
```
|
|
28
26
|
|
|
29
27
|
### server.js
|
|
@@ -34,10 +32,15 @@ This file is used for local development. It runs a local server using `minimonol
|
|
|
34
32
|
// server.js
|
|
35
33
|
import { getServerFactory } from 'minimonolith';
|
|
36
34
|
|
|
37
|
-
|
|
35
|
+
import dotenv from 'dotenv';
|
|
36
|
+
dotenv.config({ path: './.env' })
|
|
37
|
+
|
|
38
38
|
const { lambdaHandler } = await import('./index.js');
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
const serverFactory = await getServerFactory();
|
|
41
|
+
|
|
42
|
+
const server = serverFactory(lambdaHandler);
|
|
43
|
+
server.listen(8080);
|
|
41
44
|
```
|
|
42
45
|
|
|
43
46
|
### index.js
|
|
@@ -46,17 +49,16 @@ This file serves as the root of the code in a deployed AWS Lambda:
|
|
|
46
49
|
|
|
47
50
|
```js
|
|
48
51
|
// index.js
|
|
52
|
+
|
|
49
53
|
'use strict';
|
|
50
54
|
|
|
51
55
|
import { getNewAPI } from 'minimonolith';
|
|
52
56
|
|
|
53
|
-
|
|
54
|
-
PROD_ENV: process.env.PROD_ENV,
|
|
55
|
-
DEV_ENV: process.env.DEV_ENV,
|
|
56
|
-
});
|
|
57
|
+
import todo from './todo/index.js';
|
|
57
58
|
|
|
58
|
-
await
|
|
59
|
-
|
|
59
|
+
const API = await getNewAPI();
|
|
60
|
+
|
|
61
|
+
await API.postService(todo.name, todo.service, todo.model);
|
|
60
62
|
await API.postDatabaseService({
|
|
61
63
|
DB_DIALECT: process.env.DB_DIALECT,
|
|
62
64
|
DB_HOST: process.env.DB_HOST,
|
|
@@ -64,6 +66,7 @@ await API.postDatabaseService({
|
|
|
64
66
|
DB_DB: process.env.DB_DB,
|
|
65
67
|
DB_USER: process.env.DB_USER,
|
|
66
68
|
DB_PASS: process.env.DB_PASS,
|
|
69
|
+
DB_STORAGE: process.env.DB_STORAGE,
|
|
67
70
|
});
|
|
68
71
|
|
|
69
72
|
export const lambdaHandler = await API.getSyncedHandler();
|
|
@@ -71,28 +74,53 @@ export const lambdaHandler = await API.getSyncedHandler();
|
|
|
71
74
|
|
|
72
75
|
### todo/index.js
|
|
73
76
|
|
|
74
|
-
Here, we declare the
|
|
77
|
+
Here, we declare the method handlers for the `todo` service:
|
|
75
78
|
|
|
76
79
|
```js
|
|
77
|
-
// todo/
|
|
80
|
+
// todo/index.js
|
|
78
81
|
export default ['getAll', 'get:id', 'post', 'patch:id', 'delete:id'];
|
|
82
|
+
|
|
83
|
+
import get from './get/handler.js';
|
|
84
|
+
import getOne from './getOne/handler.js';
|
|
85
|
+
import post from './post/handler.js';
|
|
86
|
+
import patch from './patch/handler.js';
|
|
87
|
+
import deleteTodo from './delete/handler.js';
|
|
88
|
+
import model from './model.js';
|
|
89
|
+
|
|
90
|
+
export default {
|
|
91
|
+
name: 'todo',
|
|
92
|
+
service: {
|
|
93
|
+
'get': get,
|
|
94
|
+
'post': post,
|
|
95
|
+
'patch:id': patch,·
|
|
96
|
+
'delete:id': deleteTodo,
|
|
97
|
+
},
|
|
98
|
+
model,
|
|
99
|
+
};
|
|
79
100
|
```
|
|
80
101
|
|
|
81
102
|
### todo/model.js
|
|
82
103
|
|
|
83
|
-
In this file, we define a Sequelize model for the `todo`
|
|
104
|
+
In this file, we define a Sequelize model for the `todo` service:
|
|
84
105
|
|
|
85
106
|
```js
|
|
86
107
|
// todo/model.js
|
|
87
|
-
export default
|
|
88
|
-
const schema = orm.define(
|
|
108
|
+
export default serviceName => (orm, types) => {
|
|
109
|
+
const schema = orm.define(serviceName, {
|
|
89
110
|
name: {
|
|
90
111
|
type: types.STRING,
|
|
91
112
|
allowNull: false
|
|
92
113
|
},
|
|
93
114
|
});
|
|
94
115
|
|
|
95
|
-
schema.associate = MODELS => {
|
|
116
|
+
schema.associate = MODELS => {
|
|
117
|
+
/*
|
|
118
|
+
schema.belongsTo(MODELS.todoList, {
|
|
119
|
+
foreignKey: 'todoListId',
|
|
120
|
+
as: 'todoList'
|
|
121
|
+
});
|
|
122
|
+
*/
|
|
123
|
+
};
|
|
96
124
|
|
|
97
125
|
return schema;
|
|
98
126
|
};
|
|
@@ -100,29 +128,19 @@ export default moduleName => (orm, types) => {
|
|
|
100
128
|
|
|
101
129
|
### todo/get/index.js
|
|
102
130
|
|
|
103
|
-
This file contains the `get:id`
|
|
131
|
+
This file contains the `get:id` method handler for the `todo` service. It retrieves a todo item by its ID:
|
|
104
132
|
|
|
105
133
|
```js
|
|
106
134
|
// todo/get/index.js
|
|
107
|
-
export default async ({ body, MODELS }) => {
|
|
108
|
-
return await MODELS.todo.findOne({ where: { id: body.id } });
|
|
109
|
-
}
|
|
110
|
-
```
|
|
111
135
|
|
|
112
|
-
|
|
136
|
+
export default async ({ body, MODELS }) => {
|
|
137
|
+
const id = body.id;
|
|
113
138
|
|
|
114
|
-
|
|
139
|
+
const todo = await MODELS.todo.findOne({ where: { id } });
|
|
140
|
+
const todoJSON = todo.toJSON();
|
|
115
141
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
import { z, zdb } from 'minimonolith';
|
|
119
|
-
|
|
120
|
-
export default ({ MODELS }) => ({
|
|
121
|
-
id: z.string()
|
|
122
|
-
.superRefine(zdb.getIsSafeInt('id'))
|
|
123
|
-
.transform(id => parseInt(id))
|
|
124
|
-
.superRefine(zdb.getExists(MODELS.todo, 'id')),
|
|
125
|
-
})
|
|
142
|
+
return { body: todoJSON };
|
|
143
|
+
}
|
|
126
144
|
```
|
|
127
145
|
|
|
128
146
|
## Response Codes
|
|
@@ -132,45 +150,12 @@ export default ({ MODELS }) => ({
|
|
|
132
150
|
- POST -> 201
|
|
133
151
|
- DELETE -> 204
|
|
134
152
|
- Everything else -> 200
|
|
135
|
-
|
|
136
|
-
### Invalid Request
|
|
137
|
-
|
|
138
|
-
- ANY -> 400
|
|
153
|
+
- Custom -> status value in handler.js return statement
|
|
139
154
|
|
|
140
155
|
### Runtime Error
|
|
141
156
|
|
|
142
157
|
- ANY -> 500
|
|
143
158
|
|
|
144
|
-
## App Environments
|
|
145
|
-
|
|
146
|
-
There are 4 possible environments:
|
|
147
|
-
1. DEV=TRUE + PROD=FALSE: This is the standard DEV environment
|
|
148
|
-
2. DEV=FALSE + PROD=FALSE: This is the standard QA environment
|
|
149
|
-
3. DEV=FALSE + PROD=TRUE: This is the stnadard PROD environment
|
|
150
|
-
4. DEV=TRUE + PROD=TRUE: This allows to test the behavior of PROD within the "new concept" of DEV environment
|
|
151
|
-
|
|
152
|
-
To better understand their relevance:
|
|
153
|
-
1. The "new concept" DEV environments (DEV=TRUE) aim to make the api crash if an "important" error happens
|
|
154
|
-
- Its current only difference is it makes it crash on error at service registration phase
|
|
155
|
-
- Some may think QA should also fail on "important" errors They can use DEV=TRUE there But some do training activities on QA that must be minimally disrupted
|
|
156
|
-
2. The "new concept" QA environments (PROD=FALSE) aim at logging data about the system which on production environments would be forbiden personal information
|
|
157
|
-
- This is relevant because replication of QA activities (even security QA activities) depend heavily on this
|
|
158
|
-
|
|
159
|
-
The current App environment is determined on the values of DEV ENV [TRUE/FALSE] and PROD_ENV [TRUE/FALSE]
|
|
160
|
-
Assuming using same env variables as used at index.js above
|
|
161
|
-
|
|
162
|
-
```makefile
|
|
163
|
-
# .env standard dev environment
|
|
164
|
-
DEV_ENV=TRUE
|
|
165
|
-
PROD_ENV=FALSE
|
|
166
|
-
TEST_ENV=FALSE
|
|
167
|
-
[...]
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
*NOTICE*: Default environment it is assumed standard PROD environment (DEV=FLASE + PROD=TRUE)
|
|
171
|
-
- This means that sequelize will not alter automatically tables having mismatches with defined model.js files
|
|
172
|
-
- Database dialect/credentials detected will not be printed
|
|
173
|
-
- Critical errors will not make the app crash
|
|
174
159
|
|
|
175
160
|
## Database Authentication
|
|
176
161
|
|
|
@@ -193,17 +178,7 @@ DB_PASS=<your_database_password>
|
|
|
193
178
|
For SQLite in memory:
|
|
194
179
|
|
|
195
180
|
```makefile
|
|
196
|
-
DEV_ENV=TRUE
|
|
197
|
-
PROD_ENV=FALSE
|
|
198
181
|
DB_DIALECT=sqlite
|
|
199
182
|
DB_DB=<your_database_name>
|
|
200
183
|
DB_STORAGE=:memory: # Need to also pass to API.postDatabaseService()
|
|
201
184
|
```
|
|
202
|
-
|
|
203
|
-
Make sure to replace the placeholders with your actual database credentials.
|
|
204
|
-
- `DEV_ENV=TRUE` allows Sequelize to alter table structure automatically when working locally
|
|
205
|
-
- `PROD_ENV=FALSE` allows logging of DB credentials for debugging purposes in non-production environments
|
|
206
|
-
- We consider high quality logging important for app performance and evolution
|
|
207
|
-
- However we recommend automatic DB credentials updates (daily) High quality logging does not mean
|
|
208
|
-
giving away your infraestructure to hackers
|
|
209
|
-
- At the risk of stating the obvious do not store personal information at the QA database
|
package/backtest/back.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { jest } from '@jest/globals';
|
|
2
|
+
import { postTestEnvironment, getTestServer } from '../index.js';
|
|
3
|
+
|
|
4
|
+
test('todo ok', async () => {
|
|
5
|
+
postTestEnvironment();
|
|
6
|
+
const { lambdaHandler } = await import('./handler.js');
|
|
7
|
+
|
|
8
|
+
const testMethod = async params => {
|
|
9
|
+
const event = {
|
|
10
|
+
path: params.path, httpMethod: params.method,
|
|
11
|
+
body: params.body ? JSON.stringify(params.body) : undefined,
|
|
12
|
+
querySgringParameters: params.queryStringParameters,
|
|
13
|
+
requestContext: {}, headers: {},
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const response = await lambdaHandler(event);
|
|
17
|
+
expect(response.statusCode).toBe(200);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
await testMethod({ path: '/', method: 'GET' });
|
|
21
|
+
await testMethod({ path: '/postSeed/todo', method: 'POST' });
|
|
22
|
+
await testMethod({ path: '/todo/get', method: 'GET' });
|
|
23
|
+
await testMethod({ path: '/todo/post', method: 'POST', body:{name:'n'}});
|
|
24
|
+
await testMethod({ path: '/todo/getOne/1', method: 'GET', queryStringParameters:{id:'1'}});
|
|
25
|
+
await testMethod({ path: '/todo/patch/1', method: 'PATCH', queryStringParameters:{id:'1'}, body:{name: 'm'}});
|
|
26
|
+
await testMethod({ path: '/todo/delete/1', method: 'DELETE', queryStringParameters:{id:'1'}});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('todo invalid', async () => {
|
|
30
|
+
postTestEnvironment();
|
|
31
|
+
const { lambdaHandler } = await import('./handler.js');
|
|
32
|
+
|
|
33
|
+
const testMethod = async params => {
|
|
34
|
+
const event = {
|
|
35
|
+
path: params.path, httpMethod: params.method,
|
|
36
|
+
body: params.body ? JSON.stringify(params.body) : undefined,
|
|
37
|
+
querySgringParameters: params.queryStringParameters,
|
|
38
|
+
requestContext: {}, headers: {},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const response = await lambdaHandler(event);
|
|
42
|
+
expect(response.statusCode).toBe(400);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
await testMethod({ path: '/todo/post', method: 'POST', body:{name:1}});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test('todo compiletime error', async () => {
|
|
49
|
+
postTestEnvironment();
|
|
50
|
+
|
|
51
|
+
await expect(async () => {
|
|
52
|
+
await import('./handlerCompiletimeError.js')
|
|
53
|
+
}).rejects.toThrow();
|
|
54
|
+
});
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { jest } from '@jest/globals';
|
|
2
|
+
import http from 'http';
|
|
3
|
+
import url from 'url';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
import { getServerFactory, getMethodTest } from '../index.js';
|
|
7
|
+
import postConnection from '../src/database/postConnection/index.js';
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
jest.spyOn(console, 'log').mockImplementation(() => {});
|
|
11
|
+
jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
console.log.mockRestore();
|
|
16
|
+
console.error.mockRestore();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe('postConnection', () => {
|
|
20
|
+
const mockORMSuccess = { authenticate: jest.fn().mockResolvedValue(true) };
|
|
21
|
+
const mockORMFail = { authenticate: jest.fn().mockRejectedValue(new Error('AUTHENTICATION_FAILED')) };
|
|
22
|
+
|
|
23
|
+
test('successfully authenticates', async () => {
|
|
24
|
+
const retries = await postConnection(mockORMSuccess);
|
|
25
|
+
|
|
26
|
+
expect(mockORMSuccess.authenticate).toHaveBeenCalledTimes(1);
|
|
27
|
+
expect(retries).toBe(0);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('retries when authentication fails', async () => {
|
|
31
|
+
const retries = await postConnection(mockORMFail);
|
|
32
|
+
|
|
33
|
+
expect(mockORMFail.authenticate).toHaveBeenCalledTimes(5);
|
|
34
|
+
expect(retries).toBe(5);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe('end-to-end requests', () => {
|
|
39
|
+
let getServer, server;
|
|
40
|
+
|
|
41
|
+
beforeAll(async () => {
|
|
42
|
+
getServer = await getServerFactory(path.join('test', '.env.test'), 'src' + path.sep);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
beforeEach(async () => {
|
|
46
|
+
const { lambdaHandler } = await import('./handler.js');
|
|
47
|
+
server = getServer(lambdaHandler);
|
|
48
|
+
server.listen(0);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
afterEach(async () => {
|
|
52
|
+
server.close();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('successful codes', async () => {
|
|
56
|
+
|
|
57
|
+
const testMethod = await getMethodTest(server);
|
|
58
|
+
await testMethod({ path: '/', method: 'OPTIONS', expectedCode: 200,
|
|
59
|
+
headers: { 'authorization': 'Bearer '+ [
|
|
60
|
+
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9',
|
|
61
|
+
'eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ',
|
|
62
|
+
'SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
|
|
63
|
+
].join('.') } });
|
|
64
|
+
|
|
65
|
+
await testMethod({ path: '/', method: 'GET', expectedCode: 200 });
|
|
66
|
+
await testMethod({ path: '/postSeed/todo', method: 'POST', expectedCode: 201 });
|
|
67
|
+
await testMethod({ path: '/todo/get', method: 'GET', expectedCode: 200 });
|
|
68
|
+
await testMethod({ path: '/todo/getAttributes?name=n', method: 'GET', expectedCode: 200 });
|
|
69
|
+
await testMethod({ path: '/todo/post', method: 'POST', expectedCode: 201,
|
|
70
|
+
headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'n' }) });
|
|
71
|
+
await testMethod({ path: '/todo/getAttributes', method: 'GET', expectedCode: 200 });
|
|
72
|
+
await testMethod({ path: '/todo/getAttributes?name=n', method: 'GET', expectedCode: 200 });
|
|
73
|
+
await testMethod({ path: '/todo/getOne/1', method: 'GET', expectedCode: 200 });
|
|
74
|
+
await testMethod({ path: '/todo/getOneAlias/1', method: 'GET', expectedCode: 200 });
|
|
75
|
+
await testMethod({ path: '/todo/patch/1', method: 'PATCH', expectedCode: 200,
|
|
76
|
+
headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'm' }) });
|
|
77
|
+
await testMethod({ path: '/todo/delete/1', method: 'DELETE', expectedCode: 204 });
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('invalid requests', async () => {
|
|
81
|
+
const testMethod = await getMethodTest(server);
|
|
82
|
+
await testMethod({ path: '/postSeed/todo', method: 'POST', expectedCode: 400,
|
|
83
|
+
headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 1 }) });
|
|
84
|
+
await testMethod({ path: '/todo/post', method: 'POST', expectedCode: 400,
|
|
85
|
+
headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 1 }) });
|
|
86
|
+
await testMethod({ path: '/todo/delete/1', method: 'DELETE', expectedCode: 400 });
|
|
87
|
+
await testMethod({ path: '/todo/delete/n', method: 'DELETE', expectedCode: 400});
|
|
88
|
+
|
|
89
|
+
const testMethodSuccess = await getMethodTest(server);
|
|
90
|
+
await testMethodSuccess({ path: '/todo/post', method: 'POST', expectedCode: 201,
|
|
91
|
+
headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'i' }) });
|
|
92
|
+
await testMethod({ path: '/todo/post', method: 'POST', expectedCode: 400,
|
|
93
|
+
headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'i' }) });
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test('wrong header error code', async () => {
|
|
97
|
+
const testMethod = await getMethodTest(server);
|
|
98
|
+
//await testMethod({ path: '/todo/get', method: 'GET', headers: { accept: {} } });
|
|
99
|
+
await testMethod({ path: '/', method: 'OPTIONS', expectedCode: 500,
|
|
100
|
+
headers: { 'x-trigger-error': 'TRUE' } });
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('wrong jwt error code', async () => {
|
|
104
|
+
const testMethod = await getMethodTest(server);
|
|
105
|
+
await testMethod({ path: '/', method: 'OPTIONS', expectedCode: 500,
|
|
106
|
+
headers: { authorization: 'Bearer ERROR' } });
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
test('throwing method runtime error', async () => {
|
|
112
|
+
const getServer = await getServerFactory(path.join('test', '.env.test'), 'src' + path.sep);
|
|
113
|
+
const { lambdaHandler } = await import('./indexRuntimeError.js');
|
|
114
|
+
const server = getServer(lambdaHandler);
|
|
115
|
+
server.listen(0);
|
|
116
|
+
|
|
117
|
+
const methodWithError = (await import('./todoRuntimeError/get/handler.js')).default;
|
|
118
|
+
await expect(methodWithError()).rejects.toThrow();
|
|
119
|
+
const testMethod = await getMethodTest(server);
|
|
120
|
+
await testMethod({ path: '/todoRuntimeError/get', method: 'GET', expectedCode: 500 });
|
|
121
|
+
|
|
122
|
+
server.close();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test('not existent method type compiletime error', async () => {
|
|
126
|
+
await expect(async () => { await import('./indexCompiletimeError.js') }).rejects.toThrow();
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
test('not existent module folder compiletime error', async () => {
|
|
130
|
+
await expect(async () => { await import('./indexCompiletimeError2.js') }).rejects.toThrow();
|
|
131
|
+
})
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import { getNewAPI } from '../index.js';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
const API = await getNewAPI({
|
|
7
|
+
PROD_ENV: process.env.PROD_ENV,
|
|
8
|
+
DEV_ENV: process.env.DEV_ENV,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
await API.postHealthService();
|
|
12
|
+
await API.postService('todo', 'test' + path.sep, 'src' + path.sep);
|
|
13
|
+
await API.postDatabaseService({
|
|
14
|
+
DB_DIALECT: process.env.DB_DIALECT,
|
|
15
|
+
DB_HOST: process.env.DB_HOST,
|
|
16
|
+
DB_PORT: process.env.DB_PORT,
|
|
17
|
+
DB_DB: process.env.DB_DB,
|
|
18
|
+
DB_USER: process.env.DB_USER,
|
|
19
|
+
DB_PASS: process.env.DB_PASS,
|
|
20
|
+
DB_STORAGE: process.env.DB_STORAGE,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export const lambdaHandler = await API.getSyncedHandler();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import { getNewAPI } from '../index.js';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
const API = await getNewAPI({
|
|
7
|
+
PROD_ENV: process.env.PROD_ENV,
|
|
8
|
+
DEV_ENV: process.env.DEV_ENV,
|
|
9
|
+
});
|
|
10
|
+
await API.postService('todoCompiletimeError', 'test'+path.sep, 'src'+path.sep);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import { getNewAPI } from '../index.js';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
const API = await getNewAPI({
|
|
7
|
+
PROD_ENV: process.env.PROD_ENV,
|
|
8
|
+
DEV_ENV: process.env.DEV_ENV,
|
|
9
|
+
});
|
|
10
|
+
await API.postService('todoCompiletimeError', 'test' + path.sep, 'src2' + path.sep);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import { getNewAPI } from '../index.js';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
const API = await getNewAPI({
|
|
7
|
+
PROD_ENV: process.env.PROD_ENV,
|
|
8
|
+
DEV_ENV: process.env.DEV_ENV,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
await API.postHealthService();
|
|
12
|
+
await API.postService('todoRuntimeError', 'test' + path.sep, 'src' + path.sep);
|
|
13
|
+
|
|
14
|
+
await API.postDatabaseService({
|
|
15
|
+
DB_DIALECT: process.env.DB_DIALECT,
|
|
16
|
+
DB_HOST: process.env.DB_HOST,
|
|
17
|
+
DB_PORT: process.env.DB_PORT,
|
|
18
|
+
DB_DB: process.env.DB_DB,
|
|
19
|
+
DB_USER: process.env.DB_USER,
|
|
20
|
+
DB_PASS: process.env.DB_PASS,
|
|
21
|
+
DB_STORAGE: process.env.DB_STORAGE,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export const lambdaHandler = await API.getSyncedHandler();
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
version: '3'
|
|
2
|
+
|
|
3
|
+
services:
|
|
4
|
+
db:
|
|
5
|
+
container_name: ${DB_CONTAINER_NAME}
|
|
6
|
+
image: mysql:5.7
|
|
7
|
+
restart: always
|
|
8
|
+
environment:
|
|
9
|
+
MYSQL_ROOT_PASSWORD: ${MM_API_DB_PASS}
|
|
10
|
+
MYSQL_DATABASE: ${MM_API_DB_DB}
|
|
11
|
+
ports: ["${MM_API_DB_PORT}:3306"]
|
|
12
|
+
networks: [todo]
|
|
13
|
+
command: mysqld --sql_mode=""
|
|
14
|
+
api:
|
|
15
|
+
container_name: ${API_CONTAINER_NAME}
|
|
16
|
+
build: { context: .., dockerfile: ./localDocker/Dockerfile }
|
|
17
|
+
volumes: [..:/usr/src, /usr/src/node_modules]
|
|
18
|
+
ports: [8080:8080, 9229:9229]
|
|
19
|
+
environment:
|
|
20
|
+
MM_API_DB_HOST: ${MM_API_DB_HOST}
|
|
21
|
+
MM_API_DB_DB: ${MM_API_DB_DB}
|
|
22
|
+
MM_API_DB_USER: ${MM_API_DB_USER}
|
|
23
|
+
MM_API_DB_PASS: ${MM_API_DB_PASS}
|
|
24
|
+
MM_API_DEV_ENV: ${MM_API_DEV_ENV}
|
|
25
|
+
MM_API_PROD_ENV: ${MM_API_PROD_ENV}
|
|
26
|
+
command: >
|
|
27
|
+
sh -c "yarn install && yarn run start"
|
|
28
|
+
networks: [todo]
|
|
29
|
+
depends_on: [db]
|
|
30
|
+
|
|
31
|
+
networks:
|
|
32
|
+
todo:
|
|
33
|
+
driver: bridge
|
|
34
|
+
name: todo
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { getServerFactory } from '../index.js';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
const serverFactory = await getServerFactory(path.join('test','.env'), 'src' + path.sep);
|
|
5
|
+
const { lambdaHandler } = await import('./handler.js');
|
|
6
|
+
|
|
7
|
+
serverFactory(lambdaHandler, 8080, path.join('..', 'src') + path.sep);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default ['get', 'getAttributes', 'getOne:id', 'getOneAlias:id', 'post', 'patch:id', 'delete:id', '!postSeed'];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export default serviceName => (orm, types) => {
|
|
2
|
+
const schema = orm.define(serviceName, {
|
|
3
|
+
name: {
|
|
4
|
+
type: types.STRING,
|
|
5
|
+
allowNull: false
|
|
6
|
+
},
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
schema.associate = MODELS => {
|
|
10
|
+
/*
|
|
11
|
+
schema.belongsTo(MODELS.todoList, {
|
|
12
|
+
foreignKey: 'todoListId',
|
|
13
|
+
as: 'todoList'
|
|
14
|
+
});
|
|
15
|
+
*/
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
return schema;
|
|
19
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z, zdb } from '../../../index.js';
|
|
2
|
+
|
|
3
|
+
export default ({ MODELS }) => ({
|
|
4
|
+
id: z.string()
|
|
5
|
+
.superRefine(zdb.isSafeInt('id'))
|
|
6
|
+
.transform(id => parseInt(id))
|
|
7
|
+
.superRefine(zdb.exists(MODELS.todo, 'id')),
|
|
8
|
+
name: z.string()
|
|
9
|
+
.superRefine(zdb.notExists(MODELS.todo, 'name')
|
|
10
|
+
),
|
|
11
|
+
});
|
|
12
|
+
|