minimonolith 0.25.24 → 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.
Files changed (183) hide show
  1. package/README.md +55 -80
  2. package/backtest/back.js +54 -0
  3. package/backtest/backtest.js +131 -0
  4. package/backtest/handler.js +23 -0
  5. package/backtest/handlerCompiletimeError.js +10 -0
  6. package/backtest/handlerCompiletimeError2.js +10 -0
  7. package/backtest/handlerRuntimeError.js +24 -0
  8. package/backtest/localDocker/Dockerfile +11 -0
  9. package/backtest/localDocker/docker-compose.yml +34 -0
  10. package/backtest/localDocker/run.sh +4 -0
  11. package/backtest/localDocker/shutdown.sh +2 -0
  12. package/backtest/localDocker/update.sh +2 -0
  13. package/backtest/server.js +7 -0
  14. package/backtest/todo/delete/index.js +7 -0
  15. package/backtest/todo/delete/valid.js +8 -0
  16. package/backtest/todo/get/index.js +3 -0
  17. package/backtest/todo/getAttributes/index.js +5 -0
  18. package/backtest/todo/getAttributes/valid.js +5 -0
  19. package/backtest/todo/getOne/index.js +3 -0
  20. package/backtest/todo/getOne/valid.js +8 -0
  21. package/backtest/todo/getOneAlias/index.js +3 -0
  22. package/backtest/todo/getOneAlias/valid.js +3 -0
  23. package/backtest/todo/index.js +1 -0
  24. package/backtest/todo/model.js +19 -0
  25. package/backtest/todo/patch/index.js +6 -0
  26. package/backtest/todo/patch/valid.js +12 -0
  27. package/backtest/todo/post/index.js +5 -0
  28. package/backtest/todo/post/valid.js +5 -0
  29. package/backtest/todo/postSeed/index.js +9 -0
  30. package/backtest/todo/postSeed/seed.js +4 -0
  31. package/backtest/todoCompiletimeError/got/index.js +1 -0
  32. package/backtest/todoCompiletimeError/index.js +1 -0
  33. package/backtest/todoList/delete/handler.js +7 -0
  34. package/backtest/todoList/delete/valid.js +5 -0
  35. package/backtest/todoList/get/handler.js +5 -0
  36. package/backtest/todoList/index.js +1 -0
  37. package/backtest/todoList/model.js +17 -0
  38. package/backtest/todoList/post/handler.js +9 -0
  39. package/backtest/todoList/post/valid.js +6 -0
  40. package/backtest/todoRuntimeError/get/index.js +1 -0
  41. package/index.js +13 -22
  42. package/package.json +7 -8
  43. package/src/api/get/index.js +17 -0
  44. package/src/api/getNewAPI/index.js +11 -0
  45. package/src/api/getSyncedHandler/index.js +23 -0
  46. package/src/api/index.js +4 -0
  47. package/src/api/postService/index.js +29 -0
  48. package/src/autotest/getMethodTest/back.index.js +29 -0
  49. package/{autotest/getMethodTest/handler.js → src/autotest/getMethodTest/index.js} +1 -3
  50. package/src/autotest/index.js +3 -0
  51. package/src/database/index.js +4 -0
  52. package/src/database/post/index.js +38 -0
  53. package/src/database/postConnection/index.js +25 -0
  54. package/src/error/index.js +4 -0
  55. package/src/error/postCompiletime/index.js +13 -0
  56. package/src/error/postRuntime/index.js +7 -0
  57. package/src/event/getParsedEvent/index.js +9 -0
  58. package/src/event/index.js +3 -0
  59. package/src/log/index.js +5 -0
  60. package/src/log/post/index.js +3 -0
  61. package/src/log/postERROR/index.js +3 -0
  62. package/src/log/postINFO/index.js +3 -0
  63. package/src/method/getParsedCode/index.js +13 -0
  64. package/{service/getResponseCode/handler.js → src/method/getResponseCode/index.js} +1 -3
  65. package/src/method/getRouteCode/index.js +12 -0
  66. package/src/method/getType/index.js +9 -0
  67. package/src/method/index.js +7 -0
  68. package/src/method/post/index.js +44 -0
  69. package/src/method/postResponse/index.js +29 -0
  70. package/src/middleware/index.js +4 -0
  71. package/src/middleware/postCors/index.js +20 -0
  72. package/src/middleware/postError/index.js +10 -0
  73. package/src/model/getSynced/index.js +23 -0
  74. package/src/model/index.js +4 -0
  75. package/src/model/post/index.js +16 -0
  76. package/{server → src/server}/getNodejsServerHandler/index.js +13 -7
  77. package/src/server/getServerFactory/index.js +12 -0
  78. package/src/server/index.js +3 -0
  79. package/api/api.js +0 -5
  80. package/api/getModels/handler.js +0 -5
  81. package/api/getModels/out.js +0 -3
  82. package/api/getNewAPI/handler.js +0 -46
  83. package/api/getNewAPI/in.js +0 -8
  84. package/api/getNewAPI/out.js +0 -3
  85. package/api/getORM/handler.js +0 -5
  86. package/api/getORM/out.js +0 -3
  87. package/api/getSchemas/handler.js +0 -5
  88. package/api/getSchemas/out.js +0 -3
  89. package/api/getService/handler.js +0 -8
  90. package/api/getService/in.js +0 -6
  91. package/api/getService/out.js +0 -3
  92. package/api/getServices/handler.js +0 -5
  93. package/api/getServices/out.js +0 -3
  94. package/api/getSyncedHandler/handler.js +0 -28
  95. package/api/getSyncedHandler/in.js +0 -3
  96. package/api/getSyncedHandler/out.js +0 -3
  97. package/api/postDebug/handler.js +0 -5
  98. package/api/postDebug/in.js +0 -3
  99. package/api/postError/handler.js +0 -5
  100. package/api/postError/in.js +0 -3
  101. package/api/postInfo/handler.js +0 -5
  102. package/api/postInfo/in.js +0 -3
  103. package/api/postModel/handler.js +0 -8
  104. package/api/postModel/in.js +0 -6
  105. package/api/postModule/handler.js +0 -31
  106. package/api/postModule/in.js +0 -7
  107. package/api/postORM/handler.js +0 -7
  108. package/api/postORM/in.js +0 -5
  109. package/api/postRawModule/handler.js +0 -9
  110. package/api/postRawModule/in.js +0 -9
  111. package/api/postRoute/handler.js +0 -9
  112. package/api/postRoute/in.js +0 -7
  113. package/api/postSchema/handler.js +0 -8
  114. package/api/postSchema/in.js +0 -6
  115. package/api/services.js +0 -18
  116. package/autotest/getMethodTest/in.js +0 -3
  117. package/autotest/getMethodTest/out.js +0 -3
  118. package/autotest/services.js +0 -1
  119. package/control/get/handler.js +0 -8
  120. package/control/get/in.js +0 -6
  121. package/control/get/out.js +0 -3
  122. package/database/post/handler.js +0 -24
  123. package/database/post/in.js +0 -12
  124. package/database/postConnection/handler.js +0 -25
  125. package/database/postConnection/in.js +0 -5
  126. package/database/postConnection/out.js +0 -3
  127. package/database/services.js +0 -1
  128. package/environment/getDBEnvVars/handler.js +0 -6
  129. package/environment/getDBEnvVars/in.js +0 -3
  130. package/environment/getDBEnvVars/out.js +0 -3
  131. package/environment/getENVEnvVars/handler.js +0 -7
  132. package/environment/getENVEnvVars/in.js +0 -3
  133. package/environment/getENVEnvVars/out.js +0 -3
  134. package/environment/postEnvFile/handler.js +0 -16
  135. package/environment/postEnvFile/in.js +0 -6
  136. package/environment/postTestEnvironment/index.js +0 -6
  137. package/environment/services.js +0 -5
  138. package/health/post/handler.js +0 -11
  139. package/health/services.js +0 -1
  140. package/model/getSynced/handler.js +0 -29
  141. package/model/post/handler.js +0 -14
  142. package/model/post/in.js +0 -6
  143. package/model/services.js +0 -1
  144. package/modules.js +0 -19
  145. package/server/getServerFactory/handler.js +0 -17
  146. package/server/getServerFactory/in.js +0 -8
  147. package/server/getServerFactory/out.js +0 -3
  148. package/server/services.js +0 -1
  149. package/service/getParsedCode/handler.js +0 -19
  150. package/service/getParsedCode/in.js +0 -6
  151. package/service/getParsedCode/out.js +0 -6
  152. package/service/getParsedEvent/handler.js +0 -12
  153. package/service/getParsedEvent/in.js +0 -5
  154. package/service/getParsedEvent/out.js +0 -6
  155. package/service/getResponseCode/in.js +0 -3
  156. package/service/getResponseCode/out.js +0 -3
  157. package/service/getRouteCode/handler.js +0 -15
  158. package/service/getRouteCode/in.js +0 -6
  159. package/service/getRouteCode/out.js +0 -3
  160. package/service/getType/handler.js +0 -11
  161. package/service/getType/in.js +0 -5
  162. package/service/getType/out.js +0 -3
  163. package/service/postRoute/handler.js +0 -105
  164. package/service/postRoute/in.js +0 -6
  165. package/service/services.js +0 -9
  166. package/setupTesting.js +0 -17
  167. package/validation/getParsedAsync/handler.js +0 -37
  168. package/validation/getParsedAsync/in.js +0 -9
  169. package/validation/getParsedAsync/out.js +0 -6
  170. package/validation/services.js +0 -1
  171. package/zdb/components.js +0 -1
  172. package/zdb/getAssertExists/handler.js +0 -16
  173. package/zdb/getAssertExists/in.js +0 -6
  174. package/zdb/getAssertExists/out.js +0 -3
  175. package/zdb/getAssertNotExists/handler.js +0 -16
  176. package/zdb/getAssertNotExists/in.js +0 -6
  177. package/zdb/getAssertNotExists/out.js +0 -3
  178. package/zdb/getAssertSafeInt/handler.js +0 -15
  179. package/zdb/getAssertSafeInt/in.js +0 -6
  180. package/zdb/getAssertSafeInt/out.js +0 -3
  181. /package/{control/services.js → backtest/todoRuntimeError/index.js} +0 -0
  182. /package/{autotest → src/autotest}/getTestServerResponse/index.js +0 -0
  183. /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
- ├── services.js // Module 'todo' exported services are declared here
22
- ├── model.js // Optional: Sequelize model for module 'todo' is declared here
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
- ├── handler.js // Module 'todo' service 'get' handler
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
- const getServer = await getServerFactory()(;
35
+ import dotenv from 'dotenv';
36
+ dotenv.config({ path: './.env' })
37
+
38
38
  const { lambdaHandler } = await import('./index.js');
39
39
 
40
- getServer(lambdaHandler).listen(8080);
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
- const API = getNewAPI({
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 API.postHealthService();
59
- await API.postModule('todo');
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 service routes for the `todo` module:
77
+ Here, we declare the method handlers for the `todo` service:
75
78
 
76
79
  ```js
77
- // todo/services.js
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` module:
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 moduleName => (orm, types) => {
88
- const schema = orm.define(moduleName, {
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 => {}; // e.g. MODELS.todo.belongsTo(MODELS.todoList, {...});
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` route for the `todo` module. It retrieves a todo item by its 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
- ### todo/get/in.js
136
+ export default async ({ body, MODELS }) => {
137
+ const id = body.id;
113
138
 
114
- This file validates the `get:id` service's input, ensuring that the provided `id` is a string and exists in the `todo` model:
139
+ const todo = await MODELS.todo.findOne({ where: { id } });
140
+ const todoJSON = todo.toJSON();
115
141
 
116
- ```js
117
- // todo/get/in.js
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
@@ -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,11 @@
1
+ FROM node:12-alpine
2
+ WORKDIR /usr/src
3
+
4
+ COPY package.json ./
5
+ COPY yarn.lock ./
6
+
7
+ RUN yarn install
8
+
9
+ COPY . .
10
+
11
+ CMD [ "yarn", "start:development" ]
@@ -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,4 @@
1
+ #docker-compose -f "localDocker/docker-compose.yml" --env-file .env up -d
2
+ #docker-compose -f "localDocker/docker-compose.yml" --env-file .env up
3
+ docker-compose -f "localDocker/docker-compose.yml" --env-file .env up db
4
+ #docker-compose up
@@ -0,0 +1,2 @@
1
+ docker-compose -f "localDocker/docker-compose.yml" --env-file .env down
2
+ #docker-compose up
@@ -0,0 +1,2 @@
1
+ docker-compose -f "localDocker/docker-compose.yml" --env-file .env build
2
+ docker image prune
@@ -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,7 @@
1
+ export default async ({ body, MODELS }) => {
2
+
3
+ const todo = await MODELS.todo.findOne({ where: { id: body.id } });
4
+ await todo.destroy();
5
+
6
+ return undefined;
7
+ }
@@ -0,0 +1,8 @@
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
+ });
@@ -0,0 +1,3 @@
1
+ export default async ({ MODELS }) => {
2
+ return await MODELS.todo.findAll();
3
+ }
@@ -0,0 +1,5 @@
1
+ export default async ({ body, MODELS }) => {
2
+ const query = body && body.name ? { where: { name: body.name } } : {};
3
+ const todo = await MODELS.todo.findOne(query);
4
+ return todo ? todo.toJSON() : null;
5
+ }
@@ -0,0 +1,5 @@
1
+ import { z } from '../../../index.js';
2
+
3
+ export default () => ({
4
+ name: z.string().optional(),
5
+ });
@@ -0,0 +1,3 @@
1
+ export default async ({ body, MODELS }) => {
2
+ return (await MODELS.todo.findOne({ where: { id: body.id } })).toJSON();
3
+ }
@@ -0,0 +1,8 @@
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
+ });
@@ -0,0 +1,3 @@
1
+ export default async ({ body, SERVICES }) => {
2
+ return await SERVICES.todo.getOne({ id: body.id });
3
+ }
@@ -0,0 +1,3 @@
1
+ import { z, zdb } from '../../../index.js';
2
+
3
+ export default ({ VALIDATORS }) => VALIDATORS.todo.getOne();
@@ -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,6 @@
1
+ export default async ({ body, MODELS }) => {
2
+ const todo = await MODELS.todo.findOne({ where: { id: body.id } });
3
+ await todo.update({ name: body.name });
4
+
5
+ return todo.toJSON();
6
+ }
@@ -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
+
@@ -0,0 +1,5 @@
1
+ export default async ({ body, MODELS }) => {
2
+ const todo = await MODELS.todo.create({ name: body.name });
3
+
4
+ return todo.toJSON();
5
+ }