beech-api 3.7.23 → 3.8.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/README.md +490 -168
- package/index.js +2 -2
- package/package.json +8 -1
- package/packages/cli/beech +2 -2
- package/packages/cli/bin/beech-app.js +10 -8
- package/packages/cli/bin/beech-service.js +1 -1
- package/packages/cli/core/auth/Credentials.js +139 -89
- package/packages/cli/core/auth/Passport.js +264 -164
- package/packages/cli/core/auth/_Request.js +1 -1
- package/packages/cli/core/configure/app.config-basic.js +2 -2
- package/packages/cli/core/configure/app.config-sequelize.js +2 -2
- package/packages/cli/core/configure/beech.config.js +1 -0
- package/packages/cli/core/configure/passport.config.js +33 -13
- package/packages/cli/core/databases/sequelize.js +3 -0
- package/packages/cli/core/databases/test.js +5 -3
- package/packages/cli/core/generator/_endpoints +5 -9
- package/packages/cli/core/generator/_endpoints_basic +11 -8
- package/packages/cli/core/generator/_help +1 -1
- package/packages/cli/core/generator/_models +5 -4
- package/packages/cli/core/generator/_models_basic +2 -2
- package/packages/cli/core/generator/_package +5 -1
- package/packages/cli/core/generator/{_add-on → _scheduler} +1 -1
- package/packages/cli/core/generator/_spec +15 -10
- package/packages/cli/core/generator/index.js +19 -44
- package/packages/cli/core/helpers/2fa.js +85 -0
- package/packages/cli/core/helpers/math.js +55 -7
- package/packages/cli/core/helpers/poolEntity.js +29 -1
- package/packages/cli/core/index.js +65 -34
- package/packages/cli/core/middleware/express/duplicateRequest.js +12 -0
- package/packages/cli/core/middleware/express/jwtCheckAllow.js +68 -0
- package/packages/cli/core/middleware/express/rateLimit.js +17 -0
- package/packages/cli/core/middleware/express/slowDown.js +2 -0
- package/packages/cli/core/middleware/index.js +6 -0
- package/packages/cli/core/middleware/origin/guard/advance.js +74 -0
- package/packages/cli/core/{origin → middleware/origin}/whitelist/cors.js +15 -12
- package/packages/cli/core/services/http.express.js +116 -72
- package/packages/lib/index.js +3 -1
- package/packages/lib/src/endpoint.js +523 -89
- package/packages/lib/src/guard.js +61 -0
- package/packages/lib/src/schema.js +57 -26
- package/packages/lib/src/specificExpress.js +7 -0
- package/packages/lib/src/user.js +94 -18
- package/packages/cli/core/origin/index.js +0 -2
package/README.md
CHANGED
|
@@ -1,38 +1,36 @@
|
|
|
1
1
|
[](https://github.com/bombkiml)
|
|
2
2
|
|
|
3
3
|
# Beech API framework
|
|
4
|
+
#### Stable v.3.8.0 (LTS)
|
|
4
5
|
|
|
5
|
-
[](https://github.com/bombkiml/beech-api/releases/)
|
|
6
|
+
[](https://github.com/bombkiml/beech-api/releases/tag/3.8.0)
|
|
6
7
|
[](https://github.com/bombkiml/beech-api/blob/master/README.md)
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
# What is Beech API ?
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
The Beech API is API framework, It's help you with very easy to create API project under [Node.js](https://nodejs.org)
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
`Beech API` is a Very easy for using, very feather framework, easy to installation, easy to implementation, and high security.
|
|
15
|
-
|
|
16
|
-
## Powered by Node.js & Express.js
|
|
17
|
-
|
|
18
|
-

|
|
19
|
-
|
|
20
|
-
## Environment
|
|
13
|
+
# Environment
|
|
21
14
|
|
|
22
15
|
- [`Node.js`](https://nodejs.org) >= 14.19.0+ (recommended)
|
|
23
16
|
|
|
24
|
-
|
|
17
|
+
# Installation
|
|
25
18
|
|
|
26
19
|
Beech API requires Node.js version 14.19.0 or above. You can manage multiple versions of Node on the same machine with [nvm](https://github.com/creationix/nvm) or [nvm-windows](https://github.com/coreybutler/nvm-windows). So, Let's go to install `beech-api`
|
|
27
20
|
|
|
28
21
|
```sh
|
|
29
|
-
|
|
22
|
+
# NPM
|
|
30
23
|
$ npm install beech-api --global
|
|
31
24
|
|
|
32
|
-
|
|
25
|
+
# Yarn
|
|
33
26
|
$ yarn global add beech-api
|
|
34
27
|
```
|
|
35
28
|
|
|
29
|
+
Installation demo:
|
|
30
|
+
|
|
31
|
+
[Demo](https://i.ibb.co/hySFxy3/install-beech720-1.gif)
|
|
32
|
+

|
|
33
|
+
|
|
36
34
|
After installation, you will have access to the `beech-app` binary in your command line.
|
|
37
35
|
You can check you have the right version with this command:
|
|
38
36
|
|
|
@@ -40,7 +38,7 @@ You can check you have the right version with this command:
|
|
|
40
38
|
$ beech-app --version
|
|
41
39
|
```
|
|
42
40
|
|
|
43
|
-
|
|
41
|
+
# Creating a project
|
|
44
42
|
|
|
45
43
|
Create a new project run:
|
|
46
44
|
|
|
@@ -52,14 +50,14 @@ Run your project:
|
|
|
52
50
|
$ cd hello-world
|
|
53
51
|
|
|
54
52
|
$ npm start
|
|
55
|
-
|
|
53
|
+
# OR
|
|
56
54
|
$ yarn start
|
|
57
55
|
```
|
|
58
56
|
|
|
59
57
|
❓ **Note:** The Beech API it's start server at [http://localhost:9000](http://localhost:9000) you can change new a port in `app.config.js` file.
|
|
60
58
|
|
|
61
59
|
|
|
62
|
-
|
|
60
|
+
# Upgrade to latest version
|
|
63
61
|
The Beech API upgrade to latest version command avariable :
|
|
64
62
|
|
|
65
63
|
```sh
|
|
@@ -70,7 +68,7 @@ $ beech-app update
|
|
|
70
68
|
$ beech-app update -g, --global
|
|
71
69
|
```
|
|
72
70
|
|
|
73
|
-
|
|
71
|
+
# Beech CLI tool available
|
|
74
72
|
After installation, you will have access to the `beech` binary in your command line.
|
|
75
73
|
The `beech` command has a number of options and you can explore them all by running:
|
|
76
74
|
|
|
@@ -96,13 +94,13 @@ The following commands are available:
|
|
|
96
94
|
$ beech make <model> -M, --model Create a new Models file.
|
|
97
95
|
$ beech make <helper> --helper Create a new Helpers file.
|
|
98
96
|
$ beech passport init Initialize authentication with passport-jwt.
|
|
99
|
-
$ beech
|
|
97
|
+
$ beech skd init Initialize Job Scheduler file.
|
|
100
98
|
$ beech key:generate, key:gen Re-Generate application key (Dangerous!).
|
|
101
99
|
$ beech hash:<text> Hash text for Access to Database connection.
|
|
102
100
|
```
|
|
103
101
|
❓ **Note:** Every to create new project will be generated new ``app_key`` in ``app.config.js`` file, If you can re-generate. Can use command ``$ beech key:generate`` or ``$ beech key:gen``
|
|
104
102
|
|
|
105
|
-
|
|
103
|
+
# Database connection
|
|
106
104
|
|
|
107
105
|
You might connection to Database with `database_config` object in `app.config.js` file. Anything can support to multiple Database connections.
|
|
108
106
|
|
|
@@ -116,11 +114,11 @@ In case Access to Database must to Hash the `username` and `password` with Beech
|
|
|
116
114
|
```sh
|
|
117
115
|
// Hash database username
|
|
118
116
|
$ beech hash:root
|
|
119
|
-
Output:
|
|
117
|
+
Output: m42BVxQ6Q4kLdRX7xS_Hm7WbQiNqShJDvw9SLCgI431oafWBtQJoJDnoCL
|
|
120
118
|
|
|
121
119
|
// Hash database password
|
|
122
120
|
$ beech hash:password
|
|
123
|
-
Output:
|
|
121
|
+
Output: FjgcgJPylkV7EeQJjea_EeifPwaHVO9onD3ATk3YYAyvjtMGu3dcDS0ejA
|
|
124
122
|
|
|
125
123
|
```
|
|
126
124
|
Example:
|
|
@@ -136,13 +134,27 @@ database_config: [
|
|
|
136
134
|
dialect: "mysql",
|
|
137
135
|
name: "mysql_my_store_db",
|
|
138
136
|
host: "localhost",
|
|
139
|
-
username: "
|
|
140
|
-
password: "
|
|
137
|
+
username: "m42BVxQ6Q4kLdRX7xS_Hm7WbQiNqShJDvw9SLCgI431oafWBtQJoJDnoCL",
|
|
138
|
+
password: "FjgcgJPylkV7EeQJjea_EeifPwaHVO9onD3ATk3YYAyvjtMGu3dcDS0ejA",
|
|
141
139
|
database: "my_store_db",
|
|
142
140
|
port: "3306",
|
|
141
|
+
|
|
142
|
+
// Specify global options, which are used when Define is called.
|
|
143
|
+
define: {
|
|
144
|
+
charset: "utf8",
|
|
145
|
+
freezeTableName: true,
|
|
146
|
+
...
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
timezone: "+07:00", // Example: GMT+2
|
|
150
|
+
// or use a named timezone supported by Intl.Locale
|
|
151
|
+
// timezone: 'America/Los_Angeles',
|
|
152
|
+
|
|
153
|
+
logging: console.log, // SQL trace logs
|
|
154
|
+
|
|
143
155
|
is_connect: true, // boolean, Turn ON/OFF to connect
|
|
144
156
|
},
|
|
145
|
-
|
|
157
|
+
|
|
146
158
|
...
|
|
147
159
|
|
|
148
160
|
],
|
|
@@ -151,9 +163,9 @@ database_config: [
|
|
|
151
163
|
```
|
|
152
164
|
❓ **Caution! :** Every re-new generate `app_key`. Must to new Hash your Access and change to ALL Database connections.
|
|
153
165
|
|
|
154
|
-
|
|
166
|
+
# Part of generate file
|
|
155
167
|
|
|
156
|
-
|
|
168
|
+
## # Generate Endpoints
|
|
157
169
|
|
|
158
170
|
The `endpoints` keep the endpoints basic request files currently support `GET`, `POST`, `PUT`, `PATCH` and `DELETE`.
|
|
159
171
|
|
|
@@ -162,27 +174,32 @@ So, you might create new endpoints with constant `endpoint` object variable in `
|
|
|
162
174
|
```sh
|
|
163
175
|
$ beech make endpointName
|
|
164
176
|
```
|
|
165
|
-
|
|
177
|
+
You might using [special] `-R, --require` for choose Model(s) used for that endpoint.
|
|
178
|
+
|
|
179
|
+
### Example ***(Basic)*** : Fruit endpoints.
|
|
166
180
|
|
|
167
|
-
📂
|
|
181
|
+
📂 fruit-endpoints.js
|
|
168
182
|
```js
|
|
169
183
|
exports.init = () => {
|
|
170
184
|
|
|
171
185
|
// GET method
|
|
172
|
-
endpoint.get("/
|
|
186
|
+
endpoint.get("/fruit", Credentials, (req, res) => {
|
|
173
187
|
// @response
|
|
174
188
|
res.json({
|
|
175
189
|
code: 200,
|
|
176
|
-
|
|
190
|
+
status: "SUCCESS",
|
|
191
|
+
message: "GET /fruit request.",
|
|
177
192
|
});
|
|
178
193
|
});
|
|
179
194
|
|
|
180
195
|
|
|
181
196
|
// POST method
|
|
182
|
-
endpoint.post("/
|
|
197
|
+
endpoint.post("/fruit", Credentials, (req, res) => {
|
|
183
198
|
// @response
|
|
184
199
|
res.json({
|
|
185
200
|
code: 200,
|
|
201
|
+
status: "SUCCESS",
|
|
202
|
+
message: "POST request at /fruit",
|
|
186
203
|
result: {
|
|
187
204
|
id: req.body.id,
|
|
188
205
|
name: req.body.name,
|
|
@@ -192,21 +209,23 @@ exports.init = () => {
|
|
|
192
209
|
|
|
193
210
|
|
|
194
211
|
// PUT method
|
|
195
|
-
endpoint.put("/
|
|
212
|
+
endpoint.put("/fruit/:id", Credentials, (req, res) => {
|
|
196
213
|
// @response
|
|
197
214
|
res.json({
|
|
198
215
|
code: 200,
|
|
199
|
-
|
|
216
|
+
status: "SUCCESS",
|
|
217
|
+
message: "PUT request at /fruit/" + req.params.id,
|
|
200
218
|
});
|
|
201
219
|
});
|
|
202
220
|
|
|
203
221
|
|
|
204
222
|
// DELETE method
|
|
205
|
-
endpoint.delete("/
|
|
223
|
+
endpoint.delete("/fruit/:id", Credentials, (req, res) => {
|
|
206
224
|
// @response
|
|
207
225
|
res.json({
|
|
208
226
|
code: 200,
|
|
209
|
-
|
|
227
|
+
status: "SUCCESS",
|
|
228
|
+
message: "DELETE request at /fruit/" + req.params.id,
|
|
210
229
|
});
|
|
211
230
|
});
|
|
212
231
|
|
|
@@ -215,30 +234,23 @@ exports.init = () => {
|
|
|
215
234
|
}
|
|
216
235
|
```
|
|
217
236
|
|
|
218
|
-
|
|
237
|
+
### Example ***(Sequelize)*** : Fruit endpoints.
|
|
219
238
|
|
|
220
|
-
📂
|
|
239
|
+
📂 fruit-endpoints.js
|
|
221
240
|
```js
|
|
222
|
-
//
|
|
223
|
-
const {
|
|
224
|
-
|
|
225
|
-
// Model schema & function
|
|
226
|
-
const { Fruits } = require("@/models/Fruits");
|
|
241
|
+
// Require Model schema, Function & Others
|
|
242
|
+
const { Fruit } = require("@/models/Fruit");
|
|
227
243
|
|
|
228
244
|
exports.init = () => {
|
|
229
245
|
|
|
230
|
-
//
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
// Other GET method
|
|
240
|
-
endpoint.get('/example-fruits', (req, res) => {
|
|
241
|
-
...
|
|
246
|
+
// GET method
|
|
247
|
+
endpoint.get('/fruit', async (req, res) => {
|
|
248
|
+
// example call Fruit model for get data
|
|
249
|
+
res.json({
|
|
250
|
+
code: 200,
|
|
251
|
+
status: "SUCCESS",
|
|
252
|
+
results: await Fruit.findAll();
|
|
253
|
+
});
|
|
242
254
|
});
|
|
243
255
|
|
|
244
256
|
...
|
|
@@ -247,17 +259,17 @@ exports.init = () => {
|
|
|
247
259
|
```
|
|
248
260
|
|
|
249
261
|
|
|
250
|
-
|
|
262
|
+
## # Generate Models ###
|
|
251
263
|
|
|
252
|
-
The `models` keep the files of function(s) for
|
|
264
|
+
The `models` keep the files of function(s) data managemnets for Retriving, Creating, Updating and Destroying (CRUD). for understanding you might make model name same your table name inside `src/models` folder.
|
|
253
265
|
|
|
254
266
|
```sh
|
|
255
267
|
$ beech make modelName --model
|
|
256
268
|
```
|
|
257
269
|
|
|
258
|
-
|
|
270
|
+
### Example ***(Basic)*** : Fruit model.
|
|
259
271
|
|
|
260
|
-
📂
|
|
272
|
+
📂 Fruit.js
|
|
261
273
|
```js
|
|
262
274
|
module.exports = {
|
|
263
275
|
|
|
@@ -272,10 +284,10 @@ module.exports = {
|
|
|
272
284
|
},
|
|
273
285
|
|
|
274
286
|
// Example basic function get data from MySQL table
|
|
275
|
-
|
|
287
|
+
getFruit() {
|
|
276
288
|
|
|
277
|
-
//
|
|
278
|
-
mysql.default_db.query("SELECT * FROM
|
|
289
|
+
// calling Pool connection name by `mysql.default_db`
|
|
290
|
+
mysql.default_db.query("SELECT * FROM fruit", (err, results) => {
|
|
279
291
|
|
|
280
292
|
if (err) { throw err }
|
|
281
293
|
return results;
|
|
@@ -287,64 +299,208 @@ module.exports = {
|
|
|
287
299
|
};
|
|
288
300
|
```
|
|
289
301
|
|
|
290
|
-
|
|
302
|
+
### Example ***(Sequelize)*** : Fruit model.
|
|
291
303
|
|
|
292
304
|
You can asign more DataTypes, Learn more : [Sequelize docs](https://sequelize.org/docs/v6/core-concepts/model-basics/#data-types)
|
|
293
305
|
|
|
294
|
-
📂
|
|
306
|
+
📂Fruit.js
|
|
295
307
|
```js
|
|
296
308
|
const { Schema } = require("beech-api");
|
|
297
309
|
|
|
298
310
|
// Define table Schema with `Schema(sql.default_db)` connection name
|
|
299
|
-
const
|
|
311
|
+
const Fruit = Schema(sql.default_db).define("fruit", {
|
|
300
312
|
fruit_id: {
|
|
301
|
-
field: "id", // Ref:
|
|
313
|
+
field: "id", // Rename PK field to fruit_id Ref: `id` field in fruit table
|
|
302
314
|
type: DataTypes.INTEGER,
|
|
303
315
|
autoIncrement: true,
|
|
304
316
|
primaryKey: true
|
|
305
317
|
},
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
318
|
+
friut_uuid: {
|
|
319
|
+
field: "uuid",
|
|
320
|
+
type: DataTypes.STRING(100),
|
|
321
|
+
allowNull: true,
|
|
322
|
+
defaultValue: DataTypes.UUIDV4,
|
|
323
|
+
},
|
|
324
|
+
fruitName: DataTypes.STRING,
|
|
325
|
+
fruitQty: DataTypes.INTEGER,
|
|
326
|
+
fruitPrice: {
|
|
309
327
|
type: DataTypes.INTEGER,
|
|
310
328
|
allowNull: false, // Allow null feilds
|
|
311
329
|
},
|
|
312
|
-
createdAt:
|
|
313
|
-
|
|
330
|
+
createdAt: {
|
|
331
|
+
type: DataTypes.DATE,
|
|
332
|
+
allowNull: false,
|
|
333
|
+
defaultValue: DataTypes.NOW,
|
|
334
|
+
},
|
|
335
|
+
updatedAt: {
|
|
336
|
+
type: DataTypes.DATE,
|
|
337
|
+
allowNull: true,
|
|
338
|
+
},
|
|
339
|
+
}, {
|
|
340
|
+
// Enables timestamps with createdAt and updatedAt
|
|
341
|
+
timestamps: true,
|
|
342
|
+
// Custom field names createdAt and updatedAt
|
|
343
|
+
createdAt: "createdAt",
|
|
344
|
+
updatedAt: "updatedAt",
|
|
314
345
|
});
|
|
315
346
|
|
|
347
|
+
Fruit.options = {
|
|
348
|
+
// Choose one for Allow magic generate default Endpoint (CRUD), It's like magic creating The endpoints for you (CRUD) ✨
|
|
349
|
+
|
|
350
|
+
// Option 1: Allow all methods
|
|
351
|
+
defaultEndpoint: true,
|
|
352
|
+
|
|
353
|
+
// Option 2: Allow with specific per methods
|
|
354
|
+
defaultEndpoint: {
|
|
355
|
+
GET: true,
|
|
356
|
+
POST: false,
|
|
357
|
+
PATCH: {
|
|
358
|
+
allow: true, // allow Auto-Endpoint
|
|
359
|
+
jwt: {
|
|
360
|
+
allow: true, // allow JWT
|
|
361
|
+
broken_role: [
|
|
362
|
+
{ role: [1, 2] },
|
|
363
|
+
],
|
|
364
|
+
},
|
|
365
|
+
},
|
|
366
|
+
DELETE: false,
|
|
367
|
+
},
|
|
368
|
+
|
|
369
|
+
limitRows: 100, // Limit rows default 100
|
|
370
|
+
|
|
371
|
+
};
|
|
372
|
+
|
|
316
373
|
// Example Finder by id (ORM), Learn more: https://sequelize.org/docs/v6/core-concepts/model-querying-finders/
|
|
317
|
-
function
|
|
318
|
-
return
|
|
374
|
+
function exampleFindOneFruitById(id) {
|
|
375
|
+
return Fruit.findOne({ where: { id: id } });
|
|
319
376
|
}
|
|
320
377
|
|
|
321
|
-
// Example Raw Query, Learn more: https://sequelize.org/docs/v6/core-concepts/raw-queries/
|
|
322
|
-
function exampleGetAllFruits(id) {
|
|
323
|
-
return Fruits.query("SELECT * FROM fruits");
|
|
324
|
-
}
|
|
325
378
|
|
|
326
379
|
// Example Raw Query with Model Instances. This allows you to easily map a query to a predefined model
|
|
327
|
-
function
|
|
328
|
-
return
|
|
329
|
-
model:
|
|
380
|
+
function exampleGetAllFruitWithModelInstance(id) {
|
|
381
|
+
return Fruit.query("SELECT * FROM fruit", {
|
|
382
|
+
model: Fruit, // When JOIN table needed register that table [Fruit, ...]
|
|
330
383
|
mapToModel: true // pass true here if you have any mapped fields
|
|
331
384
|
});
|
|
332
385
|
}
|
|
333
386
|
|
|
387
|
+
// Example Raw Query, Learn more: https://sequelize.org/docs/v6/core-concepts/raw-queries/
|
|
388
|
+
function exampleGetAllFruit(id) {
|
|
389
|
+
return Fruit.query("SELECT * FROM fruit");
|
|
390
|
+
}
|
|
391
|
+
|
|
334
392
|
...
|
|
335
393
|
|
|
336
394
|
// Export Schema, Function, ...
|
|
337
395
|
module.exports = {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
396
|
+
Fruit,
|
|
397
|
+
exampleFindOneFruitById,
|
|
398
|
+
exampleGetAllFruitWithModelInstance,
|
|
399
|
+
exampleGetAllFruit,
|
|
342
400
|
...
|
|
343
401
|
};
|
|
344
402
|
```
|
|
403
|
+
#### That's cool! It's like magic creating The endpoints for you (CRUD) ✨
|
|
404
|
+
|
|
405
|
+
Now! you can request to `/fruit` with methods GET, POST, PATCH and DELETE like this.
|
|
406
|
+
|
|
407
|
+
| Efficacy | Method | Endpoint | Body |
|
|
408
|
+
|:---------|:---------|:-----------------------|:-----------|
|
|
409
|
+
| Create | POST | /fruit | { } |
|
|
410
|
+
| Read | GET | /fruit | No |
|
|
411
|
+
| Read | GET | /fruit/:id | No |
|
|
412
|
+
| Read | GET | /fruit/:limit/:offset | No |
|
|
413
|
+
| Update | PATCH | /fruit/:id | { } |
|
|
414
|
+
| Delete | DELETE | /fruit/:id | No |
|
|
415
|
+
|
|
416
|
+
## # Transactions
|
|
417
|
+
|
|
418
|
+
Sequelize does not use transactions by default. However, for production-ready usage of Sequelize, you should definitely configure Sequelize to use transactions.
|
|
419
|
+
|
|
420
|
+
Beech use Sequelize supports three ways of using transactions:
|
|
421
|
+
|
|
422
|
+
- ### Way 1 - Disorganized transactions :
|
|
423
|
+
```js
|
|
424
|
+
// First, we start a transaction from your connection and save it into a variable
|
|
425
|
+
const t = await Fruit.transaction();
|
|
426
|
+
|
|
427
|
+
try {
|
|
428
|
+
|
|
429
|
+
// Then, we do some calls passing this transaction as an option:
|
|
430
|
+
const fruit = await Fruit.create({ fruitName: 'Banana', fruitQty: '5', }, { transaction: t });
|
|
431
|
+
await fruit.addSibling({ fruitName: 'Litle', fruitQty: '2', }, { transaction: t }); // Error function
|
|
432
|
+
|
|
433
|
+
// If the execution reaches this line, no errors were thrown.
|
|
434
|
+
// We commit the transaction.
|
|
435
|
+
await t.commit();
|
|
436
|
+
|
|
437
|
+
} catch (error) {
|
|
438
|
+
|
|
439
|
+
// If the execution reaches this line, an error was thrown.
|
|
440
|
+
// We rollback the transaction.
|
|
441
|
+
await t.rollback();
|
|
442
|
+
|
|
443
|
+
}
|
|
444
|
+
```
|
|
345
445
|
|
|
446
|
+
- ### Way 2 - Organized transactions :
|
|
447
|
+
```js
|
|
448
|
+
// First, we start a transaction from your connection and save it into a variable
|
|
449
|
+
Fruit.transaction(async t => {
|
|
450
|
+
try {
|
|
451
|
+
|
|
452
|
+
// Then, we do some calls passing this transaction as an option:
|
|
453
|
+
const fruit = await Fruit.create({ fruitName: 'Banana', fruitQty: '5', }, { transaction: t });
|
|
454
|
+
await fruit.addSibling({ fruitName: 'Litle', fruitQty: '2', }, { transaction: t }); // Error function
|
|
455
|
+
|
|
456
|
+
// If the execution reaches this line, no errors were thrown.
|
|
457
|
+
// We commit the transaction.
|
|
458
|
+
await t.commit();
|
|
459
|
+
|
|
460
|
+
} catch (error) {
|
|
346
461
|
|
|
347
|
-
|
|
462
|
+
// If the execution reaches this line, an error was thrown.
|
|
463
|
+
// We rollback the transaction.
|
|
464
|
+
await t.rollback();
|
|
465
|
+
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
- ### Way 3 - Transactions set Isolation levels :
|
|
471
|
+
|
|
472
|
+
The possible [isolations levels](https://sequelize.org/docs/v6/other-topics/transactions/#isolation-levels) to use when starting a transaction:
|
|
473
|
+
|
|
474
|
+
```js
|
|
475
|
+
const { Transaction } = require('sequelize');
|
|
476
|
+
|
|
477
|
+
// First, we start a transaction from your connection and save it into a variable
|
|
478
|
+
Fruit.transaction(
|
|
479
|
+
{
|
|
480
|
+
isolationLevel: Transaction.ISOLATION_LEVELS.SERIALIZABLE,
|
|
481
|
+
},
|
|
482
|
+
async t => {
|
|
483
|
+
try {
|
|
484
|
+
|
|
485
|
+
// Then, we do some calls passing this transaction as an option:
|
|
486
|
+
const fruit = await Fruit.create({ fruitName: 'Banana', fruitQty: '5', }, { transaction: t });
|
|
487
|
+
await fruit.addSibling({ fruitName: 'Litle', fruitQty: '2', }, { transaction: t }); // Error function
|
|
488
|
+
|
|
489
|
+
// If the execution reaches this line, no errors were thrown.
|
|
490
|
+
// We commit the transaction.
|
|
491
|
+
await t.commit();
|
|
492
|
+
|
|
493
|
+
} catch (error) {
|
|
494
|
+
|
|
495
|
+
// If the execution reaches this line, an error was thrown.
|
|
496
|
+
// We rollback the transaction.
|
|
497
|
+
await t.rollback();
|
|
498
|
+
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
## # Generate Helpers ###
|
|
348
504
|
|
|
349
505
|
The `helpers` keep the files of functions for process specific something in the project. So, you might create the `helpers` in path `src/helpers` folder.
|
|
350
506
|
|
|
@@ -352,7 +508,7 @@ The `helpers` keep the files of functions for process specific something in the
|
|
|
352
508
|
$ beech make helperName --helper
|
|
353
509
|
```
|
|
354
510
|
|
|
355
|
-
|
|
511
|
+
***Example:*** Text editor helper.
|
|
356
512
|
|
|
357
513
|
📂 TextEditor.js
|
|
358
514
|
```js
|
|
@@ -371,11 +527,11 @@ module.exports = {
|
|
|
371
527
|
};
|
|
372
528
|
```
|
|
373
529
|
|
|
374
|
-
|
|
530
|
+
# Authentication (passport-jwt)
|
|
375
531
|
|
|
376
532
|
Passport is authentication middleware for Node. It is designed to serve a singular purpose: authenticate requests. When writing modules, encapsulation is a virtue, so Passport delegates all other functionality to the application. This separation of concerns keeps code clean and maintainable, and makes Passport extremely easy to integrate into an application.
|
|
377
533
|
|
|
378
|
-
Passport-jwt
|
|
534
|
+
### Passport-jwt Initialization
|
|
379
535
|
|
|
380
536
|
```sh
|
|
381
537
|
$ beech passport init
|
|
@@ -386,7 +542,7 @@ After passport initialized the `passport.config.js` it's appeared
|
|
|
386
542
|
📂 passport.config.js
|
|
387
543
|
```js
|
|
388
544
|
module.exports = {
|
|
389
|
-
//
|
|
545
|
+
// Allow for using passport-jwt
|
|
390
546
|
jwt_allow: true,
|
|
391
547
|
|
|
392
548
|
// custom authenticaiton endpoint name, default `/authentication`
|
|
@@ -398,6 +554,11 @@ module.exports = {
|
|
|
398
554
|
// token expiry time (seconds), default 86400 sec. it's expired in 24 hr.
|
|
399
555
|
token_expired: 86400,
|
|
400
556
|
|
|
557
|
+
// Allow for using global jwt broken role
|
|
558
|
+
jwt_broken_role: [
|
|
559
|
+
// { role: [1, 2, 9] },
|
|
560
|
+
],
|
|
561
|
+
|
|
401
562
|
model: {
|
|
402
563
|
// Main sql connection name. You must make sure connection name like inside `app.config.js` file and choose one connection name.
|
|
403
564
|
name: "default_db",
|
|
@@ -410,10 +571,27 @@ module.exports = {
|
|
|
410
571
|
password_field: "",
|
|
411
572
|
|
|
412
573
|
// JWT playload data, You can add it. Example: ["name", "email", ...]
|
|
413
|
-
fields: []
|
|
574
|
+
fields: [],
|
|
575
|
+
|
|
576
|
+
// Other fields add for authentication.
|
|
577
|
+
guard: {
|
|
578
|
+
// Basic guard field, Example: ["pin", "hint", "2fa"]
|
|
579
|
+
guard_field: [],
|
|
580
|
+
|
|
581
|
+
// Advanced guard jwt request (needed some logical from front-end)
|
|
582
|
+
advanced_guard: {
|
|
583
|
+
allow: false,
|
|
584
|
+
entity: "", // default entity `timing`
|
|
585
|
+
secret: "top_secret",
|
|
586
|
+
time_expired: {
|
|
587
|
+
minutes: 1, // should length [0-60]
|
|
588
|
+
seconds: 0, // should length [0-60]
|
|
589
|
+
},
|
|
590
|
+
},
|
|
591
|
+
},
|
|
414
592
|
},
|
|
415
593
|
|
|
416
|
-
//
|
|
594
|
+
// Allow for using request with app_key entity (Every request must be using the app_key entity in headers)
|
|
417
595
|
app_key_allow: false
|
|
418
596
|
|
|
419
597
|
...
|
|
@@ -421,7 +599,7 @@ module.exports = {
|
|
|
421
599
|
};
|
|
422
600
|
```
|
|
423
601
|
|
|
424
|
-
|
|
602
|
+
**Authentication structure :** Simple ``users`` table:
|
|
425
603
|
```
|
|
426
604
|
==============================================================
|
|
427
605
|
| id | username | password | name | email |
|
|
@@ -434,10 +612,10 @@ When you config passport with ```users``` table already. You will got Auth endpo
|
|
|
434
612
|
```js
|
|
435
613
|
POST: "/authentication" // Request token
|
|
436
614
|
POST: "/authentication/create" // Create new Auth data
|
|
437
|
-
PATCH: "/authentication/update/:id" // Update old Auth data
|
|
615
|
+
PATCH: "/authentication/update/:id" // Update old Auth data (needed id)
|
|
438
616
|
```
|
|
439
617
|
|
|
440
|
-
Example
|
|
618
|
+
***XHR Example :***
|
|
441
619
|
|
|
442
620
|
```js
|
|
443
621
|
// Request with body for gether Token
|
|
@@ -460,7 +638,7 @@ POST: "/authentication/create"
|
|
|
460
638
|
|
|
461
639
|
// Request with body for Update Auth data
|
|
462
640
|
PATCH: "/authentication/update/1"
|
|
463
|
-
|
|
641
|
+
headers: Authorization: Bearer <your_token>
|
|
464
642
|
{
|
|
465
643
|
username: "update_bombkiml",
|
|
466
644
|
password: "update_secret",
|
|
@@ -469,7 +647,88 @@ Bearer Authorization: your_token
|
|
|
469
647
|
}
|
|
470
648
|
```
|
|
471
649
|
|
|
472
|
-
|
|
650
|
+
# Beech Two Factor (2FA)
|
|
651
|
+
You can easy using 2 Factor authenticate with ```guard_field``` inside ```passport.config.js``` file and add your Guard field ex: ```2fa``` field for Authenticate Conditions.
|
|
652
|
+
|
|
653
|
+
## # Usage guard (2FA, Other)
|
|
654
|
+
|
|
655
|
+
📂 passport.config.js
|
|
656
|
+
```js
|
|
657
|
+
module.exports = {
|
|
658
|
+
...
|
|
659
|
+
|
|
660
|
+
guard: {
|
|
661
|
+
// Other fields add for authenticate, exmaple ["pin", "hint", "2fa"]
|
|
662
|
+
guard_field: ["2fa"], 👈 // your feild guard.
|
|
663
|
+
|
|
664
|
+
...
|
|
665
|
+
},
|
|
666
|
+
|
|
667
|
+
...
|
|
668
|
+
|
|
669
|
+
}
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
## # Beech Advanced Guard (Timing)
|
|
673
|
+
Advance Guard for Protection your Endpoint with Timing. You can allow in object ```advance_guard``` inside ```passport.config.js``` file. So let's go add your Advance Guard Configuration.
|
|
674
|
+
|
|
675
|
+
📂 passport.config.js
|
|
676
|
+
```js
|
|
677
|
+
module.exports = {
|
|
678
|
+
...
|
|
679
|
+
|
|
680
|
+
guard: {
|
|
681
|
+
...
|
|
682
|
+
|
|
683
|
+
// Advanced guard jwt request (needed some logical from front-end)
|
|
684
|
+
advanced_guard: {
|
|
685
|
+
allow: false, 👈 // advanced guard allow for All Endpoint.
|
|
686
|
+
entity: "", // default entity `timing`
|
|
687
|
+
secret: "your_advance_guard_secret",
|
|
688
|
+
time_expired: {
|
|
689
|
+
minutes: 1, // should length [0-60]
|
|
690
|
+
seconds: 0, // should length [0-60]
|
|
691
|
+
},
|
|
692
|
+
},
|
|
693
|
+
},
|
|
694
|
+
|
|
695
|
+
...
|
|
696
|
+
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
<b>After configure</b>, You must add some logic in your front-end like this.
|
|
702
|
+
|
|
703
|
+
Before add logic, We needed [```beech-auth0```](https://github.com/bombkiml/beech-auth0) and [```moment.js```](https://momentjs.com) for apply in Policy.
|
|
704
|
+
|
|
705
|
+
```sh
|
|
706
|
+
# NPM
|
|
707
|
+
$ npm install --save beech-auth0 moment
|
|
708
|
+
|
|
709
|
+
# Yarn
|
|
710
|
+
$ yarn add beech-auth0 moment
|
|
711
|
+
```
|
|
712
|
+
Now! you can add some logic.
|
|
713
|
+
```js
|
|
714
|
+
const { Auth0 } = require("beech-auth0");
|
|
715
|
+
const moment = require("moment");
|
|
716
|
+
|
|
717
|
+
// Get UNIX TIME with moment
|
|
718
|
+
let unix_time = moment().unix();
|
|
719
|
+
|
|
720
|
+
// Auth0 Policy.
|
|
721
|
+
Auth0(unix_time, 'your_advance_guard_secret', (error, hashing) => {
|
|
722
|
+
|
|
723
|
+
// Your XHR request for All Endpoint.
|
|
724
|
+
POST: "/authentication"
|
|
725
|
+
headers: timing: hashing, 👈 // Assign advance guard entity to headers with callback hashing.
|
|
726
|
+
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
## # Beech User Auth Managements ###
|
|
473
732
|
You can easy management `users` data with Beech, Only ```Store, Update``` NO ```Delete```, Anything you can make DELETE endpoint by yourself
|
|
474
733
|
|
|
475
734
|
```js
|
|
@@ -513,12 +772,12 @@ Update(data, id, (err, updated) => {
|
|
|
513
772
|
});
|
|
514
773
|
```
|
|
515
774
|
|
|
516
|
-
|
|
775
|
+
# Beech with Official Strategy
|
|
517
776
|
|
|
518
777
|
Latest supported with ``Google`` and ``Facebook`` Strategy.
|
|
519
778
|
|
|
520
779
|
|
|
521
|
-
|
|
780
|
+
## # Google Strategy
|
|
522
781
|
|
|
523
782
|
|
|
524
783
|
The Google OAuth 2.0 authentication strategy authenticates users using a Google account and OAuth 2.0 tokens. The strategy requires a verify callback, which accepts these credentials and calls done providing a user, as well as options specifying a client ID, client secret, and callback URL.
|
|
@@ -535,7 +794,7 @@ strategy: {
|
|
|
535
794
|
|
|
536
795
|
google: {
|
|
537
796
|
|
|
538
|
-
// Allow using google strategy
|
|
797
|
+
// Allow for using google strategy
|
|
539
798
|
allow: true,
|
|
540
799
|
|
|
541
800
|
// Authen profile store fields available: `google_id`, `name`, `email`, `photos`, `locate`
|
|
@@ -577,7 +836,7 @@ Place a button on the application's login page, prompting the user to sign in wi
|
|
|
577
836
|
❓ **Note:** The URL "``/authentication``" will be follow by ``auth_endpoint`` when you custom it.
|
|
578
837
|
|
|
579
838
|
|
|
580
|
-
|
|
839
|
+
## # Facebook Strategy
|
|
581
840
|
|
|
582
841
|
|
|
583
842
|
Facebook Login allows users to sign in using their Facebook account. Support for Faceboook Login is provided by the ``passport-facebook`` package.
|
|
@@ -594,7 +853,7 @@ strategy: {
|
|
|
594
853
|
|
|
595
854
|
facebook: {
|
|
596
855
|
|
|
597
|
-
// Allow using facebook strategy
|
|
856
|
+
// Allow for using facebook strategy
|
|
598
857
|
allow: true,
|
|
599
858
|
|
|
600
859
|
// Authen profile store fields available: `facebook_id`, `name`, `email`, `photos`, `locate`
|
|
@@ -641,16 +900,35 @@ Place a button on the application's login page, prompting the user to sign in wi
|
|
|
641
900
|
|
|
642
901
|
❓ **Note:** The URL "``/authentication``" will be follow by ``auth_endpoint`` when you custom it.
|
|
643
902
|
|
|
644
|
-
|
|
903
|
+
# CORS Origin & Server Configuration
|
|
645
904
|
The origin array to the callback can be any value allowed for the origin option of the middleware. Certain CORS requests are considered `complex` and require an initial OPTIONS request (called the `pre-flight request`). You can allowed CORS origin inside file `beech.config.js`
|
|
646
905
|
|
|
647
906
|
📂 beech.config.js
|
|
648
907
|
```js
|
|
649
908
|
module.exports = {
|
|
650
909
|
defineConfig: {
|
|
910
|
+
// Base public path when served in development or production.
|
|
911
|
+
base: process.env.NODE_ENV === "production"
|
|
912
|
+
? "/my-api/" // For Production
|
|
913
|
+
: "/", // For Development
|
|
914
|
+
|
|
651
915
|
server: {
|
|
916
|
+
// Client request allow origin whitelist
|
|
652
917
|
origin: ["http://example.com", "http://my-webapp:8080", "https://cat.io"],
|
|
653
918
|
originSensitive: false, // Sensitive with contrasts wording
|
|
919
|
+
|
|
920
|
+
// API Request rate limit (Disabled for Remove it.)
|
|
921
|
+
rateLimit: {
|
|
922
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
923
|
+
limit: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes).
|
|
924
|
+
// store: ... , // Redis, Memcached, etc.
|
|
925
|
+
// See more: https://www.npmjs.com/package/express-rate-limit#Configuration
|
|
926
|
+
},
|
|
927
|
+
|
|
928
|
+
// API Duplicate Request (Disabled for Set expiration to 0 zero.)
|
|
929
|
+
duplicateRequest: {
|
|
930
|
+
expiration: 500, // Can't duplicate request for 5 milliseconds each IP requests per `window`
|
|
931
|
+
},
|
|
654
932
|
},
|
|
655
933
|
},
|
|
656
934
|
}
|
|
@@ -658,16 +936,95 @@ module.exports = {
|
|
|
658
936
|
|
|
659
937
|
❓ **Note:** When you must to allowed all Origin. You can assign `*` or `[]` null value to `origin` variable.
|
|
660
938
|
|
|
939
|
+
## # Custom Endpoint Specific Rate Limit
|
|
940
|
+
When you need assign specific request Endpoint with [express-rate-limit](https://www.npmjs.com/package/express-rate-limit), You can managemnet with Beech object ```rateLimit``` for your custom Rate Limit like this.
|
|
661
941
|
|
|
662
|
-
|
|
942
|
+
```js
|
|
943
|
+
const { rateLimit } = require("beech-api").Express;
|
|
663
944
|
|
|
664
|
-
|
|
945
|
+
// Specific of your rate limit
|
|
946
|
+
const specificRateLimit1 = rateLimit({
|
|
947
|
+
windowMs: 5 * 60 * 1000, // 5 minutes
|
|
948
|
+
limit: 20,
|
|
949
|
+
// more...
|
|
950
|
+
});
|
|
951
|
+
|
|
952
|
+
// Your Endpoints...
|
|
953
|
+
endpoint.get("/banana", specificRateLimit1, (req, res) => {
|
|
954
|
+
...
|
|
955
|
+
});
|
|
956
|
+
|
|
957
|
+
...
|
|
958
|
+
```
|
|
959
|
+
|
|
960
|
+
## # Custom Endpoint Specific Slow Down
|
|
961
|
+
**DON'T DO IT.** Because it's annoying to users.
|
|
962
|
+
|
|
963
|
+
When you need assign specific request Endpoint with [express-slow-down](https://www.npmjs.com/package/express-slow-down), You can managemnet with Beech object ```slowDown``` for your custom Slow Down like this.
|
|
964
|
+
|
|
965
|
+
```js
|
|
966
|
+
const { slowDown } = require("beech-api").Express;
|
|
967
|
+
|
|
968
|
+
// Specific of your slow down
|
|
969
|
+
const specificSlowDown1 = slowDown({
|
|
970
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
971
|
+
delayAfter: 5, // Allow 5 requests per 15 minutes.
|
|
972
|
+
delayMs: (hits) => hits * 100, // Add 100 ms of delay to every request after the 5th one.
|
|
973
|
+
// more...
|
|
974
|
+
|
|
975
|
+
/**
|
|
976
|
+
* So:
|
|
977
|
+
*
|
|
978
|
+
* - requests 1-5 are not delayed.
|
|
979
|
+
* - request 6 is delayed by 600ms
|
|
980
|
+
* - request 7 is delayed by 700ms
|
|
981
|
+
* - request 8 is delayed by 800ms
|
|
982
|
+
*
|
|
983
|
+
* and so on. After 15 minutes, the delay is reset to 0.
|
|
984
|
+
*/
|
|
985
|
+
});
|
|
986
|
+
|
|
987
|
+
// Your Endpoints...
|
|
988
|
+
endpoint.get("/banana", specificSlowDown1, (req, res) => {
|
|
989
|
+
...
|
|
990
|
+
});
|
|
991
|
+
|
|
992
|
+
...
|
|
993
|
+
```
|
|
994
|
+
|
|
995
|
+
## # Custom Endpoint Specific Duplicate Request
|
|
996
|
+
This middleware to Limit each IP duplicated requests per window.
|
|
997
|
+
|
|
998
|
+
When you need assign specific request Endpoint with duplicate request use [express-duplicate-request](https://github.com/bombkiml/express-duplicate-request), You can managemnet with Beech object ```duplicateRequest``` for your custom Duplicate Request like this.
|
|
999
|
+
|
|
1000
|
+
```js
|
|
1001
|
+
const { duplicateRequest } = require("beech-api").Express;
|
|
1002
|
+
|
|
1003
|
+
// Specific of your duplicate request
|
|
1004
|
+
const specificDup1 = duplicateRequest({
|
|
1005
|
+
expiration: 500, // Can't duplicate request for 5 milliseconds, Should 0 to disabled
|
|
1006
|
+
// more...
|
|
1007
|
+
});
|
|
1008
|
+
|
|
1009
|
+
// Your Endpoints...
|
|
1010
|
+
endpoint.get("/banana", specificDup1, (req, res) => {
|
|
1011
|
+
...
|
|
1012
|
+
});
|
|
1013
|
+
|
|
1014
|
+
...
|
|
1015
|
+
```
|
|
1016
|
+
|
|
1017
|
+
|
|
1018
|
+
|
|
1019
|
+
# Databases managements
|
|
1020
|
+
|
|
1021
|
+
## # Migrations & Seeder
|
|
665
1022
|
|
|
666
1023
|
Just like you use Git / SVN to manage changes in your source code, you can use migrations to keep track of changes to the database. With migrations you can transfer your existing database into another state and vice versa: Those state transitions are saved in migration files, which describe how to get to the new state and how to revert the changes in order to get back to the old state.
|
|
667
1024
|
|
|
668
1025
|
You will need [Sequelize CLI.](https://github.com/sequelize/cli) The CLI ships support for [migrations](https://sequelize.org/v5/manual/migrations.html) and project.
|
|
669
1026
|
|
|
670
|
-
|
|
1027
|
+
## # Usage
|
|
671
1028
|
|
|
672
1029
|
To create an empty project you will need to execute `init` command
|
|
673
1030
|
|
|
@@ -682,7 +1039,7 @@ This will create following folders inside `databases` folder.
|
|
|
682
1039
|
- `migrations`, contains all migration files.
|
|
683
1040
|
- `seeders`, contains all seed files.
|
|
684
1041
|
|
|
685
|
-
|
|
1042
|
+
## # Configuration
|
|
686
1043
|
|
|
687
1044
|
Before continuing further we will need to tell CLI how to connect to database. To do that let's open default config file `databases/config/database.json` It looks something like this:
|
|
688
1045
|
|
|
@@ -716,7 +1073,7 @@ Before continuing further we will need to tell CLI how to connect to database. T
|
|
|
716
1073
|
|
|
717
1074
|
❓ **Note:** If your database doesn't exists yet, you can just call `npx sequelize-cli db:create` command. With proper access it will create that database for you.
|
|
718
1075
|
|
|
719
|
-
|
|
1076
|
+
## # Creating first Migrations
|
|
720
1077
|
|
|
721
1078
|
Create `model` use `model:generate` command. This command requires two options.
|
|
722
1079
|
|
|
@@ -729,7 +1086,7 @@ Let's create a model name example `User`. See more about of [Datatypes](https://
|
|
|
729
1086
|
$ npx sequelize-cli model:generate --name User --attributes firstName:string,lastName:string,email:string,birhday:date
|
|
730
1087
|
```
|
|
731
1088
|
|
|
732
|
-
|
|
1089
|
+
## # Migrations Up and Down
|
|
733
1090
|
|
|
734
1091
|
Until this step, we haven't inserted anything into the database. We have just created required model and migration files for our first model User.
|
|
735
1092
|
|
|
@@ -744,7 +1101,7 @@ Until this step, we haven't inserted anything into the database. We have just cr
|
|
|
744
1101
|
$ npx sequelize-cli db:migrate:undo
|
|
745
1102
|
```
|
|
746
1103
|
|
|
747
|
-
|
|
1104
|
+
## # Creating First Seeder
|
|
748
1105
|
|
|
749
1106
|
To manage all data migrations you can use seeders. Seed files are some change in data that can be used to populate database table with sample data or test data.
|
|
750
1107
|
|
|
@@ -754,7 +1111,7 @@ Let's create a seed file which will add a demo user to our User table.
|
|
|
754
1111
|
$ npx sequelize-cli seed:generate --name user
|
|
755
1112
|
```
|
|
756
1113
|
|
|
757
|
-
|
|
1114
|
+
## # Seeder Up and Down
|
|
758
1115
|
|
|
759
1116
|
In last step you have create a seed file. It's still not committed to database. To do that we need to run a simple command.
|
|
760
1117
|
|
|
@@ -784,7 +1141,7 @@ In last step you have create a seed file. It's still not committed to database.
|
|
|
784
1141
|
$ npx sequelize-cli db:seed:undo:all
|
|
785
1142
|
```
|
|
786
1143
|
|
|
787
|
-
|
|
1144
|
+
# Testing
|
|
788
1145
|
|
|
789
1146
|
Test using [Jest](https://jestjs.io/en/) for testing the project. Jest is a delightful JavaScript Testing Framework with a focus on simplicity. Learn more [Jest docs](https://jestjs.io/docs/en/getting-started.html)
|
|
790
1147
|
|
|
@@ -792,13 +1149,13 @@ So, When you make the new endpoints it's automatic create test file end with `.s
|
|
|
792
1149
|
|
|
793
1150
|
Example endpoints testing :
|
|
794
1151
|
|
|
795
|
-
📂
|
|
1152
|
+
📂 fruit-endpoints.spec.js
|
|
796
1153
|
```js
|
|
797
|
-
const endpoint = baseUrl.concat("/
|
|
1154
|
+
const endpoint = baseUrl.concat("/fruit");
|
|
798
1155
|
|
|
799
1156
|
describe("Test endpoint : " + endpoint, () => {
|
|
800
1157
|
it("Truthy!", () => {
|
|
801
|
-
expect("/
|
|
1158
|
+
expect("/fruit").toBeTruthy();
|
|
802
1159
|
});
|
|
803
1160
|
|
|
804
1161
|
it("Respond with basic GET status code 200", (done) => {
|
|
@@ -811,26 +1168,13 @@ describe("Test endpoint : " + endpoint, () => {
|
|
|
811
1168
|
```
|
|
812
1169
|
|
|
813
1170
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
### # Implement with [PM2](https://pm2.keymetrics.io/)
|
|
817
|
-
[PM2](https://pm2.keymetrics.io/) is a daemon process manager that will help you manage and keep your application online. Getting started with PM2 is straightforward, it is offered as a simple and intuitive CLI, installable via [NPM](https://www.npmjs.com/).
|
|
818
|
-
|
|
819
|
-
```sh
|
|
820
|
-
# Start service as standalone
|
|
821
|
-
$ pm2 start ./node_modules/beech-api/packages/cli/beech --name <serviceName>
|
|
1171
|
+
# Implementation
|
|
822
1172
|
|
|
823
|
-
#
|
|
824
|
-
|
|
825
|
-
# Start service as cluster mode
|
|
826
|
-
$ pm2 start ./node_modules/beech-api/packages/cli/beech --name <serviceName> -i <instances>
|
|
827
|
-
```
|
|
828
|
-
|
|
829
|
-
### # Implement with [Docker](https://www.docker.com)
|
|
1173
|
+
## # Implement with [Docker](https://www.docker.com)
|
|
830
1174
|
|
|
831
1175
|
[Docker](https://www.docker.com) is an open platform for developing, shipping, and running applications. Docker enables you to separate your applications from your infrastructure so you can deliver software quickly.
|
|
832
1176
|
|
|
833
|
-
- **Create Dockerfile**
|
|
1177
|
+
- ### **Create Dockerfile**
|
|
834
1178
|
|
|
835
1179
|
Docker builds images automatically by reading the instructions from a Dockerfile -- a text file that contains all commands, in order, needed to build a given image. A Dockerfile adheres to a specific format and set of instructions which you can find at [Dockerfile reference](https://docs.docker.com/engine/reference/builder/).
|
|
836
1180
|
|
|
@@ -839,14 +1183,14 @@ Docker builds images automatically by reading the instructions from a Dockerfile
|
|
|
839
1183
|
FROM node:14.19-alpine
|
|
840
1184
|
ENV NODE_ENV=production
|
|
841
1185
|
WORKDIR /usr/src/api
|
|
842
|
-
COPY ["package.json", "package-lock.json*", "
|
|
1186
|
+
COPY ["package.json", "package-lock.json*", "./"]
|
|
843
1187
|
RUN npm install --production --silent && mv node_modules .
|
|
844
1188
|
COPY . .
|
|
845
1189
|
EXPOSE 9000
|
|
846
1190
|
CMD ["node", "./node_modules/beech-api/packages/cli/beech"]
|
|
847
1191
|
```
|
|
848
1192
|
|
|
849
|
-
- **Docker build image**
|
|
1193
|
+
- ### **Docker build image**
|
|
850
1194
|
|
|
851
1195
|
The docker build command builds an image from a Dockerfile and a context. The build’s context is the set of files at a specified location ```PATH``` or ```URL```. The PATH is a directory on your local filesystem. The URL is a Git repository location.
|
|
852
1196
|
|
|
@@ -856,16 +1200,16 @@ $ docker build -t <imageName> .
|
|
|
856
1200
|
|
|
857
1201
|
❓ **Note:** You can specify a repository and tag at which to save the new image : ``` $ docker build -t <imageName>:<tags> . ```
|
|
858
1202
|
|
|
859
|
-
- **Run docker**
|
|
1203
|
+
- ### **Run docker**
|
|
860
1204
|
|
|
861
1205
|
After create ``image`` you can run docker engine following :
|
|
862
1206
|
|
|
863
|
-
- **Docker Container (Standalone)**
|
|
1207
|
+
- ### **Docker Container (Standalone)**
|
|
864
1208
|
```sh
|
|
865
1209
|
$ docker run -d -p 9000:9000 --name <containerName> <imageName>
|
|
866
1210
|
```
|
|
867
1211
|
|
|
868
|
-
- **Create Docker Swarm (Cluster)**
|
|
1212
|
+
- ### **Create Docker Swarm (Cluster)**
|
|
869
1213
|
```sh
|
|
870
1214
|
# Initiate swarm
|
|
871
1215
|
$ docker swarm init
|
|
@@ -874,42 +1218,20 @@ $ docker build -t <imageName> .
|
|
|
874
1218
|
$ docker service create --replicas <instances> --name <containerName> --publish 9000:9000 <imageName>
|
|
875
1219
|
```
|
|
876
1220
|
|
|
1221
|
+
## # Implement with [PM2](https://pm2.keymetrics.io/)
|
|
1222
|
+
[PM2](https://pm2.keymetrics.io/) is a daemon process manager that will help you manage and keep your application online. Getting started with PM2 is straightforward, it is offered as a simple and intuitive CLI, installable via [NPM](https://www.npmjs.com/).
|
|
877
1223
|
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
Installation the package:
|
|
883
|
-
|
|
884
|
-
```
|
|
885
|
-
$ npm install line-api
|
|
886
|
-
```
|
|
887
|
-
|
|
888
|
-
Create file `Line.js` in `src/helpers` folder and copy code below:
|
|
889
|
-
|
|
890
|
-
📂 Line.js
|
|
891
|
-
```js
|
|
892
|
-
const Line = require("line-api");
|
|
893
|
-
|
|
894
|
-
module.exports = {
|
|
1224
|
+
```sh
|
|
1225
|
+
# Start service as standalone
|
|
1226
|
+
$ pm2 start ./node_modules/beech-api/packages/cli/beech --name <serviceName>
|
|
895
1227
|
|
|
896
|
-
|
|
897
|
-
const notify = new Line.Notify({
|
|
898
|
-
token: token
|
|
899
|
-
});
|
|
900
|
-
notify
|
|
901
|
-
.send({
|
|
902
|
-
message: message
|
|
903
|
-
})
|
|
904
|
-
.then(console.log);
|
|
905
|
-
}
|
|
1228
|
+
# OR
|
|
906
1229
|
|
|
907
|
-
|
|
1230
|
+
# Start service as cluster mode
|
|
1231
|
+
$ pm2 start ./node_modules/beech-api/packages/cli/beech --name <serviceName> -i <instances>
|
|
908
1232
|
```
|
|
909
1233
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
## Development
|
|
1234
|
+
# Development
|
|
913
1235
|
|
|
914
1236
|
Want to contribute or join for great job!, You can contact to me via
|
|
915
1237
|
|
|
@@ -917,6 +1239,6 @@ Want to contribute or join for great job!, You can contact to me via
|
|
|
917
1239
|
- E-mail: nattapat.jquery@gmail.com
|
|
918
1240
|
- Facebook: [https://www.facebook.com/bombkiml](https://www.facebook.com/bombkiml)
|
|
919
1241
|
|
|
920
|
-
|
|
1242
|
+
# License
|
|
921
1243
|
|
|
922
1244
|
The Beech API framework is open-sourced software licensed under the [MIT license.](https://opensource.org/licenses/MIT)
|