beech-api 3.9.0-beta.9-rc → 3.9.80

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 (59) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +1717 -1649
  3. package/index.js +2 -2
  4. package/package.json +92 -84
  5. package/packages/cli/beech +9 -10
  6. package/packages/cli/bin/beech-app.js +390 -390
  7. package/packages/cli/bin/beech-service.js +263 -170
  8. package/packages/cli/core/auth/Credentials.js +174 -174
  9. package/packages/cli/core/auth/Passport.js +664 -664
  10. package/packages/cli/core/auth/_Request.js +12 -12
  11. package/packages/cli/core/configure/_gitignore +16 -15
  12. package/packages/cli/core/configure/_sequelizerc +9 -9
  13. package/packages/cli/core/configure/app.config-basic.js +55 -55
  14. package/packages/cli/core/configure/app.config-sequelize.js +88 -88
  15. package/packages/cli/core/configure/beech.config.js +9 -9
  16. package/packages/cli/core/configure/global.config-basic.js +8 -8
  17. package/packages/cli/core/configure/global.config-sequelize.js +8 -8
  18. package/packages/cli/core/configure/jest.config.js +6 -6
  19. package/packages/cli/core/configure/jsconfig.json +8 -7
  20. package/packages/cli/core/configure/passport.config.js +97 -97
  21. package/packages/cli/core/databases/mysql.js +94 -95
  22. package/packages/cli/core/databases/sequelize.js +187 -188
  23. package/packages/cli/core/databases/test.js +250 -255
  24. package/packages/cli/core/file-walk/file-walk.js +35 -35
  25. package/packages/cli/core/generator/_endpoints +15 -15
  26. package/packages/cli/core/generator/_endpoints_basic +42 -42
  27. package/packages/cli/core/generator/_help +29 -19
  28. package/packages/cli/core/generator/_help_create +10 -10
  29. package/packages/cli/core/generator/_help_service +10 -10
  30. package/packages/cli/core/generator/_helpers +9 -9
  31. package/packages/cli/core/generator/_helpers_basic +166 -22
  32. package/packages/cli/core/generator/_models +6 -6
  33. package/packages/cli/core/generator/_models_basic +13 -13
  34. package/packages/cli/core/generator/_package +23 -19
  35. package/packages/cli/core/generator/_scheduler +32 -32
  36. package/packages/cli/core/generator/_spec +29 -29
  37. package/packages/cli/core/generator/index.js +1229 -992
  38. package/packages/cli/core/helpers/2fa.js +106 -106
  39. package/packages/cli/core/helpers/math.js +115 -115
  40. package/packages/cli/core/helpers/poolEntity.js +103 -103
  41. package/packages/cli/core/index.js +264 -266
  42. package/packages/cli/core/middleware/express/duplicateRequest.js +16 -16
  43. package/packages/cli/core/middleware/express/jwtCheckAllow.js +85 -85
  44. package/packages/cli/core/middleware/express/rateLimit.js +29 -29
  45. package/packages/cli/core/middleware/express/slowDown.js +2 -2
  46. package/packages/cli/core/middleware/index.js +6 -6
  47. package/packages/cli/core/middleware/origin/guard/advance.js +75 -75
  48. package/packages/cli/core/middleware/origin/whitelist/cors.js +94 -94
  49. package/packages/cli/core/services/http.express.js +481 -481
  50. package/packages/cli/core/test/check-node.js +21 -21
  51. package/packages/cli/core/test/utils.js +7 -7
  52. package/packages/cli/entry +10 -0
  53. package/packages/lib/index.js +6 -6
  54. package/packages/lib/src/endpoint.js +947 -885
  55. package/packages/lib/src/guard.js +60 -60
  56. package/packages/lib/src/salt.js +3 -3
  57. package/packages/lib/src/schema.js +96 -96
  58. package/packages/lib/src/specificExpress.js +7 -7
  59. package/packages/lib/src/user.js +271 -271
package/README.md CHANGED
@@ -1,1649 +1,1717 @@
1
- [![N|Solid](https://i.ibb.co/NKxx9NQ/beech320.jpg)](https://github.com/bombkiml)
2
-
3
- # Beech API framework
4
- #### Auto endpoint v.3.9.0 (LTS)
5
-
6
- [![beech-api release](https://img.shields.io/github/v/release/bombkiml/beech-api)](https://github.com/bombkiml/beech-api/releases/)
7
- [![PyPI license](https://shields.io/pypi/l/ansicolortags.svg)](https://github.com/bombkiml/beech-api/blob/master/README.md)
8
-
9
- # What is Beech API ?
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)
12
-
13
- ## Let's go
14
- - <b>[Installation](#installation)</b>
15
- - <b>[Creating a project](#creating-a-project)</b>
16
- - <b>[Upgrade to latest version](#upgrade-to-latest-version)</b>
17
- - <b>[Beech CLI tool available](#beech-cli-tool-available)</b>
18
- - ✨ <b>Automation Endpoints with CRUD</b>
19
- - [Database Connection](#database-connection)
20
- - [Model](#models)
21
- - [Retrieving data with Query String](#retrieving-data-with-query-string)
22
- - Conditions
23
- - Grouping
24
- - Ordering
25
- - Timestamps (Add-on in Store and Update)
26
- - [Transactions](#-transactions)
27
- - [Disorganized transactions](#way-1---disorganized-transactions-)
28
- - [Organized transactions](#way-2---organized-transactions-)
29
- - [Transactions set Isolation levels](#way-3---transactions-set-isolation-levels-)
30
- - [Endpoints](#endpoints)
31
- - [Helpers](#helpers)
32
- - 🔐 <b>System Management of Authentication</b>
33
- - [Authentication Manegement](#authentication-passport-jwt)
34
- - [Request Token](#request-token)
35
- - [Beech Guard](#beech-guard)
36
- - Verify Identity Management
37
- - Two Factor (2fa, OTP, etc.)
38
- - [Beech User Authentication Managements](#-beech-user-authentication-managements)
39
- - Create Auth
40
- - Update Auth
41
- - 🛠️ <b>Safe Endpoints Request</b>
42
- - [Rate Limit](#-custom-endpoint-specific-rate-limit)
43
- - [Slow Down](#-custom-endpoint-specific-slow-down)
44
- - [Block Duplicate Request per Window](#-custom-endpoint-specific-duplicate-request)
45
- - [JWT Broken Role](#jwt-broken-role)
46
- - [Advance Guard (Timimg)](#-beech-advanced-guard-timing)
47
- - 🙂 <b>Hight Security under passport-jwt, oauth2</b>
48
- - 🌐 <b>Supported Official Strategy</b>
49
- - [Google](#-google-strategy)
50
- - [Facebook](#-facebook-strategy)
51
- - 🖥️ <b>CORS Origin & Server Configuration</b>
52
- - [Config Base public path `./`](#cors-origin--server-configuration)
53
- - [Allow origin whitelist](#cors-origin--server-configuration)
54
- - 📚 <b>Databases Managements</b>
55
- - [Migrations](#databases-managements)
56
- - [Seeder](#-creating-first-seeder)
57
- - ☕ <b>Testing</b>
58
- - [Jest](#testing)
59
- - 🏃 <b>Implementration</b>
60
- - [Docker](#implementation)
61
- - [PM2](#-implement-with-pm2)
62
-
63
- # Environment
64
-
65
- - [`Node.js`](https://nodejs.org) >= 18.17.1+ (recommended)
66
-
67
- # Installation
68
-
69
- Beech API needed Node.js version 18.17.1 or above. You can management multiple versions on the same machine with [nvm](https://github.com/creationix/nvm) or [nvm-windows](https://github.com/coreybutler/nvm-windows).
70
-
71
- <b>So, Let's go to install</b> `beech-api`
72
-
73
- ```sh
74
- # NPM
75
- $ npm install beech-api --global
76
-
77
- # Yarn
78
- $ yarn global add beech-api
79
- ```
80
-
81
- Installation demo:
82
-
83
- [Demo 1](https://i.ibb.co/TBjNgVrF/1-11.gif)
84
- ![Alt Text](https://i.ibb.co/TBjNgVrF/1-11.gif)
85
-
86
- [Demo 2](https://i.ibb.co/wrdgyzDP/ezgif-8539024298ec62a9.gif)
87
- ![Alt Text](https://i.ibb.co/wrdgyzDP/ezgif-8539024298ec62a9.gif)
88
-
89
- After installation, you will have access to the `beech-app` binary in your command line.
90
- You can check you have the right version with this command:
91
-
92
- ```sh
93
- $ beech-app --version
94
- ```
95
-
96
- # Creating a project
97
-
98
- Create a new project run:
99
-
100
- ```sh
101
- $ beech-app create hello-world
102
- ```
103
- Run your project:
104
- ```sh
105
- $ cd hello-world
106
-
107
- $ npm start
108
- # OR
109
- $ yarn start
110
- ```
111
-
112
- ❓ **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.
113
-
114
-
115
- # Upgrade to latest version
116
- The Beech API upgrade to latest version command avariable :
117
-
118
- ```sh
119
- // Project upgrade
120
- $ beech-app update
121
-
122
- // Global upgrade
123
- $ beech-app update -g, --global
124
- ```
125
-
126
- # Beech CLI tool available
127
- After installation, you will have access to the `beech` binary in your command line.
128
- The `beech` command has a number of options and you can explore them all by running:
129
-
130
- ```sh
131
- $ beech --help
132
- ```
133
-
134
- The `beech` command line available:
135
-
136
- ```
137
- Usage:
138
- $ beech [options] [arguments] [special]
139
-
140
- Options:
141
- ?, -h, --help Display this help message.
142
- -v, --version Display the application version.
143
-
144
- The following commands are available:
145
-
146
- $ beech make <endpoint> Create a new Endpoints and unit test file,
147
- You might using [special] `-R, --require`
148
- for choose Model(s) used to endpoint file.
149
- $ beech make <model> -M, --model Create a new Models file.
150
- $ beech make <helper> --helper Create a new Helpers file.
151
- $ beech passport init Initialize authentication with passport-jwt.
152
- $ beech skd init Initialize Job Scheduler file.
153
- $ beech key:generate, key:gen Re-Generate application key (Dangerous!).
154
- $ beech hash:<text> Hash text for Access to Database connection.
155
- ```
156
- **Note:** Every to create new project will be generated new ``app_key`` in ``app.config.js`` file.
157
-
158
- **Note:** If you can re-generate. Can use command ``$ beech key:generate`` or ``$ beech key:gen``
159
-
160
- # Database connection
161
-
162
- You might connection to Database with `database_config` object in `app.config.js` file. Anything can support to multiple Database connections.
163
-
164
- The connection base on `pool_base` in `global.config.js` file.
165
-
166
- - `basic` = Support only Raw Query with Only MySQL.
167
- - `sequelize` = Support PDO, Raw Query with various Database Engine.
168
-
169
- In case Access to Database must to Hash the `username` and `password` with Beech CLI like this.
170
-
171
- ```sh
172
- // Hash database username
173
- $ beech hash:root
174
- Output: m42BVxQ6Q4kLdRX7xS_Hm7WbQiNqShJDvw9SLCgI431oafWBtQJoJDnoCL
175
-
176
- // Hash database password
177
- $ beech hash:password
178
- Output: FjgcgJPylkV7EeQJjea_EeifPwaHVO9onD3ATk3YYAyvjtMGu3dcDS0ejA
179
-
180
- ```
181
- ***For Example :***
182
-
183
- 📂 app.config.js
184
- ```js
185
- // Database configuration Only Basic & Sequelize (needed Hash)
186
-
187
- ...
188
-
189
- database_config: [
190
- {
191
- dialect: "mysql",
192
- name: "mysql_my_store_db",
193
- host: "localhost",
194
- username: "m42BVxQ6Q4kLdRX7xS_Hm7WbQiNqShJDvw9SLCgI431oafWBtQJoJDnoCL",
195
- password: "FjgcgJPylkV7EeQJjea_EeifPwaHVO9onD3ATk3YYAyvjtMGu3dcDS0ejA",
196
- database: "my_store_db",
197
- port: "3306",
198
-
199
- // Specify global options, which are used when Define is called.
200
- define: {
201
- charset: "utf8",
202
- freezeTableName: true,
203
- ...
204
- },
205
-
206
- timezone: "+07:00", // Example: GMT+2
207
- // or use a named timezone supported by Intl.Locale
208
- // timezone: 'America/Los_Angeles',
209
-
210
- logging: console.log, // SQL trace logs. Learn more: https://sequelize.org/docs/v6/getting-started/#logging
211
-
212
- is_connect: true, // Boolean, Turn ON/OFF to connect
213
- },
214
-
215
- ...
216
-
217
- ],
218
-
219
- ...
220
- ```
221
- **Caution! :** Every re-new generate `app_key`. Must to new Hash your Access and change to ALL Database connections.
222
-
223
- ❓ **Development** : You can add ```dev: true``` in ```main_config``` for a better experience.
224
-
225
- # Models
226
-
227
- 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.
228
-
229
- ```sh
230
- $ beech make modelName --model
231
- ```
232
-
233
- ## # Model (Basic)
234
-
235
- Basic model only support `MySQL` Raw Query format and freedom of your SQL query
236
-
237
- ❓ **Note:** The Basic pool engine it's not support auto Endpoints.
238
-
239
-
240
- ***For example :***
241
-
242
- 📂 models/Fruit.js
243
- ```js
244
- module.exports = {
245
-
246
- // Example basic function get data
247
- getData() {
248
-
249
- return {
250
- id: 1,
251
- name: "John Doe",
252
- }
253
-
254
- },
255
-
256
- // Example basic function get data from MySQL table
257
- getFruit() {
258
-
259
- // calling Pool connection name by `mysql.default_db`
260
- mysql.default_db.query("SELECT * FROM fruit", (err, results) => {
261
-
262
- if (err) { throw err }
263
- return results;
264
-
265
- });
266
-
267
- }
268
-
269
- };
270
- ```
271
-
272
- ## # Model (Sequelize)
273
-
274
- Sequelize is a promise-based Node.js ORM tool for Postgres, MySQL, MariaDB, SQLite, Microsoft SQL Server, Oracle Database, Amazon Redshift and Snowflake’s Data Cloud. It features solid transaction support, relations, eager and lazy loading, read replication and more. <br/>You can learn more: [Sequelize docs](https://sequelize.org/docs/v6)
275
-
276
- You can asign more DataTypes, Learn more : [Sequelize docs](https://sequelize.org/docs/v6/core-concepts/model-basics/#data-types)
277
-
278
- ❓ **Note:** When you generate a model it's create table structure for automatically for you.
279
-
280
- ***For example :***
281
-
282
- 📂 models/Fruit.js
283
- ```js
284
- const { Schema } = require("beech-api");
285
-
286
- // Define table Schema with `Schema(sql.default_db)` connection name
287
- const Fruit = Schema(sql.default_db).define("fruit", {
288
- fruit_id: {
289
- field: "id", // Rename PK field to fruit_id Ref: `id` field in fruit table
290
- type: DataTypes.INTEGER,
291
- autoIncrement: true,
292
- primaryKey: true
293
- },
294
- friut_uuid: {
295
- field: "uuid",
296
- type: DataTypes.STRING(100),
297
- allowNull: true,
298
- defaultValue: DataTypes.UUIDV4,
299
- },
300
- fruitName: DataTypes.STRING,
301
- fruitQty: DataTypes.INTEGER,
302
- fruitPrice: {
303
- type: DataTypes.INTEGER,
304
- allowNull: false, // Allow null feilds
305
- },
306
- sort: DataTypes.STRING,
307
- createdAt: {
308
- type: DataTypes.DATE,
309
- allowNull: false,
310
- defaultValue: DataTypes.NOW,
311
- },
312
- updatedAt: {
313
- type: DataTypes.DATE,
314
- allowNull: true,
315
- },
316
- }, {
317
- // Enables timestamps with createdAt and updatedAt
318
- timestamps: true,
319
- // Custom field names createdAt and updatedAt
320
- createdAt: "createdAt",
321
- updatedAt: "updatedAt",
322
- });
323
-
324
- Fruit.options = {
325
- // Choose one for Allow magic generate default Endpoint (CRUD), It's like magic creating The endpoints for you (CRUD) ✨
326
-
327
- // Option 1: Allow all methods
328
- defaultEndpoint: true,
329
-
330
- // Option 2: Allow with specific per methods
331
- defaultEndpoint: {
332
- GET: true,
333
- POST: {
334
- allow: true, // allow Auto-Endpoint
335
- jwt: {
336
- allow: true, // allow JWT
337
- broken_role: [
338
- { role: [1, 2] },
339
- ],
340
- },
341
- // Rate Limit for POST
342
- rate_limit: {
343
- windowMs: 15 * 60 * 1000, // 15 minutes
344
- limit: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes).
345
- // store: ... , // Redis, Memcached, etc.
346
- // See more: https://www.npmjs.com/package/express-rate-limit#Configuration
347
- },
348
- // Duplicate Request for POST
349
- duplicate_request: {
350
- expiration: 500, // Can't duplicate request for 5 milliseconds each IP requests per `window` (Disabled for Set expiration to 0 zero.)
351
- },
352
- },
353
- PATCH: false,
354
- DELETE: false,
355
- },
356
-
357
- limitRows: 100, // Limit rows default 100
358
- };
359
-
360
- // Example Finder by id (ORM), Learn more: https://sequelize.org/docs/v6/core-concepts/model-querying-finders/
361
- function exampleFindOneFruitById(id) {
362
- return Fruit.findOne({ where: { id: id } });
363
- }
364
-
365
- // Example Raw Query with Model Instances. This allows you to easily map a query to a predefined model
366
- function exampleGetAllFruitWithModelInstance(id) {
367
- return Fruit.query("SELECT * FROM fruit", {
368
- model: Fruit, // When JOIN table needed register that table [Fruit, ...]
369
- mapToModel: true // pass true here if you have any mapped fields
370
- });
371
- }
372
-
373
- // Example Raw Query, Learn more: https://sequelize.org/docs/v6/core-concepts/raw-queries/
374
- function exampleGetAllFruit(id) {
375
- return Fruit.query("SELECT * FROM fruit");
376
- }
377
-
378
- ...
379
-
380
- // Export Schema, Function, ...
381
- module.exports = {
382
- Fruit,
383
- exampleFindOneFruitById,
384
- exampleGetAllFruitWithModelInstance,
385
- exampleGetAllFruit,
386
- ...
387
- };
388
- ```
389
-
390
- ## Retrieving data with Query String
391
-
392
- Now you can add Query String with Conditional, Grouping and Ordering (Now Support Readonly for GET method)
393
-
394
- ### ✨ That's cool! It's like magic Creating The Endpoints for you (CRUD) ✨
395
-
396
- <b style="font-size:12pt">For Example, Now!</b>, You can request to `/fruit` with methods GET, POST, PATCH and DELETE like this.
397
-
398
- | Efficacy | Method | Endpoint | Body | Mode |
399
- |:---------|:---------|:-----------------------|:-------------|:--------|
400
- | Create | POST | /fruit | { } | Single |
401
- | Create | POST | /fruit | [ ] | Bulk |
402
- | Read | GET | /fruit | No | Fetch |
403
- | Read | GET | /fruit/:limit/:offset | No | Fetch |
404
- | Read | GET | /fruit?someField=1 | No | Fetch |
405
- | Read | GET | /fruit?orderby=sort | No | Fetch |
406
- | Read | GET | /fruit?groupby=id | No | Fetch |
407
- | Update | PATCH | /fruit/:id | { } | Single |
408
- | Delete | DELETE | /fruit/:id | No | Single |
409
-
410
- Add some Basic Conditions, Grouping and Ordering with `QUERY STRING` under GET methods<br/>
411
-
412
- Retrieving `fruit` data with GET : `/fruit?someField=[eq,1]&groupby=[id]&orderby=[id,desc]`
413
-
414
- ***For Example :***
415
-
416
- ```java
417
- // WHERE Conditions
418
- GET: /fruit?id=1 // id = 1
419
- GET: /fruit?isActived=[eq,1] // isActived = 1
420
- GET: /fruit?fruitName=[like,Banana%] // fruitName LIKE 'Banana%' (Not allow with date, time)
421
- GET: /fruit?cost=[gt,50]&qty=[lt,10] // cost > 50 AND qty < 10
422
- GET: /fruit/10/0?qty=[lt,10] // qty < 10 LIMIT 0,10
423
-
424
- // Grouping
425
- GET: /fruit?groupby=id // GROUP BY id
426
- GET: /fruit?groupby=[id,fruitName] // GROUP BY id, fruitName
427
-
428
- // Ordering
429
- GET: /fruit?oderby=id // ORDER BY id ASC
430
- GET: /fruit?oderby=[sort,desc] // ORDER BY sort DESC
431
- ```
432
-
433
- For usage avariable:
434
-
435
- ```java
436
- // Basics conditions
437
- 3 // = 3
438
- [eq, 3] // = 3
439
- [ne, 20] // != 20
440
- [is, null] // IS NULL
441
- [not, null] // IS NOT NULL
442
- [or, [5, 6]] // (someField = 5) OR (someField = 6) // Not support NULL value
443
-
444
- // Number comparisons conditions
445
- [gt, 6] // > 6
446
- [gte, 6] // >= 6
447
- [lt, 10] // < 10
448
- [lte, 10] // <= 10
449
- [between, [6, 10]] // BETWEEN 6 AND 10
450
- [between, [2025-01-01, 2025-04-30]] // BETWEEN '2025-01-01 00:00:00' AND '2025-04-30 23:59:59'
451
- // When assign Datetime format will only support field datatype is `Date`, `Datetime`, `Time`
452
-
453
- // OR You can assign Datetime like this.
454
- [between, [2025-01-01 12:00:00, 2025-04-30 15:00:00]] // BETWEEN '2025-01-01 12:00:00' AND '2025-04-30 15:00:00'
455
-
456
- [notBetween, [11, 15]] // NOT BETWEEN 11 AND 15
457
-
458
- // Other operators conditions
459
- [in, [1, 2, 3]], // IN [1, 2, 3]
460
- [notIn, [1, 2, 3]], // NOT IN [1, 2, 3]
461
- [like, %hat] // LIKE '%hat' (Avoid use #, % and %<Number> between wording)
462
- // Becuase URL will be decoded it, Reccommand use startsWith, endsWith and substring when you need assing Number value)
463
- // And NOT SUPPORT field datatype is `date`, `datetime`, `time`. Should be use with datatype is `String` or `Number` it work!.
464
-
465
- [notLike, %hat] // NOT LIKE '%hat'
466
- [startsWith, hat] // LIKE 'hat%'
467
- [endsWith, hat] // LIKE '%hat'
468
- [substring, hat] // LIKE '%hat%'
469
-
470
- // Grouping
471
- groupby=id // GROUP BY id
472
- groupby=[id] // ORDER BY id
473
- groupby=[id, fruitName] // ORDER BY id, fruitName
474
-
475
- // Ordering
476
- oderby=id // ORDER BY id ASC (Basic usage default Ascending)
477
- oderby=[id, asc] // ORDER BY id ASC
478
- oderby=[id, desc] // ORDER BY id ASC
479
- oderby=[[id, desc], [sort, asc]] // ORDER BY id DESC, sort ASC
480
- ```
481
-
482
- ## # Transactions
483
-
484
- Sequelize does not use transactions by default. However, for production-ready usage of Sequelize, you should definitely configure Sequelize to use transactions.
485
-
486
- Beech use Sequelize supports three ways of using transactions:
487
-
488
- - ### Way 1 - Disorganized transactions :
489
- ```js
490
- // First, we start a transaction from your connection and save it into a variable
491
- const t = await Fruit.transaction();
492
-
493
- try {
494
-
495
- // Then, we do some calls passing this transaction as an option:
496
- const fruit = await Fruit.create({ fruitName: 'Banana', fruitQty: '5', }, { transaction: t });
497
- await fruit.addSibling({ fruitName: 'Litle', fruitQty: '2', }, { transaction: t }); // Error function
498
-
499
- // If the execution reaches this line, no errors were thrown.
500
- // We commit the transaction.
501
- await t.commit();
502
-
503
- } catch (error) {
504
-
505
- // If the execution reaches this line, an error was thrown.
506
- // We rollback the transaction.
507
- await t.rollback();
508
-
509
- }
510
- ```
511
-
512
- - ### Way 2 - Organized transactions :
513
- ```js
514
- // First, we start a transaction from your connection and save it into a variable
515
- Fruit.transaction(async t => {
516
- try {
517
-
518
- // Then, we do some calls passing this transaction as an option:
519
- const fruit = await Fruit.create({ fruitName: 'Banana', fruitQty: '5', }, { transaction: t });
520
- await fruit.addSibling({ fruitName: 'Litle', fruitQty: '2', }, { transaction: t }); // Error function
521
-
522
- // If the execution reaches this line, no errors were thrown.
523
- // We commit the transaction.
524
- await t.commit();
525
-
526
- } catch (error) {
527
-
528
- // If the execution reaches this line, an error was thrown.
529
- // We rollback the transaction.
530
- await t.rollback();
531
-
532
- }
533
- });
534
- ```
535
-
536
- - ### Way 3 - Transactions set Isolation levels :
537
-
538
- The possible [isolations levels](https://sequelize.org/docs/v6/other-topics/transactions/#isolation-levels) to use when starting a transaction:
539
-
540
- ```js
541
- const { Transaction } = require('sequelize');
542
-
543
- // First, we start a transaction from your connection and save it into a variable
544
- Fruit.transaction(
545
- {
546
- isolationLevel: Transaction.ISOLATION_LEVELS.SERIALIZABLE,
547
- },
548
- async t => {
549
- try {
550
-
551
- // Then, we do some calls passing this transaction as an option:
552
- const fruit = await Fruit.create({ fruitName: 'Banana', fruitQty: '5', }, { transaction: t });
553
- await fruit.addSibling({ fruitName: 'Litle', fruitQty: '2', }, { transaction: t }); // Error function
554
-
555
- // If the execution reaches this line, no errors were thrown.
556
- // We commit the transaction.
557
- await t.commit();
558
-
559
- } catch (error) {
560
-
561
- // If the execution reaches this line, an error was thrown.
562
- // We rollback the transaction.
563
- await t.rollback();
564
-
565
- }
566
- });
567
- ```
568
-
569
- # Endpoints
570
-
571
- The `endpoints` keep the endpoints basic request files currently support `GET`, `POST`, `PUT`, `PATCH` and `DELETE`.
572
-
573
- So, you might create new endpoints with constant `endpoint` object variable in `src/endpoints/` folder and file neme must be end with `-endpoints.js`
574
-
575
- ```sh
576
- $ beech make endpointName
577
- ```
578
- You might using [special] `-R, --require` for choose Model(s) used for that endpoint.
579
-
580
- ***For Example :***
581
-
582
- 📂 endpoints/fruit-endpoints.js
583
- ```js
584
- // Require Model schema, Function & Others
585
- const { Fruit } = require("@/models/Fruit");
586
-
587
- exports.init = () => {
588
-
589
- // GET method
590
- endpoint.get("/fruit", Credentials, async (req, res) => {
591
- // example call Fruit model for get data
592
- res.json({
593
- code: 200,
594
- status: "SUCCESS",
595
- results: await Fruit.findAll();
596
- });
597
- });
598
-
599
-
600
- // POST method
601
- endpoint.post("/fruit", Credentials, (req, res) => {
602
- // @response
603
- res.json({
604
- code: 200,
605
- status: "SUCCESS",
606
- message: "POST request at /fruit",
607
- result: {
608
- id: req.body.id,
609
- name: req.body.name,
610
- },
611
- });
612
- });
613
-
614
-
615
- // PUT method
616
- endpoint.put("/fruit/:id", Credentials, (req, res) => {
617
- // @response
618
- res.json({
619
- code: 200,
620
- status: "SUCCESS",
621
- message: "PUT request at /fruit/" + req.params.id,
622
- });
623
- });
624
-
625
-
626
- // DELETE method
627
- endpoint.delete("/fruit/:id", Credentials, (req, res) => {
628
- // @response
629
- res.json({
630
- code: 200,
631
- status: "SUCCESS",
632
- message: "DELETE request at /fruit/" + req.params.id,
633
- });
634
- });
635
-
636
- ...
637
-
638
- }
639
- ```
640
-
641
- # JWT Broken Role
642
-
643
- The **JWT Broken Role** mechanism provides a flexible way to bypass or override role-based authorization rules when using JWT.
644
-
645
- #### It can be applied in three different levels, depending on your use case.
646
-
647
- | Priority | Level | Scope | Best For |
648
- |:---------|:--------------------------------|:-------------------------|:--------------------------------|
649
- | 3rd | Global (``passport.config.js``) | All endpoints | Common authorization exceptions |
650
- | 2nd | Model-level options | Per model & HTTP method | Structured, reusable rules |
651
- | 1st | Endpoint middleware | Single endpoint | Custom or special cases |
652
-
653
- This multi-layer approach allows you to design **secure, flexible, and maintainable JWT authorization flows**.
654
-
655
- ### 1. Global Configuration (passport.config.js) - Priority 3
656
-
657
- You can define global JWT Broken Role rules that apply to all endpoints by configuring them in ``passport.config.js``.
658
- ```js
659
- module.exports = {
660
- // Enable JWT authentication
661
- jwt_allow: true,
662
-
663
- ...
664
-
665
- // Global JWT broken role configuration
666
- jwt_broken_role: [
667
- {
668
- role: [0, 2, 4],
669
- email: "john.doe@company.com",
670
- }, // Basic role matching
671
-
672
- {
673
- role: { $in: [0, 2, 4] },
674
- email: { $regex: /@company\.com$/ },
675
- }, // Advanced matching using operators
676
- ],
677
-
678
- ...
679
- };
680
- ```
681
-
682
- **Use cases**
683
-
684
- - Apply common authorization exceptions across the entire application
685
- - Support both simple role arrays and advanced operators (``$in``, ``$regex``, etc.)
686
-
687
- ### 2. Model-Level Configuration (Per HTTP Method) - Priority 2
688
-
689
- You can configure JWT and Broken Role rules per model and per HTTP method using model options.
690
-
691
- 📂 src/models/Fruit.js
692
- ```js
693
- Fruit.options = {
694
- ...
695
-
696
- // Auto-endpoint configuration by HTTP method
697
- defaultEndpoint: {
698
- GET: true, // Enable auto-generated GET endpoint
699
-
700
- POST: {
701
- allow: true,
702
- jwt: {
703
- allow: true,
704
- broken_role: [
705
- { role: [5, 6] },
706
- ],
707
- },
708
- },
709
-
710
- PATCH: {
711
- allow: true,
712
- jwt: {
713
- allow: true,
714
- broken_role: [
715
- { role: [5, 6, 9] },
716
- { department: "IT" },
717
- ],
718
- },
719
- },
720
-
721
- DELETE: false, // Disable auto-generated DELETE endpoint
722
- },
723
-
724
- ...
725
- };
726
- ```
727
-
728
- **Use cases**
729
-
730
- - Fine-grained access control per HTTP method
731
- - Different role requirements for POST, PATCH, etc.
732
- - Combine role-based and attribute-based conditions
733
-
734
- ### 3. Endpoint-Level Configuration (Credentials Middleware) - Priority 1
735
-
736
- For maximum flexibility, you can define Broken Role rules directly on a specific endpoint using the Credentials middleware.
737
-
738
- 📂 endpoints/custom-fruit-endpoints.js
739
- ```js
740
- const { Fruit } = require("@/models/Fruit");
741
-
742
- endpoint.delete(
743
- "/destroy-fruit-by-id/:id",
744
- Credentials([{ role: [5, 9] }]),
745
- async (req, res) => {
746
-
747
- // Only JWT tokens with role level 5 or 9 are allowed
748
-
749
- const deleted = await Fruit.destroy({
750
- where: {
751
- id: req.params.id,
752
- },
753
- });
754
-
755
- console.log("result:", deleted);
756
-
757
- // @response
758
- }
759
- );
760
- ```
761
-
762
- **Use cases**
763
-
764
- - One-off or custom endpoints
765
- - Highly specific authorization rules
766
- - Override global or model-level behavior when necessary
767
-
768
- ## Supported Basic & Operators Usage
769
-
770
- The JWT Broken Role system supports both basic value matching and advanced operators for flexible authorization rules.
771
-
772
- | Operator | Meaning | Description |
773
- |:---------|:-------------------|:--------------------------------------------------------------|
774
- | $eq | equal | Matches when the value is equal |
775
- | $ne | not equal | Matches when the value is not equal |
776
- | $in | value IN array | Matches when the value exists in the specified array |
777
- | $not | value NOT IN array | Matches when the value does not exist in the specified array |
778
- | $regex | regex match | Matches using a regular expression |
779
- | $fn | custom function | Matches using a custom evaluation function |
780
-
781
- ## Evaluation Logic (Very Important !)
782
- ```js
783
- [
784
- { rule1 AND rule1 },
785
- { rule2 AND rule2 }
786
- ]
787
-
788
- OR
789
- ```
790
-
791
- ## Basic Usage for Examples :
792
-
793
- ```js
794
- Credentials([
795
- { role: [9] }, // Only role check
796
- { email: 'a@b.com' }, // OR email
797
- ])
798
-
799
- // Common Matching Patterns
800
- { role: [1, 2, 3] } // IN
801
- { role: 1 } // Equal
802
- { email: 'a@b.com' } // Equal
803
- { department: 'IT' } // Equal
804
- { status: ['active'] } // Dynamic key
805
- ```
806
-
807
- ## Operators Usage for Examples :
808
-
809
- ```js
810
- // Equal with Role
811
- Credentials([
812
- {
813
- role: { $eq: [1, 2, 5] }
814
- }
815
- ])
816
-
817
- // Not Equal with Role
818
- Credentials([
819
- {
820
- role: { $ne: [0, 3] }
821
- }
822
- ])
823
-
824
- // Regex with Email domain
825
- Credentials([
826
- {
827
- email: { $regex: /@company\.com$/ }
828
- }
829
- ])
830
-
831
- // IN with Role
832
- Credentials([
833
- {
834
- role: { $in: [1, 2, 4] }
835
- }
836
- ])
837
-
838
- // NOT IN with Role
839
- Credentials([
840
- {
841
- role: { $not: [0, 3] }
842
- }
843
- ])
844
-
845
- // Multiple OR rules
846
- Credentials([
847
- {
848
- role: { $in: [1] },
849
- email: 'john.doe@company.com'
850
- },
851
- // OR
852
- {
853
- role: { $in: [4] },
854
- email: { $regex: /@company\.com$/ }
855
- },
856
- ])
857
-
858
- // Custom Function
859
- Credentials([
860
- {
861
- role: {
862
- $fn: (value, user) => value >= 4 && user.department === 'IT'
863
- }
864
- }
865
- ])
866
- ```
867
-
868
- # Helpers
869
-
870
- 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.
871
-
872
- ```sh
873
- $ beech make helperName --helper
874
- ```
875
-
876
- ***For Example :***
877
-
878
- 📂 helpers/TextEditor.js
879
- ```js
880
- module.exports = {
881
-
882
- textUpperCase(text) {
883
- return text.toUpperCase();
884
- },
885
-
886
- textTrim(text) {
887
- return text.trim();
888
- },
889
-
890
- ...
891
-
892
- };
893
- ```
894
-
895
- # Authentication (passport-jwt)
896
-
897
- 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.
898
-
899
- ### Passport-jwt Initialization
900
-
901
- ```sh
902
- $ beech passport init
903
- ```
904
-
905
- After passport initialized the `passport.config.js` it's appeared
906
-
907
- 📂 passport.config.js
908
- ```js
909
- module.exports = {
910
- // Allow for using passport-jwt
911
- jwt_allow: true,
912
-
913
- // custom authenticaiton endpoint name, default `/authentication`
914
- auth_endpoint: "",
915
-
916
- // your jwt secret key
917
- secret: "your_jwt_secret",
918
-
919
- // token expiry time (seconds), default 86400 sec. it's expired in 24 hr.
920
- token_expired: 86400,
921
-
922
- // Allow for using global jwt broken role
923
- jwt_broken_role: [
924
- // { role: [1, 2, 9] },
925
- ],
926
-
927
- model: {
928
- // Main sql connection name. You must make sure connection name like inside `app.config.js` file and choose one connection name.
929
- name: "default_db",
930
-
931
- // table name of users store, default table `users`
932
- table: "",
933
-
934
- // secret user store field for authenticate, default field `username` and `password`
935
- username_field: "",
936
- password_field: "",
937
-
938
- // JWT playload data, You can add it. Example: ["name", "email", ...]
939
- fields: [],
940
-
941
- // Other fields add for authentication.
942
- guard: {
943
- // Basic guard field, Example: ["pin", "hint", "2fa"]
944
- guard_field: [],
945
-
946
- // Advanced guard jwt request (needed some logical from front-end)
947
- advanced_guard: {
948
- allow: false,
949
- entity: "", // default entity `timing`
950
- secret: "top_secret",
951
- time_expired: {
952
- minutes: 1, // should length [0-60]
953
- seconds: 0, // should length [0-60]
954
- },
955
- },
956
- },
957
- },
958
-
959
- // Allow for using request with app_key entity (Every request must be using the app_key entity in headers)
960
- app_key_allow: false
961
-
962
- ...
963
-
964
- };
965
- ```
966
- ### Request Token
967
- **Authentication structure :** Simple ``users`` table:
968
- ```
969
- ==============================================================
970
- | id | username | password | name | email |
971
- --------------------------------------------------------------
972
- | 1 | bombkiml | secret | bombkiml NC. | bomb@bomb.com |
973
- | 2 | johnson | secret | johnson BA. | john@bomb.com |
974
- ```
975
-
976
- When you config passport with ```users``` table already. You will got Auth endpoint in available.
977
- ```js
978
- POST: "/authentication" // Request token
979
- POST: "/authentication/refresh" // Request refresh token
980
- POST: "/authentication/create" // Create new Auth data
981
- PATCH: "/authentication/update/:id" // Update old Auth data (needed user id)
982
- ```
983
-
984
- ***XHR Example :***
985
-
986
- ```js
987
- // Request with body for gether Token
988
- POST: "/authentication"
989
- payload: {
990
- username: "bombkiml",
991
- password: "secret"
992
- }
993
-
994
- // Request with header for refresh token
995
- POST: "/authentication/refresh"
996
- headers: Authorization: Bearer <your_token>
997
-
998
- // Request with body for Create Auth data
999
- POST: "/authentication/create"
1000
- payload: {
1001
- username: "add_new_username",
1002
- password: "add_new_secret",
1003
- name: "add_new_my_name",
1004
- email: "add_new_email"
1005
- }
1006
-
1007
- // Request with body for Update Auth data
1008
- PATCH: "/authentication/update/1"
1009
- headers: Authorization: Bearer <your_token>
1010
- payload: {
1011
- username: "update_bombkiml",
1012
- password: "update_secret",
1013
- name: "update_my_name",
1014
- email: "my_update_email@bomb.com"
1015
- }
1016
- ```
1017
-
1018
- # Beech Guard
1019
- 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.
1020
-
1021
- ## # Guard (2FA, Other)
1022
-
1023
- 📂 passport.config.js
1024
- ```js
1025
- module.exports = {
1026
- ...
1027
-
1028
- guard: {
1029
- // Other fields add for authenticate, exmaple ["pin", "hint", "2fa"]
1030
- guard_field: ["2fa"], 👈 // your feild guard. (Disabled to remove it.)
1031
-
1032
- ...
1033
- },
1034
-
1035
- ...
1036
-
1037
- }
1038
- ```
1039
-
1040
- ## # Beech Advanced Guard (Timing)
1041
- 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.
1042
-
1043
- 📂 passport.config.js
1044
- ```js
1045
- module.exports = {
1046
- ...
1047
-
1048
- guard: {
1049
- ...
1050
-
1051
- // Advanced guard to Request (Needed some logical from front-end)
1052
- advanced_guard: {
1053
- allow: false, 👈 // advanced guard allow for All Endpoint.
1054
- entity: "", // default entity `timing`
1055
- secret: "your_advance_guard_secret",
1056
- time_expired: {
1057
- minutes: 1, // should length [0-60]
1058
- seconds: 0, // should length [0-60]
1059
- },
1060
- },
1061
- },
1062
-
1063
- ...
1064
-
1065
- }
1066
-
1067
- ```
1068
-
1069
- <b>After configure</b>, You must add some logic in your front-end like this.
1070
-
1071
- Before add logic, We needed [```beech-auth0```](https://github.com/bombkiml/beech-auth0) and [```moment.js```](https://momentjs.com) for apply in Policy.
1072
-
1073
- ```sh
1074
- # NPM
1075
- $ npm install --save beech-auth0 moment
1076
-
1077
- # Yarn
1078
- $ yarn add beech-auth0 moment
1079
- ```
1080
- Now! you can add some logic like this.
1081
-
1082
- - Import packages
1083
-
1084
- ```js
1085
- // CommonJS
1086
- const { Auth0 } = require("beech-auth0");
1087
- const moment = require("moment");
1088
-
1089
- // ES6
1090
- import { Auth0 } from "beech-auth0";
1091
- import moment from "moment";
1092
- ```
1093
-
1094
- - Get unix time with momentJS
1095
-
1096
- ```js
1097
- // Get UNIX TIME with moment
1098
- let unix_time = moment().unix();
1099
- ```
1100
-
1101
- - Get hashing with Beech Auth0
1102
-
1103
- ```js
1104
- // Auth0 Policy.
1105
- Auth0(unix_time, 'your_advance_guard_secret', (error, hashing) => {
1106
-
1107
- // Your XHR request for All Endpoint.
1108
- POST: "/authentication"
1109
- headers: { timing: hashing } 👈 // Assign advance guard entity to headers with callback hashing.
1110
-
1111
- });
1112
-
1113
- ```
1114
-
1115
- ## # Beech User Authentication Managements ###
1116
- You can easy management `users` data with Beech, Only ```Store, Update``` NO ```Delete```, Anything you can make DELETE endpoint by yourself
1117
-
1118
- ```js
1119
- const { Store, Update } = require("beech-api");
1120
- ```
1121
-
1122
- - ***Store*** users data with ``Store()``
1123
- ```js
1124
- // prepare data for store users
1125
- var data = {
1126
- username: "bombkiml",
1127
- password: "secret",
1128
- name: "bombkiml nc.",
1129
- email: "bomb@bomb.com"
1130
- }
1131
-
1132
- Store(data, (err, stored) => {
1133
- if (err) throw err;
1134
-
1135
- // response affected data
1136
- console.log(stored.insertId, stored.affectedRows);
1137
-
1138
- });
1139
- ```
1140
-
1141
- - ***Update*** users data with ``Update()``
1142
- ```js
1143
- // prepare data for update users
1144
- var data = {
1145
- password: "new_secret",
1146
- name: "bombkiml NC.",
1147
- email: "bombkiml@bomb.com"
1148
- }
1149
-
1150
- Update(data, id, (err, updated) => {
1151
- if (err) throw err;
1152
-
1153
- // response affected data
1154
- console.log(updated.updateId, updated.affectedRows);
1155
-
1156
- });
1157
- ```
1158
-
1159
- # Beech with Official Strategy
1160
-
1161
- Latest supported with ``Google`` and ``Facebook`` Strategy.
1162
-
1163
-
1164
- ## # Google Strategy
1165
-
1166
-
1167
- 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.
1168
-
1169
- Before your application can make use of Sign In With Google, you must register your app with Google. This can be done in the [APIs & Services](https://console.cloud.google.com/apis) page of the [Google Cloud Platform console.](https://console.cloud.google.com/) Once registered, your app will be issued a client ID and secret which will be used in the strategy configuration.
1170
-
1171
- Go to open file ``passport.config.js`` and go to ``google strategy`` then turn allow Google Strategy is ``allow: true`` something like this.
1172
-
1173
- 📂 passport.config.js
1174
- ```js
1175
- ...
1176
-
1177
- strategy: {
1178
-
1179
- google: {
1180
-
1181
- // Allow for using google strategy
1182
- allow: true,
1183
-
1184
- // Authen profile store fields available: `google_id`, `name`, `email`, `photos`, `locate`
1185
- local_profile_fields: {
1186
- google_id: "google_id", // Google ID field, default field name: `google_id`
1187
- name: "your_name_field",
1188
- email: "your_email_field",
1189
- photos: "your_profile_url_field",
1190
- locate: "" // If you not store set to null or remove it.
1191
- },
1192
- // Google development Credentials OAuth 2.0 Client IDs
1193
- client_id: "GOOGLE_CLIENT_ID",
1194
- client_secret: "GOOGLE_CLIENT_SECRET",
1195
- // Callback endpoint default `/google/callback`
1196
- callbackURL: "",
1197
- // Failure redirect to your route
1198
- failureRedirect: "/login"
1199
- }
1200
- }
1201
-
1202
- ...
1203
- ```
1204
-
1205
- The above code is a configures and registers the Google Strategy.
1206
-
1207
- - ``allow`` : Turn on/off the Google Strategy config type of ``boolean`` switch by ``true/false``.
1208
- - ``google_id`` : Local Google ID field for store Google ID in my local database default field is ``google_id``.
1209
- - ``local_profile_fields`` : Local Profile fields for store Google user details.
1210
- - ``client_id`` and ``client_secret`` : The options to the Google Strategy constructor must include a ``clientID`` and ``clientSecret``, the values of which are set to the client ID and secret that were obtained when registering your application.
1211
- - ``callbackURL`` : When registering your application. A callbackURL must also be included. Google will redirect users to this location after they have authenticated.
1212
- - ``failureRedirect`` : When registering your application somthing failure it's redirect to that.
1213
-
1214
- Place a button on the application's login page, prompting the user to sign in with Google.
1215
-
1216
- ```html
1217
- <a href="/authentication/google" class="button">Sign in with Google</a>
1218
- ```
1219
-
1220
- **Note:** The URL "``/authentication``" will be follow by ``auth_endpoint`` when you custom it.
1221
-
1222
-
1223
- ## # Facebook Strategy
1224
-
1225
-
1226
- Facebook Login allows users to sign in using their Facebook account. Support for Faceboook Login is provided by the ``passport-facebook`` package.
1227
-
1228
- Before your application can make use of Facebook Login, you must register your app with Facebook. This can be done in the [App dashboard](https://developers.facebook.com/apps) at [Facebook for Developers.](https://developers.facebook.com/) Once registered, your app will be issued an app ID and secret which will be used in the strategy configuration.
1229
-
1230
- Go to open file ``passport.config.js`` and go to ``facebook strategy`` then turn allow Facebook Strategy is ``allow: true`` something like this.
1231
-
1232
- 📂 passport.config.js
1233
- ```js
1234
- ...
1235
-
1236
- strategy: {
1237
-
1238
- facebook: {
1239
-
1240
- // Allow for using facebook strategy
1241
- allow: true,
1242
-
1243
- // Authen profile store fields available: `facebook_id`, `name`, `email`, `photos`, `locate`
1244
- local_profile_fields: {
1245
- facebook_id: "facebook_id", // Facebook ID field, default field name: `facebook_id`
1246
- name: "your_name_field",
1247
- email: "your_email_field",
1248
- photos: "your_profile_url_field",
1249
- locate: "" // If you not store set to null or remove it.
1250
- },
1251
- // Facebook development Credentials OAuth 2.0
1252
- app_id: "FACEBOOK_APP_ID",
1253
- app_secret: "FACEBOOK_APP_SECRET",
1254
-
1255
- // You can allow Permissions facebook profile fields. Learn more (https://developers.facebook.com/docs/graph-api/reference/v13.0/user#readperms)
1256
- // **Update 2024, Now! Facebook requests permission for show Email. Learn more (https://developers.facebook.com/docs/permissions)
1257
- profileFieldsAllow: [ 'id', 'displayName', 'name', 'photos', 'email', 'location' ], // Default allowed
1258
-
1259
- // Callback endpoint default `/facebook/callback`
1260
- callbackURL: "",
1261
- // Failure redirect to your route
1262
- failureRedirect: "/login"
1263
- }
1264
- }
1265
-
1266
- ...
1267
- ```
1268
-
1269
- The above code is a configures and registers the Facebook Strategy.
1270
-
1271
- - ``allow`` : Turn on/off the Facebook Strategy config type of ``boolean`` switch by ``true/false``.
1272
- - ``facebook_id`` : Local Facebook ID field for store Facebook ID in my local database default field is ``facebook_id``.
1273
- - ``local_profile_fields`` : Local Profile fields for store Facebook user details.
1274
- - ``app_id`` and ``app_secret`` : The options to the Facebook Strategy must include an app ID and secret. you must register your app with Facebook. This can be done in the [App dashboard](https://developers.facebook.com/apps) at [Facebook for Developers.](https://developers.facebook.com/) Once registered, your app will be issued an ``app ID`` and ``secret`` which will be used in the strategy configuration.
1275
- - ``profileFieldsAllow`` : Permissions with Facebook Login. You must allow Permissions facebook profile fields: see more (https://developers.facebook.com/docs/graph-api/reference/v13.0/user#readperms)
1276
- - ``callbackURL`` : When registering your application. A callbackURL must also be included. Facebook will redirect users to this location after they have authenticated.
1277
- - ``failureRedirect`` : When registering your application somthing failure it's redirect to that.
1278
-
1279
- Place a button on the application's login page, prompting the user to sign in with Facebook.
1280
-
1281
- ```html
1282
- <a href="/authentication/facebook" class="button">Log In With Facebook</a>
1283
- ```
1284
-
1285
- **Note:** The URL "``/authentication``" will be follow by ``auth_endpoint`` when you custom it.
1286
-
1287
- # CORS Origin & Server Configuration
1288
- 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`
1289
-
1290
- 📂 beech.config.js
1291
- ```js
1292
- module.exports = {
1293
- defineConfig: {
1294
- // Base public path when served in development or production.
1295
- base: process.env.NODE_ENV === "production"
1296
- ? "/my-api/" // For Production
1297
- : "/", // For Development
1298
-
1299
- server: {
1300
- // Client request allow origin whitelist
1301
- origin: ["http://example.com", "http://my-webapp:8080", "https://cat.io"],
1302
- originSensitive: false, // Sensitive with contrasts wording
1303
-
1304
- // API Request rate limit (Disabled for Remove it.)
1305
- rateLimit: {
1306
- windowMs: 15 * 60 * 1000, // 15 minutes
1307
- limit: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes).
1308
- // store: ... , // Redis, Memcached, etc.
1309
- // See more: https://www.npmjs.com/package/express-rate-limit#Configuration
1310
- },
1311
-
1312
- // API Duplicate Request (Disabled for Set expiration to 0 zero.)
1313
- duplicateRequest: {
1314
- expiration: 500, // Can't duplicate request for 5 milliseconds each IP requests per `window`
1315
- },
1316
-
1317
- payload: {
1318
- // The limit of request body size, json default "100KB", urlencoded default "100KB". Learn more: https://expressjs.com/en/4x/api.html#express.json
1319
- json: {
1320
- limit: "100KB", // default: "100KB"
1321
- },
1322
- urlencoded: {
1323
- limit: "100KB", // default: "100KB"
1324
- extended: true, // default: true (reccomended: true)
1325
- },
1326
- file: {
1327
- uploadAllowMethod: ["POST", "PATCH", "PUT"], // Only apply file upload limit for POST, PATCH, PUT method.
1328
- allowedTypes: ["image/jpeg", "image/png", "application/pdf"], // Example: Allow only JPEG, PNG, and PDF files. Learn more: https://www.digipres.org/formats/mime-types/
1329
- limit: 5 * 1024 * 1024, // 5MB (default: Infinity)
1330
- },
1331
- },
1332
-
1333
- },
1334
- },
1335
- }
1336
- ```
1337
-
1338
- **Note:** When you must to allowed all Origin. You can assign `*` or `[]` null value to `origin` variable.
1339
-
1340
- ## # Custom Endpoint Specific Rate Limit
1341
- 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.
1342
-
1343
- ```js
1344
- const { rateLimit } = require("beech-api").Express;
1345
-
1346
- // Specific of your rate limit
1347
- const specificRateLimit1 = rateLimit({
1348
- windowMs: 5 * 60 * 1000, // 5 minutes
1349
- limit: 20,
1350
- // more...
1351
- });
1352
-
1353
- // Your Endpoints...
1354
- endpoint.get("/banana", specificRateLimit1, (req, res) => {
1355
- ...
1356
- });
1357
-
1358
- ...
1359
- ```
1360
-
1361
- ## # Custom Endpoint Specific Slow Down
1362
- **DON'T DO IT.** &nbsp; Because it's annoying to users.
1363
-
1364
- 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.
1365
-
1366
- ```js
1367
- const { slowDown } = require("beech-api").Express;
1368
-
1369
- // Specific of your slow down
1370
- const specificSlowDown1 = slowDown({
1371
- windowMs: 15 * 60 * 1000, // 15 minutes
1372
- delayAfter: 5, // Allow 5 requests per 15 minutes.
1373
- delayMs: (hits) => hits * 100, // Add 100 ms of delay to every request after the 5th one.
1374
- // more...
1375
-
1376
- /**
1377
- * So:
1378
- *
1379
- * - requests 1-5 are not delayed.
1380
- * - request 6 is delayed by 600ms
1381
- * - request 7 is delayed by 700ms
1382
- * - request 8 is delayed by 800ms
1383
- *
1384
- * and so on. After 15 minutes, the delay is reset to 0.
1385
- */
1386
- });
1387
-
1388
- // Your Endpoints...
1389
- endpoint.get("/banana", specificSlowDown1, (req, res) => {
1390
- ...
1391
- });
1392
-
1393
- ...
1394
- ```
1395
-
1396
- ## # Custom Endpoint Specific Duplicate Request
1397
- This middleware to Limit each IP duplicated requests per window.
1398
-
1399
- 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.
1400
-
1401
- ```js
1402
- const { duplicateRequest } = require("beech-api").Express;
1403
-
1404
- // Specific of your duplicate request
1405
- const specificDup1 = duplicateRequest({
1406
- expiration: 500, // Can't duplicate request for 5 milliseconds, Should 0 to disabled
1407
- // more...
1408
- });
1409
-
1410
- // Your Endpoints...
1411
- endpoint.get("/banana", specificDup1, (req, res) => {
1412
- ...
1413
- });
1414
-
1415
- ...
1416
- ```
1417
-
1418
- # Databases managements
1419
-
1420
- ## # Migrations & Seeder
1421
-
1422
- 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.
1423
-
1424
- 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.
1425
-
1426
- ## # Usage
1427
-
1428
- To create an empty project you will need to execute `init` command
1429
-
1430
- ```sh
1431
- $ npx sequelize-cli init
1432
- ```
1433
-
1434
- This will create following folders inside `databases` folder.
1435
-
1436
- - `config`, contains config file, which tells CLI how to connect with database.
1437
- - `models`, contains all models for your project.
1438
- - `migrations`, contains all migration files.
1439
- - `seeders`, contains all seed files.
1440
-
1441
- ## # Configuration
1442
-
1443
- 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:
1444
-
1445
- ```json
1446
- {
1447
- "development": {
1448
- "username": "root",
1449
- "password": null,
1450
- "database": "database_development",
1451
- "host": "127.0.0.1",
1452
- "port": 3306, // IF your another port
1453
- "dialect": "mysql"
1454
- },
1455
- "test": {
1456
- "username": "root",
1457
- "password": null,
1458
- "database": "database_test",
1459
- "host": "127.0.0.1",
1460
- "dialect": "mysql"
1461
- },
1462
- "production": {
1463
- "username": "root",
1464
- "password": null,
1465
- "database": "database_production",
1466
- "host": "127.0.0.1",
1467
- "dialect": "mysql"
1468
- }
1469
- }
1470
- ```
1471
-
1472
- ❓ **Note:** The database connect default port 3306 if you another port you can add object ``port`` in config.
1473
-
1474
- **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.
1475
-
1476
- ## # Creating first Migrations
1477
-
1478
- Create `model` use `model:generate` command. This command requires two options.
1479
-
1480
- - `--name`, Name of the model
1481
- - `--attributes`, List of model attributes
1482
-
1483
- Let's create a model name example `User`. See more about of [Datatypes](https://sequelize.org/v5/manual/data-types.html)
1484
-
1485
- ```sh
1486
- $ npx sequelize-cli model:generate --name User --attributes firstName:string,lastName:string,email:string,birhday:date
1487
- ```
1488
-
1489
- ## # Migrations Up and Down
1490
-
1491
- 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.
1492
-
1493
- - **Migrate Up** : you can create that table in database you need to run db:migrate command.
1494
-
1495
- ```sh
1496
- $ npx sequelize-cli db:migrate
1497
- ```
1498
-
1499
- - **Migrate Down** : you can use `db:migrate:undo`, this command will revert most recent migration.
1500
- ```sh
1501
- // Step to undo
1502
- $ npx sequelize-cli db:migrate:undo
1503
-
1504
- // All to undo
1505
- $ npx sequelize-cli db:migrate:undo:all
1506
-
1507
- ```
1508
-
1509
- ## # Creating First Seeder
1510
-
1511
- 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.
1512
-
1513
- Let's create a seed file which will add a demo user to our User table.
1514
-
1515
- ```sh
1516
- $ npx sequelize-cli seed:generate --name user
1517
- ```
1518
-
1519
- ## # Seeder Up and Down
1520
-
1521
- 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.
1522
-
1523
- - **Seed Up** : you can execute that seed file and you will have a user inserted into `User` table.
1524
-
1525
- ```sh
1526
- $ npx sequelize-cli db:seed:all
1527
- ```
1528
-
1529
- - **Seed Down** : seeders can be undone if they are using any storage. There are two commands available for that:
1530
-
1531
- If you wish to undo most recent seed
1532
-
1533
- ```sh
1534
- $ npx sequelize-cli db:seed:undo
1535
- ```
1536
-
1537
- If you wish to undo a specific seed
1538
-
1539
- ```
1540
- $ npx sequelize-cli db:seed:undo --seed <seederName>
1541
- ```
1542
-
1543
- If you wish to undo all seeds
1544
-
1545
- ```sh
1546
- $ npx sequelize-cli db:seed:undo:all
1547
- ```
1548
-
1549
- # Testing
1550
-
1551
- 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)
1552
-
1553
- So, When you make the new endpoints it's automatic create test file end with `.spec.js` in `__test__` folder with constant `baseUrl` variable and `axios` package.
1554
-
1555
- ***For Example :***
1556
-
1557
- 📂 \_\_test\_\_/unit/endpoints/fruit-endpoints.spec.js
1558
- ```js
1559
- const endpoint = baseUrl.concat("/fruit");
1560
-
1561
- describe("Test endpoint : " + endpoint, () => {
1562
- it("Truthy!", () => {
1563
- expect("/fruit").toBeTruthy();
1564
- });
1565
-
1566
- it("Respond with basic GET status code 200", (done) => {
1567
- axios.get(endpoint).then((res) => {
1568
- expect(200).toEqual(res.data.code);
1569
- done();
1570
- });
1571
- });
1572
- });
1573
- ```
1574
-
1575
-
1576
- # Implementation
1577
-
1578
- ## # Implement with [Docker](https://www.docker.com)
1579
-
1580
- [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.
1581
-
1582
- - ### **Create Dockerfile**
1583
-
1584
- 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/).
1585
-
1586
- 📂 Dockerfile
1587
- ```js
1588
- FROM node:18-alpine
1589
- ENV NODE_ENV=production
1590
- WORKDIR /usr/src/api
1591
- COPY ["package.json", "package-lock.json*", "./"]
1592
- RUN npm install --production --silent && mv node_modules .
1593
- COPY . .
1594
- EXPOSE 9000
1595
- CMD ["node", "./node_modules/beech-api/packages/cli/beech"]
1596
- ```
1597
-
1598
- - ### **Docker build image**
1599
-
1600
- 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.
1601
-
1602
- ```sh
1603
- $ docker build -t <imageName> .
1604
- ```
1605
-
1606
- ❓ **Note:** You can specify a repository and tag at which to save the new image : ``` $ docker build -t <imageName>:<tags> . ```
1607
-
1608
- - ### **Run docker**
1609
-
1610
- After create ``image`` you can run docker engine following :
1611
-
1612
- - ### **Docker Container (Standalone)**
1613
- ```sh
1614
- $ docker run -d -p 9000:9000 --name <containerName> <imageName>
1615
- ```
1616
-
1617
- - ### **Create Docker Swarm (Cluster)**
1618
- ```sh
1619
- # Initiate swarm
1620
- $ docker swarm init
1621
-
1622
- # Run docker service
1623
- $ docker service create --replicas <instances> --name <containerName> --publish 9000:9000 <imageName>
1624
- ```
1625
-
1626
- ## # Implement with [PM2](https://pm2.keymetrics.io/)
1627
- [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/).
1628
-
1629
- ```sh
1630
- # Start service as standalone
1631
- $ pm2 start ./node_modules/beech-api/packages/cli/beech --name <serviceName>
1632
-
1633
- # OR
1634
-
1635
- # Start service as cluster mode
1636
- $ pm2 start ./node_modules/beech-api/packages/cli/beech --name <serviceName> -i <instances>
1637
- ```
1638
-
1639
- # Development
1640
-
1641
- Want to contribute or join for great job!, You can contact to me via
1642
-
1643
- - GitHub: [bombkiml/beech-api - issues](https://github.com/bombkiml/beech-api/issues)
1644
- - E-mail: nattapat.jquery@gmail.com
1645
- - Facebook: [https://www.facebook.com/bombkiml](https://www.facebook.com/bombkiml)
1646
-
1647
- # License
1648
-
1649
- The Beech API framework is open-sourced software licensed under the [MIT license.](https://opensource.org/licenses/MIT)
1
+ [![N|Solid](https://i.ibb.co/NKxx9NQ/beech320.jpg)](https://github.com/bombkiml)
2
+
3
+ # Beech API framework
4
+ #### Auto endpoint v.3.9.0 (LTS)
5
+
6
+ [![beech-api release](https://img.shields.io/github/v/release/bombkiml/beech-api)](https://github.com/bombkiml/beech-api/releases/)
7
+ [![PyPI license](https://shields.io/pypi/l/ansicolortags.svg)](https://github.com/bombkiml/beech-api/blob/master/README.md)
8
+
9
+ # What is Beech API ?
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)
12
+
13
+ ## Let's go
14
+ - <b>[Installation](#installation)</b>
15
+ - <b>[Creating a project](#creating-a-project)</b>
16
+ - <b>[Upgrade to latest version](#upgrade-to-latest-version)</b>
17
+ - <b>[Beech CLI tool available](#beech-cli-tool-available)</b>
18
+ - ✨ <b>Automation Endpoints with CRUD</b>
19
+ - [Database Connection](#database-connection)
20
+ - [Model](#models)
21
+ - [Retrieving data with Query String](#retrieving-data-with-query-string)
22
+ - Conditions
23
+ - Grouping
24
+ - Ordering
25
+ - Timestamps (Add-on in Store and Update)
26
+ - [Transactions](#-transactions)
27
+ - [Disorganized transactions](#way-1---disorganized-transactions-)
28
+ - [Organized transactions](#way-2---organized-transactions-)
29
+ - [Transactions set Isolation levels](#way-3---transactions-set-isolation-levels-)
30
+ - [Endpoints](#endpoints)
31
+ - [Helpers](#helpers)
32
+ - 🔐 <b>System Management of Authentication</b>
33
+ - [Authentication Manegement](#authentication-passport-jwt)
34
+ - [Request Token](#request-token)
35
+ - [Beech Guard](#beech-guard)
36
+ - Verify Identity Management
37
+ - Two Factor (2fa, OTP, etc.)
38
+ - [Beech User Authentication Managements](#-beech-user-authentication-managements)
39
+ - Create Auth
40
+ - Update Auth
41
+ - 🛠️ <b>Safe Endpoints Request</b>
42
+ - [Rate Limit](#-custom-endpoint-specific-rate-limit)
43
+ - [Slow Down](#-custom-endpoint-specific-slow-down)
44
+ - [Block Duplicate Request per Window](#-custom-endpoint-specific-duplicate-request)
45
+ - [JWT Broken Role](#jwt-broken-role)
46
+ - [Advance Guard (Timimg)](#-beech-advanced-guard-timing)
47
+ - 🙂 <b>Hight Security under passport-jwt, oauth2</b>
48
+ - 🌐 <b>Supported Official Strategy</b>
49
+ - [Google](#-google-strategy)
50
+ - [Facebook](#-facebook-strategy)
51
+ - 🖥️ <b>CORS Origin & Server Configuration</b>
52
+ - [Config Base public path `./`](#cors-origin--server-configuration)
53
+ - [Allow origin whitelist](#cors-origin--server-configuration)
54
+ - 📚 <b>Databases Managements</b>
55
+ - [Migrations](#databases-managements)
56
+ - [Seeder](#-creating-first-seeder)
57
+ - ☕ <b>Testing</b>
58
+ - [Jest](#testing)
59
+ - 🏃 <b>Implementration</b>
60
+ - [Building for Production](#building-for-production)
61
+ - [Docker](#implementation)
62
+ - [PM2](#-implement-with-pm2)
63
+
64
+ # Environment
65
+
66
+ - [`Node.js`](https://nodejs.org) >= 18.18.0+ (recommended)
67
+
68
+ # Installation
69
+
70
+ Beech API needed Node.js version 18.18.0 or above. You can management multiple versions on the same machine with [nvm](https://github.com/creationix/nvm) or [nvm-windows](https://github.com/coreybutler/nvm-windows).
71
+
72
+ <b>So, Let's go to install</b> `beech-api`
73
+
74
+ ```sh
75
+ # NPM
76
+ $ npm install beech-api --global
77
+
78
+ # Yarn
79
+ $ yarn global add beech-api
80
+ ```
81
+
82
+ Installation demo:
83
+
84
+ [Demo 1](https://i.ibb.co/TBjNgVrF/1-11.gif)
85
+ ![Alt Text](https://i.ibb.co/TBjNgVrF/1-11.gif)
86
+
87
+ [Demo 2](https://i.ibb.co/wrdgyzDP/ezgif-8539024298ec62a9.gif)
88
+ ![Alt Text](https://i.ibb.co/wrdgyzDP/ezgif-8539024298ec62a9.gif)
89
+
90
+ After installation, you will have access to the `beech-app` binary in your command line.
91
+ You can check you have the right version with this command:
92
+
93
+ ```sh
94
+ $ beech-app --version
95
+ ```
96
+
97
+ # Creating a project
98
+
99
+ Create a new project run:
100
+
101
+ ```sh
102
+ $ beech-app create hello-world
103
+ ```
104
+ Run your project:
105
+ ```sh
106
+ $ cd hello-world
107
+
108
+ $ npm run dev
109
+ # OR
110
+ $ yarn dev
111
+ ```
112
+
113
+ ❓ **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.
114
+
115
+
116
+ # Upgrade to latest version
117
+ The Beech API upgrade to latest version command avariable :
118
+
119
+ ```sh
120
+ // Project upgrade
121
+ $ beech-app update
122
+
123
+ // Global upgrade
124
+ $ beech-app update -g, --global
125
+ ```
126
+
127
+ # Beech CLI tool available
128
+ After installation, you will have access to the `beech` binary in your command line.
129
+ The `beech` command has a number of options and you can explore them all by running:
130
+
131
+ ```sh
132
+ $ beech --help
133
+ ```
134
+
135
+ The `beech` command line available:
136
+
137
+ ```
138
+ Usage:
139
+ $ beech [options] [arguments] [special]
140
+
141
+ Options:
142
+ ?, -h, --help Display this help message.
143
+ -v, --version Display the application version.
144
+
145
+ Commands:
146
+ $ beech make <endpoint> Create a new Endpoints and unit test file.
147
+ Use [special] `-R, --require` to select Model(s).
148
+
149
+ $ beech make <model> --model, -M Create a new Models file.
150
+ Options:
151
+ --no-comment Ignore property comments in Schema.
152
+ --name <custom_name> Rename for the Model file.
153
+
154
+ $ beech update model <model_name> Update existing Model with latest DB structure.
155
+ Options:
156
+ --no-comment Ignore property comments in Schema.
157
+ --name <custom_name> Rename for the Model file.
158
+ --inject <table_name> Update schema to latest,
159
+ from a specific table name.
160
+
161
+ $ beech make <helper> --helper Create a new Helpers file.
162
+ $ beech passport init Initialize authentication with passport-jwt.
163
+ $ beech skd init Initialize Job Scheduler file.
164
+ $ beech key:generate, key:gen Re-Generate application key (Dangerous!).
165
+ $ beech hash:<text> Hash text for Database connection access.
166
+ ```
167
+ **Note:** Every to create new project will be generated new ``app_key`` in ``app.config.js`` file.
168
+
169
+ **Note:** If you can re-generate. Can use command ``$ beech key:generate`` or ``$ beech key:gen``
170
+
171
+ # Database connection
172
+
173
+ You might connection to Database with `database_config` object in `app.config.js` file. Anything can support to multiple Database connections.
174
+
175
+ The connection base on `pool_base` in `global.config.js` file.
176
+
177
+ - `basic` = Support only Raw Query with Only MySQL.
178
+ - `sequelize` = Support PDO, Raw Query with various Database Engine.
179
+
180
+ In case Access to Database must to Hash the `username` and `password` with Beech CLI like this.
181
+
182
+ ```sh
183
+ // Hash database username
184
+ $ beech hash:root
185
+ Output: m42BVxQ6Q4kLdRX7xS_Hm7WbQiNqShJDvw9SLCgI431oafWBtQJoJDnoCL
186
+
187
+ // Hash database password
188
+ $ beech hash:password
189
+ Output: FjgcgJPylkV7EeQJjea_EeifPwaHVO9onD3ATk3YYAyvjtMGu3dcDS0ejA
190
+
191
+ ```
192
+ ***For Example :***
193
+
194
+ 📂 app.config.js
195
+ ```js
196
+ // Database configuration Only Basic & Sequelize (needed Hash)
197
+
198
+ ...
199
+
200
+ database_config: [
201
+ {
202
+ dialect: "mysql",
203
+ name: "mysql_my_store_db",
204
+ host: "localhost",
205
+ username: "m42BVxQ6Q4kLdRX7xS_Hm7WbQiNqShJDvw9SLCgI431oafWBtQJoJDnoCL",
206
+ password: "FjgcgJPylkV7EeQJjea_EeifPwaHVO9onD3ATk3YYAyvjtMGu3dcDS0ejA",
207
+ database: "my_store_db",
208
+ port: "3306",
209
+
210
+ // Specify global options, which are used when Define is called.
211
+ define: {
212
+ charset: "utf8",
213
+ freezeTableName: true,
214
+ ...
215
+ },
216
+
217
+ timezone: "+07:00", // Example: GMT+2
218
+ // or use a named timezone supported by Intl.Locale
219
+ // timezone: 'America/Los_Angeles',
220
+
221
+ logging: console.log, // SQL trace logs. Learn more: https://sequelize.org/docs/v6/getting-started/#logging
222
+
223
+ is_connect: true, // Boolean, Turn ON/OFF to connect
224
+ },
225
+
226
+ ...
227
+
228
+ ],
229
+
230
+ ...
231
+ ```
232
+ ❓ **Caution! :** Every re-new generate `app_key`. Must to new Hash your Access and change to ALL Database connections.
233
+
234
+ ❓ **Development** : You can add ```dev: true``` in ```main_config``` for a better experience.
235
+
236
+ # Models
237
+
238
+ 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.
239
+
240
+ ```sh
241
+ $ beech make modelName --model
242
+ ```
243
+
244
+ ## # Model (Basic)
245
+
246
+ Basic model only support `MySQL` Raw Query format and freedom of your SQL query
247
+
248
+ ❓ **Note:** The Basic pool engine it's not support auto Endpoints.
249
+
250
+
251
+ ***For example :***
252
+
253
+ 📂 models/Fruit.js
254
+ ```js
255
+ module.exports = {
256
+
257
+ // Example basic function get data
258
+ getData() {
259
+
260
+ return {
261
+ id: 1,
262
+ name: "John Doe",
263
+ }
264
+
265
+ },
266
+
267
+ // Example basic function get data from MySQL table
268
+ getFruit() {
269
+
270
+ // calling Pool connection name by `mysql.default_db`
271
+ mysql.default_db.query("SELECT * FROM fruit", (err, results) => {
272
+
273
+ if (err) { throw err }
274
+ return results;
275
+
276
+ });
277
+
278
+ }
279
+
280
+ };
281
+ ```
282
+
283
+ ## # Model (Sequelize)
284
+
285
+ Sequelize is a promise-based Node.js ORM tool for Postgres, MySQL, MariaDB, SQLite, Microsoft SQL Server, Oracle Database, Amazon Redshift and Snowflake’s Data Cloud. It features solid transaction support, relations, eager and lazy loading, read replication and more. <br/>You can learn more: [Sequelize docs](https://sequelize.org/docs/v6)
286
+
287
+ You can asign more DataTypes, Learn more : [Sequelize Data Types](https://sequelize.org/docs/v6/core-concepts/model-basics/#data-types)
288
+
289
+ **Note:** When you generate a model it's create table structure for automatically for you.
290
+
291
+ ***For example :***
292
+
293
+ 📂 models/Fruit.js
294
+ ```js
295
+ const { Schema } = require("beech-api");
296
+
297
+ // Define table Schema with `Schema(sql.default_db)` connection name
298
+ const Fruit = Schema(sql.default_db).define("fruit", {
299
+ fruit_id: {
300
+ field: "id", // Rename PK field to fruit_id Ref: `id` field in fruit table
301
+ type: DataTypes.INTEGER,
302
+ autoIncrement: true,
303
+ primaryKey: true
304
+ },
305
+ friut_uuid: {
306
+ field: "uuid",
307
+ type: DataTypes.STRING(100),
308
+ allowNull: true,
309
+ defaultValue: DataTypes.UUIDV4,
310
+ },
311
+ fruitName: DataTypes.STRING,
312
+ fruitQty: DataTypes.INTEGER,
313
+ fruitPrice: {
314
+ type: DataTypes.INTEGER,
315
+ allowNull: false, // Allow null feilds
316
+ },
317
+ sort: DataTypes.STRING,
318
+ createdAt: {
319
+ type: DataTypes.DATE,
320
+ allowNull: false,
321
+ defaultValue: DataTypes.NOW,
322
+ },
323
+ updatedAt: {
324
+ type: DataTypes.DATE,
325
+ allowNull: true,
326
+ },
327
+ }, {
328
+ // Enables timestamps with createdAt and updatedAt
329
+ timestamps: true,
330
+ // Custom field names createdAt and updatedAt
331
+ createdAt: "createdAt",
332
+ updatedAt: "updatedAt",
333
+ });
334
+
335
+ Fruit.options = {
336
+ // Choose one for Allow magic generate default Endpoint (CRUD), It's like magic creating The endpoints for you (CRUD) ✨
337
+
338
+ // Option 1: Allow all methods
339
+ defaultEndpoint: true,
340
+
341
+ // Option 2: Allow with specific per methods
342
+ defaultEndpoint: {
343
+ GET: true,
344
+ POST: {
345
+ allow: true, // allow Auto-Endpoint
346
+ jwt: {
347
+ allow: true, // allow JWT
348
+ broken_role: [
349
+ { role: [1, 2] },
350
+ ],
351
+ },
352
+ // Rate Limit for POST
353
+ rate_limit: {
354
+ windowMs: 15 * 60 * 1000, // 15 minutes
355
+ limit: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes).
356
+ // store: ... , // Redis, Memcached, etc.
357
+ // See more: https://www.npmjs.com/package/express-rate-limit#Configuration
358
+ },
359
+ // Duplicate Request for POST
360
+ duplicate_request: {
361
+ expiration: 500, // Can't duplicate request for 5 milliseconds each IP requests per `window` (Disabled for Set expiration to 0 zero.)
362
+ },
363
+ },
364
+ PATCH: false,
365
+ DELETE: false,
366
+ },
367
+
368
+ limitRows: 100, // Limit rows default 100
369
+ };
370
+
371
+ // Example Finder by id (ORM), Learn more: https://sequelize.org/docs/v6/core-concepts/model-querying-finders/
372
+ function exampleFindOneFruitById(id) {
373
+ return Fruit.findOne({ where: { id: id } });
374
+ }
375
+
376
+ // Example Raw Query with Model Instances. This allows you to easily map a query to a predefined model
377
+ function exampleGetAllFruitWithModelInstance(id) {
378
+ return Fruit.query("SELECT * FROM fruit", {
379
+ model: Fruit, // When JOIN table needed register that table [Fruit, ...]
380
+ mapToModel: true // pass true here if you have any mapped fields
381
+ });
382
+ }
383
+
384
+ // Example Raw Query, Learn more: https://sequelize.org/docs/v6/core-concepts/raw-queries/
385
+ function exampleGetAllFruit(id) {
386
+ return Fruit.query("SELECT * FROM fruit");
387
+ }
388
+
389
+ ...
390
+
391
+ // Export Schema, Function, ...
392
+ module.exports = {
393
+ Fruit,
394
+ exampleFindOneFruitById,
395
+ exampleGetAllFruitWithModelInstance,
396
+ exampleGetAllFruit,
397
+ ...
398
+ };
399
+ ```
400
+
401
+ ## Retrieving data with Query String
402
+
403
+ Now you can add Query String with Conditional, Grouping and Ordering (Now Support Readonly for GET method)
404
+
405
+ ### That's cool! It's like magic Creating The Endpoints for you (CRUD) ✨
406
+
407
+ <b style="font-size:12pt">For Example, Now!</b>, You can request to `/fruit` with methods GET, POST, PATCH and DELETE like this.
408
+
409
+ | Efficacy | Method | Endpoint | Body | Mode |
410
+ |:---------|:---------|:-----------------------|:-------------|:--------|
411
+ | Create | POST | /fruit | { } | Single |
412
+ | Create | POST | /fruit | [ ] | Bulk |
413
+ | Read | GET | /fruit | No | Fetch |
414
+ | Read | GET | /fruit/:limit/:offset | No | Fetch |
415
+ | Read | GET | /fruit?someField=1 | No | Fetch |
416
+ | Read | GET | /fruit?orderby=sort | No | Fetch |
417
+ | Read | GET | /fruit?groupby=id | No | Fetch |
418
+ | Update | PATCH | /fruit/:id | { } | Single |
419
+ | Delete | DELETE | /fruit/:id | No | Single |
420
+
421
+ Add some Basic Conditions, Grouping and Ordering with `QUERY STRING` under GET methods<br/>
422
+
423
+ Retrieving `fruit` data with GET : `/fruit?someField=[eq,1]&groupby=[id]&orderby=[id,desc]`
424
+
425
+ ***For Example :***
426
+
427
+ ```java
428
+ // WHERE Conditions
429
+ GET: /fruit?id=1 // id = 1
430
+ GET: /fruit?isActived=[eq,1] // isActived = 1
431
+ GET: /fruit?fruitName=[like,Banana%] // fruitName LIKE 'Banana%' (Not allow with date, time)
432
+ GET: /fruit?cost=[gt,50]&qty=[lt,10] // cost > 50 AND qty < 10
433
+ GET: /fruit/10/0?qty=[lt,10] // qty < 10 LIMIT 0,10
434
+
435
+ // Grouping
436
+ GET: /fruit?groupby=id // GROUP BY id
437
+ GET: /fruit?groupby=[id,fruitName] // GROUP BY id, fruitName
438
+
439
+ // Ordering
440
+ GET: /fruit?oderby=id // ORDER BY id ASC
441
+ GET: /fruit?oderby=[sort,desc] // ORDER BY sort DESC
442
+ ```
443
+
444
+ For usage avariable:
445
+
446
+ ```java
447
+ // Basics conditions
448
+ =3 // = 3
449
+ =[eq,3] // = 3
450
+ =[ne,20] // != 20
451
+ =[is,null] // IS NULL
452
+ =[not,null] // IS NOT NULL
453
+ =[or,[5,6]] // (someField = 5) OR (someField = 6) // Not support NULL value
454
+
455
+ // Number comparisons conditions
456
+ =[gt,6] // > 6
457
+ =[gte,6] // >= 6
458
+ =[lt,10] // < 10
459
+ =[lte,10] // <= 10
460
+ =[between,[6,10]] // BETWEEN 6 AND 10
461
+ =[between,["2025-01-01","2025-04-30"]] // BETWEEN "2025-01-01" AND "2025-04-30"
462
+ // When assign Datetime format will only support field datatype is `Date`, `Datetime`, `Time`
463
+
464
+ // OR You can assign Datetime like this.
465
+ =[between,["2025-01-01 12:00:00","2025-04-30 15:00:00"]] // BETWEEN "2025-01-01 12:00:00" AND "2025-04-30 15:00:00"
466
+
467
+ =[notBetween,[11,15]] // NOT BETWEEN 11 AND 15
468
+
469
+ // Other operators conditions
470
+ =[in,[1,2,3]], // IN [1, 2, 3]
471
+ =[notIn,[1,2,3]], // NOT IN [1, 2, 3]
472
+ =[like,"%Banana"] // LIKE '%Banana' (Freestyle LIKE)
473
+
474
+ =[notLike,"Banana"] // NOT LIKE 'Banana'
475
+ =[startsWith,"Banana"] // LIKE 'Banana%'
476
+ =[endsWith,"Banana"] // LIKE '%Banana'
477
+ =[substring,"Banana"] // LIKE '%Banana%'
478
+
479
+ // Grouping
480
+ groupby=id // GROUP BY id
481
+ groupby=[id] // ORDER BY id
482
+ groupby=[id,fruitName] // ORDER BY id, fruitName
483
+
484
+ // Ordering
485
+ oderby=id // ORDER BY id ASC (Basic usage default Ascending)
486
+ oderby=[id,asc] // ORDER BY id ASC
487
+ oderby=[id,desc] // ORDER BY id ASC
488
+ oderby=[[id,desc],[sort,asc]] // ORDER BY id DESC, sort ASC
489
+ ```
490
+
491
+ ## # Transactions
492
+
493
+ Sequelize does not use transactions by default. However, for production-ready usage of Sequelize, you should definitely configure Sequelize to use transactions.
494
+
495
+ Beech use Sequelize supports three ways of using transactions:
496
+
497
+ - ### Way 1 - Disorganized transactions :
498
+ ```js
499
+ // First, we start a transaction from your connection and save it into a variable
500
+ const t = await Fruit.transaction();
501
+
502
+ try {
503
+
504
+ // Then, we do some calls passing this transaction as an option:
505
+ const fruit = await Fruit.create({ fruitName: 'Banana', fruitQty: '5', }, { transaction: t });
506
+ await fruit.addSibling({ fruitName: 'Litle', fruitQty: '2', }, { transaction: t }); // Error function
507
+
508
+ // If the execution reaches this line, no errors were thrown.
509
+ // We commit the transaction.
510
+ await t.commit();
511
+
512
+ } catch (error) {
513
+
514
+ // If the execution reaches this line, an error was thrown.
515
+ // We rollback the transaction.
516
+ await t.rollback();
517
+
518
+ }
519
+ ```
520
+
521
+ - ### Way 2 - Organized transactions :
522
+ ```js
523
+ // First, we start a transaction from your connection and save it into a variable
524
+ Fruit.transaction(async t => {
525
+ try {
526
+
527
+ // Then, we do some calls passing this transaction as an option:
528
+ const fruit = await Fruit.create({ fruitName: 'Banana', fruitQty: '5', }, { transaction: t });
529
+ await fruit.addSibling({ fruitName: 'Litle', fruitQty: '2', }, { transaction: t }); // Error function
530
+
531
+ // If the execution reaches this line, no errors were thrown.
532
+ // We commit the transaction.
533
+ await t.commit();
534
+
535
+ } catch (error) {
536
+
537
+ // If the execution reaches this line, an error was thrown.
538
+ // We rollback the transaction.
539
+ await t.rollback();
540
+
541
+ }
542
+ });
543
+ ```
544
+
545
+ - ### Way 3 - Transactions set Isolation levels :
546
+
547
+ The possible [isolations levels](https://sequelize.org/docs/v6/other-topics/transactions/#isolation-levels) to use when starting a transaction:
548
+
549
+ ```js
550
+ const { Transaction } = require('sequelize');
551
+
552
+ // First, we start a transaction from your connection and save it into a variable
553
+ Fruit.transaction(
554
+ {
555
+ isolationLevel: Transaction.ISOLATION_LEVELS.SERIALIZABLE,
556
+ },
557
+ async t => {
558
+ try {
559
+
560
+ // Then, we do some calls passing this transaction as an option:
561
+ const fruit = await Fruit.create({ fruitName: 'Banana', fruitQty: '5', }, { transaction: t });
562
+ await fruit.addSibling({ fruitName: 'Litle', fruitQty: '2', }, { transaction: t }); // Error function
563
+
564
+ // If the execution reaches this line, no errors were thrown.
565
+ // We commit the transaction.
566
+ await t.commit();
567
+
568
+ } catch (error) {
569
+
570
+ // If the execution reaches this line, an error was thrown.
571
+ // We rollback the transaction.
572
+ await t.rollback();
573
+
574
+ }
575
+ });
576
+ ```
577
+
578
+ # Endpoints
579
+
580
+ The `endpoints` keep the endpoints basic request files currently support `GET`, `POST`, `PUT`, `PATCH` and `DELETE`.
581
+
582
+ So, you might create new endpoints with constant `endpoint` object variable in `src/endpoints/` folder and file neme must be end with `-endpoints.js`
583
+
584
+ ```sh
585
+ $ beech make endpointName
586
+ ```
587
+ You might using [special] `-R, --require` for choose Model(s) used for that endpoint.
588
+
589
+ **Note:** If you generate Endpoint Name same Auto-Endpoint it's Override to main Auto-Endpoint to you, (You always have priority).
590
+
591
+ ***For Example :***
592
+
593
+ 📂 endpoints/fruit-endpoints.js
594
+ ```js
595
+ // Require Model schema, Function & Others
596
+ const { Fruit } = require("@/models/Fruit");
597
+
598
+ exports.init = () => {
599
+
600
+ // GET method
601
+ endpoint.get("/fruit", Credentials, async (req, res) => {
602
+ // example call Fruit model for get data
603
+ res.json({
604
+ code: 200,
605
+ status: "SUCCESS",
606
+ results: await Fruit.findAll();
607
+ });
608
+ });
609
+
610
+
611
+ // POST method
612
+ endpoint.post("/fruit", Credentials, (req, res) => {
613
+ // @response
614
+ res.json({
615
+ code: 200,
616
+ status: "SUCCESS",
617
+ message: "POST request at /fruit",
618
+ result: {
619
+ id: req.body.id,
620
+ name: req.body.name,
621
+ },
622
+ });
623
+ });
624
+
625
+
626
+ // PUT method
627
+ endpoint.put("/fruit/:id", Credentials, (req, res) => {
628
+ // @response
629
+ res.json({
630
+ code: 200,
631
+ status: "SUCCESS",
632
+ message: "PUT request at /fruit/" + req.params.id,
633
+ });
634
+ });
635
+
636
+
637
+ // DELETE method
638
+ endpoint.delete("/fruit/:id", Credentials, (req, res) => {
639
+ // @response
640
+ res.json({
641
+ code: 200,
642
+ status: "SUCCESS",
643
+ message: "DELETE request at /fruit/" + req.params.id,
644
+ });
645
+ });
646
+
647
+ ...
648
+
649
+ }
650
+ ```
651
+
652
+ # JWT Broken Role
653
+
654
+ The **JWT Broken Role** mechanism provides a flexible way to bypass or override role-based authorization rules when using JWT.
655
+
656
+ #### It can be applied in three different levels, depending on your use case.
657
+
658
+ | Priority | Level | Scope | Best For |
659
+ |:---------|:--------------------------------|:-------------------------|:--------------------------------|
660
+ | 3rd | Global (``passport.config.js``) | All endpoints | Common authorization exceptions |
661
+ | 2nd | Model-level options | Per model & HTTP method | Structured, reusable rules |
662
+ | 1st | Endpoint middleware | Single endpoint | Custom or special cases |
663
+
664
+ This multi-layer approach allows you to design **secure, flexible, and maintainable JWT authorization flows**.
665
+
666
+ ### 1. Global Configuration (passport.config.js) - Priority 3
667
+
668
+ You can define global JWT Broken Role rules that apply to all endpoints by configuring them in ``passport.config.js``.
669
+ ```js
670
+ module.exports = {
671
+ // Enable JWT authentication
672
+ jwt_allow: true,
673
+
674
+ ...
675
+
676
+ // Global JWT broken role configuration
677
+ jwt_broken_role: [
678
+ {
679
+ role: [0, 2, 4],
680
+ email: "john.doe@company.com",
681
+ }, // Basic role matching
682
+
683
+ {
684
+ role: { $in: [0, 2, 4] },
685
+ email: { $regex: /@company\.com$/ },
686
+ }, // Advanced matching using operators
687
+ ],
688
+
689
+ ...
690
+ };
691
+ ```
692
+
693
+ **Use cases**
694
+
695
+ - Apply common authorization exceptions across the entire application
696
+ - Support both simple role arrays and advanced operators (``$in``, ``$regex``, etc.)
697
+
698
+ ### 2. Model-Level Configuration (Per HTTP Method) - Priority 2
699
+
700
+ You can configure JWT and Broken Role rules per model and per HTTP method using model options.
701
+
702
+ 📂 src/models/Fruit.js
703
+ ```js
704
+ Fruit.options = {
705
+ ...
706
+
707
+ // Auto-endpoint configuration by HTTP method
708
+ defaultEndpoint: {
709
+ GET: true, // Enable auto-generated GET endpoint
710
+
711
+ POST: {
712
+ allow: true,
713
+ jwt: {
714
+ allow: true,
715
+ broken_role: [
716
+ { role: [5, 6] },
717
+ ],
718
+ },
719
+ },
720
+
721
+ PATCH: {
722
+ allow: true,
723
+ jwt: {
724
+ allow: true,
725
+ broken_role: [
726
+ { role: [5, 6, 9] },
727
+ { department: "IT" },
728
+ ],
729
+ },
730
+ },
731
+
732
+ DELETE: false, // Disable auto-generated DELETE endpoint
733
+ },
734
+
735
+ ...
736
+ };
737
+ ```
738
+
739
+ **Use cases**
740
+
741
+ - Fine-grained access control per HTTP method
742
+ - Different role requirements for POST, PATCH, etc.
743
+ - Combine role-based and attribute-based conditions
744
+
745
+ ### 3. Endpoint-Level Configuration (Credentials Middleware) - Priority 1
746
+
747
+ For maximum flexibility, you can define Broken Role rules directly on a specific endpoint using the Credentials middleware.
748
+
749
+ 📂 endpoints/custom-fruit-endpoints.js
750
+ ```js
751
+ const { Fruit } = require("@/models/Fruit");
752
+
753
+ endpoint.delete(
754
+ "/destroy-fruit-by-id/:id",
755
+ Credentials([{ role: [5, 9] }]),
756
+ async (req, res) => {
757
+
758
+ // Only JWT tokens with role level 5 or 9 are allowed
759
+
760
+ const deleted = await Fruit.destroy({
761
+ where: {
762
+ id: req.params.id,
763
+ },
764
+ });
765
+
766
+ console.log("result:", deleted);
767
+
768
+ // @response
769
+ }
770
+ );
771
+ ```
772
+
773
+ **Use cases**
774
+
775
+ - One-off or custom endpoints
776
+ - Highly specific authorization rules
777
+ - Override global or model-level behavior when necessary
778
+
779
+ ## Supported Basic & Operators Usage
780
+
781
+ The JWT Broken Role system supports both basic value matching and advanced operators for flexible authorization rules.
782
+
783
+ | Operator | Meaning | Description |
784
+ |:---------|:-------------------|:--------------------------------------------------------------|
785
+ | $eq | equal | Matches when the value is equal |
786
+ | $ne | not equal | Matches when the value is not equal |
787
+ | $in | value IN array | Matches when the value exists in the specified array |
788
+ | $not | value NOT IN array | Matches when the value does not exist in the specified array |
789
+ | $regex | regex match | Matches using a regular expression |
790
+ | $fn | custom function | Matches using a custom evaluation function |
791
+
792
+ ## Evaluation Logic (Very Important !)
793
+ ```js
794
+ [
795
+ { rule1 AND rule1 },
796
+ { rule2 AND rule2 }
797
+ ]
798
+
799
+ OR
800
+ ```
801
+
802
+ ## Basic Usage for Examples :
803
+
804
+ ```js
805
+ Credentials([
806
+ { role: [9] }, // Only role check
807
+ { email: 'a@b.com' }, // OR email
808
+ ])
809
+
810
+ // Common Matching Patterns
811
+ { role: [1, 2, 3] } // IN
812
+ { role: 1 } // Equal
813
+ { email: 'a@b.com' } // Equal
814
+ { department: 'IT' } // Equal
815
+ { status: ['active'] } // Dynamic key
816
+ ```
817
+
818
+ ## Operators Usage for Examples :
819
+
820
+ ```js
821
+ // Equal with Role
822
+ Credentials([
823
+ {
824
+ role: { $eq: [1, 2, 5] }
825
+ }
826
+ ])
827
+
828
+ // Not Equal with Role
829
+ Credentials([
830
+ {
831
+ role: { $ne: [0, 3] }
832
+ }
833
+ ])
834
+
835
+ // Regex with Email domain
836
+ Credentials([
837
+ {
838
+ email: { $regex: /@company\.com$/ }
839
+ }
840
+ ])
841
+
842
+ // IN with Role
843
+ Credentials([
844
+ {
845
+ role: { $in: [1, 2, 4] }
846
+ }
847
+ ])
848
+
849
+ // NOT IN with Role
850
+ Credentials([
851
+ {
852
+ role: { $not: [0, 3] }
853
+ }
854
+ ])
855
+
856
+ // Multiple OR rules
857
+ Credentials([
858
+ {
859
+ role: { $in: [1] },
860
+ email: 'john.doe@company.com'
861
+ },
862
+ // OR
863
+ {
864
+ role: { $in: [4] },
865
+ email: { $regex: /@company\.com$/ }
866
+ },
867
+ ])
868
+
869
+ // Custom Function
870
+ Credentials([
871
+ {
872
+ role: {
873
+ $fn: (value, user) => value >= 4 && user.department === 'IT'
874
+ }
875
+ }
876
+ ])
877
+ ```
878
+
879
+ # Helpers
880
+
881
+ 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.
882
+
883
+ ```sh
884
+ $ beech make helperName --helper
885
+ ```
886
+
887
+ ***For Example :***
888
+
889
+ 📂 helpers/TextEditor.js
890
+ ```js
891
+ module.exports = {
892
+
893
+ textUpperCase(text) {
894
+ return text.toUpperCase();
895
+ },
896
+
897
+ textTrim(text) {
898
+ return text.trim();
899
+ },
900
+
901
+ ...
902
+
903
+ };
904
+ ```
905
+
906
+ # Authentication (passport-jwt)
907
+
908
+ 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.
909
+
910
+ ### Passport-jwt Initialization
911
+
912
+ ```sh
913
+ $ beech passport init
914
+ ```
915
+
916
+ After passport initialized the `passport.config.js` it's appeared
917
+
918
+ 📂 passport.config.js
919
+ ```js
920
+ module.exports = {
921
+ // Allow for using passport-jwt
922
+ jwt_allow: true,
923
+
924
+ // custom authenticaiton endpoint name, default `/authentication`
925
+ auth_endpoint: "",
926
+
927
+ // your jwt secret key
928
+ secret: "your_jwt_secret",
929
+
930
+ // token expiry time (seconds), default 86400 sec. it's expired in 24 hr.
931
+ token_expired: 86400,
932
+
933
+ // Allow for using global jwt broken role
934
+ jwt_broken_role: [
935
+ // { role: [1, 2, 9] },
936
+ ],
937
+
938
+ model: {
939
+ // Main sql connection name. You must make sure connection name like inside `app.config.js` file and choose one connection name.
940
+ name: "default_db",
941
+
942
+ // table name of users store, default table `users`
943
+ table: "",
944
+
945
+ // secret user store field for authenticate, default field `username` and `password`
946
+ username_field: "",
947
+ password_field: "",
948
+
949
+ // JWT playload data, You can add it. Example: ["name", "email", ...]
950
+ fields: [],
951
+
952
+ // Other fields add for authentication.
953
+ guard: {
954
+ // Basic guard field, Example: ["pin", "hint", "2fa"]
955
+ guard_field: [],
956
+
957
+ // Advanced guard jwt request (needed some logical from front-end)
958
+ advanced_guard: {
959
+ allow: false,
960
+ entity: "", // default entity `timing`
961
+ secret: "top_secret",
962
+ time_expired: {
963
+ minutes: 1, // should length [0-60]
964
+ seconds: 0, // should length [0-60]
965
+ },
966
+ },
967
+ },
968
+ },
969
+
970
+ // Allow for using request with app_key entity (Every request must be using the app_key entity in headers)
971
+ app_key_allow: false
972
+
973
+ ...
974
+
975
+ };
976
+ ```
977
+ ### Request Token
978
+ **Authentication structure :** Simple ``users`` table:
979
+ ```
980
+ ==============================================================
981
+ | id | username | password | name | email |
982
+ --------------------------------------------------------------
983
+ | 1 | bombkiml | secret | bombkiml NC. | bomb@bomb.com |
984
+ | 2 | johnson | secret | johnson BA. | john@bomb.com |
985
+ ```
986
+
987
+ When you config passport with ```users``` table already. You will got Auth endpoint in available.
988
+ ```js
989
+ POST: "/authentication" // Request token
990
+ POST: "/authentication/refresh" // Request refresh token
991
+ POST: "/authentication/create" // Create new Auth data
992
+ PATCH: "/authentication/update/:id" // Update old Auth data (needed user id)
993
+ ```
994
+
995
+ ***XHR Example :***
996
+
997
+ ```js
998
+ // Request with body for gether Token
999
+ POST: "/authentication"
1000
+ payload: {
1001
+ username: "bombkiml",
1002
+ password: "secret"
1003
+ }
1004
+
1005
+ // Request with header for refresh token
1006
+ POST: "/authentication/refresh"
1007
+ headers: Authorization: Bearer <your_token>
1008
+
1009
+ // Request with body for Create Auth data
1010
+ POST: "/authentication/create"
1011
+ payload: {
1012
+ username: "add_new_username",
1013
+ password: "add_new_secret",
1014
+ name: "add_new_my_name",
1015
+ email: "add_new_email"
1016
+ }
1017
+
1018
+ // Request with body for Update Auth data
1019
+ PATCH: "/authentication/update/1"
1020
+ headers: Authorization: Bearer <your_token>
1021
+ payload: {
1022
+ username: "update_bombkiml",
1023
+ password: "update_secret",
1024
+ name: "update_my_name",
1025
+ email: "my_update_email@bomb.com"
1026
+ }
1027
+ ```
1028
+
1029
+ # Beech Guard
1030
+ 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.
1031
+
1032
+ ## # Guard (2FA, Other)
1033
+
1034
+ 📂 passport.config.js
1035
+ ```js
1036
+ module.exports = {
1037
+ ...
1038
+
1039
+ guard: {
1040
+ // Other fields add for authenticate, exmaple ["pin", "hint", "2fa"]
1041
+ guard_field: ["2fa"], 👈 // your feild guard. (Disabled to remove it.)
1042
+
1043
+ ...
1044
+ },
1045
+
1046
+ ...
1047
+
1048
+ }
1049
+ ```
1050
+
1051
+ ## # Beech Advanced Guard (Timing)
1052
+ 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.
1053
+
1054
+ 📂 passport.config.js
1055
+ ```js
1056
+ module.exports = {
1057
+ ...
1058
+
1059
+ guard: {
1060
+ ...
1061
+
1062
+ // Advanced guard to Request (Needed some logical from front-end)
1063
+ advanced_guard: {
1064
+ allow: false, 👈 // advanced guard allow for All Endpoint.
1065
+ entity: "", // default entity `timing`
1066
+ secret: "your_advance_guard_secret",
1067
+ time_expired: {
1068
+ minutes: 1, // should length [0-60]
1069
+ seconds: 0, // should length [0-60]
1070
+ },
1071
+ },
1072
+ },
1073
+
1074
+ ...
1075
+
1076
+ }
1077
+
1078
+ ```
1079
+
1080
+ <b>After configure</b>, You must add some logic in your front-end like this.
1081
+
1082
+ Before add logic, We needed [```beech-auth0```](https://github.com/bombkiml/beech-auth0) and [```moment.js```](https://momentjs.com) for apply in Policy.
1083
+
1084
+ ```sh
1085
+ # NPM
1086
+ $ npm install --save beech-auth0 moment
1087
+
1088
+ # Yarn
1089
+ $ yarn add beech-auth0 moment
1090
+ ```
1091
+ Now! you can add some logic like this.
1092
+
1093
+ - Import packages
1094
+
1095
+ ```js
1096
+ // CommonJS
1097
+ const { Auth0 } = require("beech-auth0");
1098
+ const moment = require("moment");
1099
+
1100
+ // ES6
1101
+ import { Auth0 } from "beech-auth0";
1102
+ import moment from "moment";
1103
+ ```
1104
+
1105
+ - Get unix time with momentJS
1106
+
1107
+ ```js
1108
+ // Get UNIX TIME with moment
1109
+ let unix_time = moment().unix();
1110
+ ```
1111
+
1112
+ - Get hashing with Beech Auth0
1113
+
1114
+ ```js
1115
+ // Auth0 Policy.
1116
+ Auth0(unix_time, 'your_advance_guard_secret', (error, hashing) => {
1117
+
1118
+ // Your XHR request for All Endpoint.
1119
+ POST: "/authentication"
1120
+ headers: { timing: hashing } 👈 // Assign advance guard entity to headers with callback hashing.
1121
+
1122
+ });
1123
+
1124
+ ```
1125
+
1126
+ ## # Beech User Authentication Managements ###
1127
+ You can easy management `users` data with Beech, Only ```Store, Update``` NO ```Delete```, Anything you can make DELETE endpoint by yourself
1128
+
1129
+ ```js
1130
+ const { Store, Update } = require("beech-api");
1131
+ ```
1132
+
1133
+ - ***Store*** users data with ``Store()``
1134
+ ```js
1135
+ // prepare data for store users
1136
+ var data = {
1137
+ username: "bombkiml",
1138
+ password: "secret",
1139
+ name: "bombkiml nc.",
1140
+ email: "bomb@bomb.com"
1141
+ }
1142
+
1143
+ Store(data, (err, stored) => {
1144
+ if (err) throw err;
1145
+
1146
+ // response affected data
1147
+ console.log(stored.insertId, stored.affectedRows);
1148
+
1149
+ });
1150
+ ```
1151
+
1152
+ - ***Update*** users data with ``Update()``
1153
+ ```js
1154
+ // prepare data for update users
1155
+ var data = {
1156
+ password: "new_secret",
1157
+ name: "bombkiml NC.",
1158
+ email: "bombkiml@bomb.com"
1159
+ }
1160
+
1161
+ Update(data, id, (err, updated) => {
1162
+ if (err) throw err;
1163
+
1164
+ // response affected data
1165
+ console.log(updated.updateId, updated.affectedRows);
1166
+
1167
+ });
1168
+ ```
1169
+
1170
+ # Beech with Official Strategy
1171
+
1172
+ Latest supported with ``Google`` and ``Facebook`` Strategy.
1173
+
1174
+
1175
+ ## # Google Strategy
1176
+
1177
+
1178
+ 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.
1179
+
1180
+ Before your application can make use of Sign In With Google, you must register your app with Google. This can be done in the [APIs & Services](https://console.cloud.google.com/apis) page of the [Google Cloud Platform console.](https://console.cloud.google.com/) Once registered, your app will be issued a client ID and secret which will be used in the strategy configuration.
1181
+
1182
+ Go to open file ``passport.config.js`` and go to ``google strategy`` then turn allow Google Strategy is ``allow: true`` something like this.
1183
+
1184
+ 📂 passport.config.js
1185
+ ```js
1186
+ ...
1187
+
1188
+ strategy: {
1189
+
1190
+ google: {
1191
+
1192
+ // Allow for using google strategy
1193
+ allow: true,
1194
+
1195
+ // Authen profile store fields available: `google_id`, `name`, `email`, `photos`, `locate`
1196
+ local_profile_fields: {
1197
+ google_id: "google_id", // Google ID field, default field name: `google_id`
1198
+ name: "your_name_field",
1199
+ email: "your_email_field",
1200
+ photos: "your_profile_url_field",
1201
+ locate: "" // If you not store set to null or remove it.
1202
+ },
1203
+ // Google development Credentials OAuth 2.0 Client IDs
1204
+ client_id: "GOOGLE_CLIENT_ID",
1205
+ client_secret: "GOOGLE_CLIENT_SECRET",
1206
+ // Callback endpoint default `/google/callback`
1207
+ callbackURL: "",
1208
+ // Failure redirect to your route
1209
+ failureRedirect: "/login"
1210
+ }
1211
+ }
1212
+
1213
+ ...
1214
+ ```
1215
+
1216
+ The above code is a configures and registers the Google Strategy.
1217
+
1218
+ - ``allow`` : Turn on/off the Google Strategy config type of ``boolean`` switch by ``true/false``.
1219
+ - ``google_id`` : Local Google ID field for store Google ID in my local database default field is ``google_id``.
1220
+ - ``local_profile_fields`` : Local Profile fields for store Google user details.
1221
+ - ``client_id`` and ``client_secret`` : The options to the Google Strategy constructor must include a ``clientID`` and ``clientSecret``, the values of which are set to the client ID and secret that were obtained when registering your application.
1222
+ - ``callbackURL`` : When registering your application. A callbackURL must also be included. Google will redirect users to this location after they have authenticated.
1223
+ - ``failureRedirect`` : When registering your application somthing failure it's redirect to that.
1224
+
1225
+ Place a button on the application's login page, prompting the user to sign in with Google.
1226
+
1227
+ ```html
1228
+ <a href="/authentication/google" class="button">Sign in with Google</a>
1229
+ ```
1230
+
1231
+ ❓ **Note:** The URL "``/authentication``" will be follow by ``auth_endpoint`` when you custom it.
1232
+
1233
+
1234
+ ## # Facebook Strategy
1235
+
1236
+
1237
+ Facebook Login allows users to sign in using their Facebook account. Support for Faceboook Login is provided by the ``passport-facebook`` package.
1238
+
1239
+ Before your application can make use of Facebook Login, you must register your app with Facebook. This can be done in the [App dashboard](https://developers.facebook.com/apps) at [Facebook for Developers.](https://developers.facebook.com/) Once registered, your app will be issued an app ID and secret which will be used in the strategy configuration.
1240
+
1241
+ Go to open file ``passport.config.js`` and go to ``facebook strategy`` then turn allow Facebook Strategy is ``allow: true`` something like this.
1242
+
1243
+ 📂 passport.config.js
1244
+ ```js
1245
+ ...
1246
+
1247
+ strategy: {
1248
+
1249
+ facebook: {
1250
+
1251
+ // Allow for using facebook strategy
1252
+ allow: true,
1253
+
1254
+ // Authen profile store fields available: `facebook_id`, `name`, `email`, `photos`, `locate`
1255
+ local_profile_fields: {
1256
+ facebook_id: "facebook_id", // Facebook ID field, default field name: `facebook_id`
1257
+ name: "your_name_field",
1258
+ email: "your_email_field",
1259
+ photos: "your_profile_url_field",
1260
+ locate: "" // If you not store set to null or remove it.
1261
+ },
1262
+ // Facebook development Credentials OAuth 2.0
1263
+ app_id: "FACEBOOK_APP_ID",
1264
+ app_secret: "FACEBOOK_APP_SECRET",
1265
+
1266
+ // You can allow Permissions facebook profile fields. Learn more (https://developers.facebook.com/docs/graph-api/reference/v13.0/user#readperms)
1267
+ // **Update 2024, Now! Facebook requests permission for show Email. Learn more (https://developers.facebook.com/docs/permissions)
1268
+ profileFieldsAllow: [ 'id', 'displayName', 'name', 'photos', 'email', 'location' ], // Default allowed
1269
+
1270
+ // Callback endpoint default `/facebook/callback`
1271
+ callbackURL: "",
1272
+ // Failure redirect to your route
1273
+ failureRedirect: "/login"
1274
+ }
1275
+ }
1276
+
1277
+ ...
1278
+ ```
1279
+
1280
+ The above code is a configures and registers the Facebook Strategy.
1281
+
1282
+ - ``allow`` : Turn on/off the Facebook Strategy config type of ``boolean`` switch by ``true/false``.
1283
+ - ``facebook_id`` : Local Facebook ID field for store Facebook ID in my local database default field is ``facebook_id``.
1284
+ - ``local_profile_fields`` : Local Profile fields for store Facebook user details.
1285
+ - ``app_id`` and ``app_secret`` : The options to the Facebook Strategy must include an app ID and secret. you must register your app with Facebook. This can be done in the [App dashboard](https://developers.facebook.com/apps) at [Facebook for Developers.](https://developers.facebook.com/) Once registered, your app will be issued an ``app ID`` and ``secret`` which will be used in the strategy configuration.
1286
+ - ``profileFieldsAllow`` : Permissions with Facebook Login. You must allow Permissions facebook profile fields: see more (https://developers.facebook.com/docs/graph-api/reference/v13.0/user#readperms)
1287
+ - ``callbackURL`` : When registering your application. A callbackURL must also be included. Facebook will redirect users to this location after they have authenticated.
1288
+ - ``failureRedirect`` : When registering your application somthing failure it's redirect to that.
1289
+
1290
+ Place a button on the application's login page, prompting the user to sign in with Facebook.
1291
+
1292
+ ```html
1293
+ <a href="/authentication/facebook" class="button">Log In With Facebook</a>
1294
+ ```
1295
+
1296
+ **Note:** The URL "``/authentication``" will be follow by ``auth_endpoint`` when you custom it.
1297
+
1298
+ # CORS Origin & Server Configuration
1299
+ 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`
1300
+
1301
+ 📂 beech.config.js
1302
+ ```js
1303
+ module.exports = {
1304
+ defineConfig: {
1305
+ // Base public path when served in development or production.
1306
+ base: process.env.NODE_ENV === "production"
1307
+ ? "/my-api/" // For Production
1308
+ : "/", // For Development
1309
+
1310
+ server: {
1311
+ // Client request allow origin whitelist
1312
+ origin: ["http://example.com", "http://my-webapp:8080", "https://cat.io"],
1313
+ originSensitive: false, // Sensitive with contrasts wording
1314
+
1315
+ // API Request rate limit (Disabled for Remove it.)
1316
+ rateLimit: {
1317
+ windowMs: 15 * 60 * 1000, // 15 minutes
1318
+ limit: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes).
1319
+ // store: ... , // Redis, Memcached, etc.
1320
+ // See more: https://www.npmjs.com/package/express-rate-limit#Configuration
1321
+ },
1322
+
1323
+ // API Duplicate Request (Disabled for Set expiration to 0 zero.)
1324
+ duplicateRequest: {
1325
+ expiration: 500, // Can't duplicate request for 5 milliseconds each IP requests per `window`
1326
+ },
1327
+
1328
+ payload: {
1329
+ // The limit of request body size, json default "100KB", urlencoded default "100KB". Learn more: https://expressjs.com/en/4x/api.html#express.json
1330
+ json: {
1331
+ limit: "100KB", // default: "100KB"
1332
+ },
1333
+ urlencoded: {
1334
+ limit: "100KB", // default: "100KB"
1335
+ extended: true, // default: true (reccomended: true)
1336
+ },
1337
+ file: {
1338
+ uploadAllowMethod: ["POST", "PATCH", "PUT"], // Only apply file upload limit for POST, PATCH, PUT method.
1339
+ allowedTypes: ["image/jpeg", "image/png", "application/pdf"], // Example: Allow only JPEG, PNG, and PDF files. Learn more: https://www.digipres.org/formats/mime-types/
1340
+ limit: 5 * 1024 * 1024, // 5MB (default: Infinity)
1341
+ },
1342
+ },
1343
+
1344
+ },
1345
+ },
1346
+ }
1347
+ ```
1348
+
1349
+ **Note:** When you must to allowed all Origin. You can assign `*` or `[]` null value to `origin` variable.
1350
+
1351
+ ## # Custom Endpoint Specific Rate Limit
1352
+ 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.
1353
+
1354
+ ```js
1355
+ const { rateLimit } = require("beech-api").Express;
1356
+
1357
+ // Specific of your rate limit
1358
+ const specificRateLimit1 = rateLimit({
1359
+ windowMs: 5 * 60 * 1000, // 5 minutes
1360
+ limit: 20,
1361
+ // more...
1362
+ });
1363
+
1364
+ // Your Endpoints...
1365
+ endpoint.get("/banana", specificRateLimit1, (req, res) => {
1366
+ ...
1367
+ });
1368
+
1369
+ ...
1370
+ ```
1371
+
1372
+ ## # Custom Endpoint Specific Slow Down
1373
+ **DON'T DO IT.** &nbsp; Because it's annoying to users.
1374
+
1375
+ 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.
1376
+
1377
+ ```js
1378
+ const { slowDown } = require("beech-api").Express;
1379
+
1380
+ // Specific of your slow down
1381
+ const specificSlowDown1 = slowDown({
1382
+ windowMs: 15 * 60 * 1000, // 15 minutes
1383
+ delayAfter: 5, // Allow 5 requests per 15 minutes.
1384
+ delayMs: (hits) => hits * 100, // Add 100 ms of delay to every request after the 5th one.
1385
+ // more...
1386
+
1387
+ /**
1388
+ * So:
1389
+ *
1390
+ * - requests 1-5 are not delayed.
1391
+ * - request 6 is delayed by 600ms
1392
+ * - request 7 is delayed by 700ms
1393
+ * - request 8 is delayed by 800ms
1394
+ *
1395
+ * and so on. After 15 minutes, the delay is reset to 0.
1396
+ */
1397
+ });
1398
+
1399
+ // Your Endpoints...
1400
+ endpoint.get("/banana", specificSlowDown1, (req, res) => {
1401
+ ...
1402
+ });
1403
+
1404
+ ...
1405
+ ```
1406
+
1407
+ ## # Custom Endpoint Specific Duplicate Request
1408
+ This middleware to Limit each IP duplicated requests per window.
1409
+
1410
+ 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.
1411
+
1412
+ ```js
1413
+ const { duplicateRequest } = require("beech-api").Express;
1414
+
1415
+ // Specific of your duplicate request
1416
+ const specificDup1 = duplicateRequest({
1417
+ expiration: 500, // Can't duplicate request for 5 milliseconds, Should 0 to disabled
1418
+ // more...
1419
+ });
1420
+
1421
+ // Your Endpoints...
1422
+ endpoint.get("/banana", specificDup1, (req, res) => {
1423
+ ...
1424
+ });
1425
+
1426
+ ...
1427
+ ```
1428
+
1429
+ # Databases managements
1430
+
1431
+ ## # Migrations & Seeder
1432
+
1433
+ 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.
1434
+
1435
+ 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.
1436
+
1437
+ ## # Usage
1438
+
1439
+ To create an empty project you will need to execute `init` command
1440
+
1441
+ ```sh
1442
+ $ npx sequelize-cli init
1443
+ ```
1444
+
1445
+ This will create following folders inside `databases` folder.
1446
+
1447
+ - `config`, contains config file, which tells CLI how to connect with database.
1448
+ - `models`, contains all models for your project.
1449
+ - `migrations`, contains all migration files.
1450
+ - `seeders`, contains all seed files.
1451
+
1452
+ ## # Configuration
1453
+
1454
+ 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:
1455
+
1456
+ ```json
1457
+ {
1458
+ "development": {
1459
+ "username": "root",
1460
+ "password": null,
1461
+ "database": "database_development",
1462
+ "host": "127.0.0.1",
1463
+ "port": 3306, // IF your another port
1464
+ "dialect": "mysql"
1465
+ },
1466
+ "test": {
1467
+ "username": "root",
1468
+ "password": null,
1469
+ "database": "database_test",
1470
+ "host": "127.0.0.1",
1471
+ "dialect": "mysql"
1472
+ },
1473
+ "production": {
1474
+ "username": "root",
1475
+ "password": null,
1476
+ "database": "database_production",
1477
+ "host": "127.0.0.1",
1478
+ "dialect": "mysql"
1479
+ }
1480
+ }
1481
+ ```
1482
+
1483
+ **Note:** The database connect default port 3306 if you another port you can add object ``port`` in config.
1484
+
1485
+ ❓ **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.
1486
+
1487
+ ## # Creating first Migrations
1488
+
1489
+ Create `model` use `model:generate` command. This command requires two options.
1490
+
1491
+ - `--name`, Name of the model
1492
+ - `--attributes`, List of model attributes
1493
+
1494
+ Let's create a model name example `User`. See more about of [Datatypes](https://sequelize.org/v5/manual/data-types.html)
1495
+
1496
+ ```sh
1497
+ $ npx sequelize-cli model:generate --name User --attributes firstName:string,lastName:string,email:string,birhday:date
1498
+ ```
1499
+
1500
+ ## # Migrations Up and Down
1501
+
1502
+ 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.
1503
+
1504
+ - **Migrate Up** : you can create that table in database you need to run db:migrate command.
1505
+
1506
+ ```sh
1507
+ $ npx sequelize-cli db:migrate
1508
+ ```
1509
+
1510
+ - **Migrate Down** : you can use `db:migrate:undo`, this command will revert most recent migration.
1511
+ ```sh
1512
+ // Step to undo
1513
+ $ npx sequelize-cli db:migrate:undo
1514
+
1515
+ // All to undo
1516
+ $ npx sequelize-cli db:migrate:undo:all
1517
+
1518
+ ```
1519
+
1520
+ ## # Creating First Seeder
1521
+
1522
+ 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.
1523
+
1524
+ Let's create a seed file which will add a demo user to our User table.
1525
+
1526
+ ```sh
1527
+ $ npx sequelize-cli seed:generate --name user
1528
+ ```
1529
+
1530
+ ## # Seeder Up and Down
1531
+
1532
+ 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.
1533
+
1534
+ - **Seed Up** : you can execute that seed file and you will have a user inserted into `User` table.
1535
+
1536
+ ```sh
1537
+ $ npx sequelize-cli db:seed:all
1538
+ ```
1539
+
1540
+ - **Seed Down** : seeders can be undone if they are using any storage. There are two commands available for that:
1541
+
1542
+ If you wish to undo most recent seed
1543
+
1544
+ ```sh
1545
+ $ npx sequelize-cli db:seed:undo
1546
+ ```
1547
+
1548
+ If you wish to undo a specific seed
1549
+
1550
+ ```
1551
+ $ npx sequelize-cli db:seed:undo --seed <seederName>
1552
+ ```
1553
+
1554
+ If you wish to undo all seeds
1555
+
1556
+ ```sh
1557
+ $ npx sequelize-cli db:seed:undo:all
1558
+ ```
1559
+
1560
+ # Testing
1561
+
1562
+ 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)
1563
+
1564
+ So, When you make the new endpoints it's automatic create test file end with `.spec.js` in `__test__` folder with constant `baseUrl` variable and `axios` package.
1565
+
1566
+ ***For Example :***
1567
+
1568
+ 📂 \_\_test\_\_/unit/endpoints/fruit-endpoints.spec.js
1569
+ ```js
1570
+ const endpoint = baseUrl.concat("/fruit");
1571
+
1572
+ describe("Test endpoint : " + endpoint, () => {
1573
+ it("Truthy!", () => {
1574
+ expect("/fruit").toBeTruthy();
1575
+ });
1576
+
1577
+ it("Respond with basic GET status code 200", (done) => {
1578
+ axios.get(endpoint).then((res) => {
1579
+ expect(200).toEqual(res.data.code);
1580
+ done();
1581
+ });
1582
+ });
1583
+ });
1584
+ ```
1585
+
1586
+ # Building for Production
1587
+
1588
+ The Beech API build system is designed to secure your source code without sacrificing performance.
1589
+
1590
+ To start the build process, run the following command from your project root
1591
+
1592
+ ```sh
1593
+ $ npm run build
1594
+ # OR
1595
+ $ yarn build
1596
+ ```
1597
+
1598
+ **Note:** This command triggers ```beech-service build``` as defined in your package.json.
1599
+
1600
+ ### # What happens during Build ?
1601
+ The build engine performs the following automated steps:
1602
+
1603
+ - **Scanning**: It scans for all .js files in src/ (endpoints, models, helpers) and configuration files.
1604
+
1605
+ - **Entry Point Generation**: It retrieves the core engine template (beech.txt) and converts it into a secured server.js in the output folder.
1606
+
1607
+ - **Compilation**: Files are minified to reduce size.
1608
+
1609
+ - **Obfuscation**:
1610
+
1611
+ - Variables and function names are renamed.
1612
+ - Strings are Base64 encoded.
1613
+ - Performance remains 100% because control-flow logic is preserved.
1614
+
1615
+ - **Distribution**: All protected files are placed in the ```./dist``` directory.
1616
+
1617
+ ### # Deployment Structure ?
1618
+ After the build is complete, your ./dist folder will look like this:
1619
+
1620
+ ```sh
1621
+ dist/
1622
+ ├── src/
1623
+ │ ├── endpoints/ (Obfuscated)
1624
+ │ ├── models/ (Obfuscated)
1625
+ │ ├── helpers/ (Obfuscated)
1626
+ │ └── etc/ (Obfuscated)
1627
+ ├── server.js (Main entry point)
1628
+ ├── app.config.js (Obfuscated)
1629
+ ├── beech.config.js (Obfuscated)
1630
+ ├── global.config.js (Obfuscated)
1631
+ └── package.json (Copied for dependency management)
1632
+ ```
1633
+
1634
+ ## # Starting the Production Server ?
1635
+ To run your application in production:
1636
+
1637
+ - Upload the contents of the dist folder to your server.
1638
+
1639
+ - Install only production dependencies:
1640
+ ```sh
1641
+ npm install --production
1642
+ ```
1643
+
1644
+ # Implementation
1645
+
1646
+ ## # Implement with [Docker](https://www.docker.com)
1647
+
1648
+ [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.
1649
+
1650
+ - ### **Create Dockerfile**
1651
+
1652
+ 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/).
1653
+
1654
+ 📂 Dockerfile
1655
+ ```js
1656
+ FROM node:18-alpine
1657
+ ENV NODE_ENV=production
1658
+ WORKDIR /usr/src/api
1659
+ COPY ["package.json", "package-lock.json*", "./"]
1660
+ RUN npm install --production --silent && mv node_modules .
1661
+ COPY . .
1662
+ EXPOSE 9000
1663
+ CMD ["node", "server.js"]
1664
+ ```
1665
+
1666
+ - ### **Docker build image**
1667
+
1668
+ 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.
1669
+
1670
+ ```sh
1671
+ $ docker build -t <imageName> .
1672
+ ```
1673
+
1674
+ ❓ **Note:** You can specify a repository and tag at which to save the new image : ``` $ docker build -t <imageName>:<tags> . ```
1675
+
1676
+ - ### **Run docker**
1677
+
1678
+ After create ``image`` you can run docker engine following :
1679
+
1680
+ - ### **Docker Container (Standalone)**
1681
+ ```sh
1682
+ $ docker run -d -p 9000:9000 --name <containerName> <imageName>
1683
+ ```
1684
+
1685
+ - ### **Create Docker Swarm (Cluster)**
1686
+ ```sh
1687
+ # Initiate swarm
1688
+ $ docker swarm init
1689
+
1690
+ # Run docker service
1691
+ $ docker service create --replicas <instances> --name <containerName> --publish 9000:9000 <imageName>
1692
+ ```
1693
+
1694
+ ## # Implement with [PM2](https://pm2.keymetrics.io/)
1695
+ [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/).
1696
+
1697
+ ```sh
1698
+ # Start service as standalone
1699
+ $ pm2 start server.js --name <serviceName>
1700
+
1701
+ # OR
1702
+
1703
+ # Start service as cluster mode
1704
+ $ pm2 start server.js --name <serviceName> -i <instances>
1705
+ ```
1706
+
1707
+ # Development
1708
+
1709
+ Want to contribute or join for great job!, You can contact to me via
1710
+
1711
+ - GitHub: [bombkiml/beech-api - issues](https://github.com/bombkiml/beech-api/issues)
1712
+ - E-mail: nattapat.jquery@gmail.com
1713
+ - Facebook: [https://www.facebook.com/bombkiml](https://www.facebook.com/bombkiml)
1714
+
1715
+ # License
1716
+
1717
+ The Beech API framework is open-sourced software licensed under the [MIT license.](https://opensource.org/licenses/MIT)