Ver código fonte

:recycle: even more restructuring based on real-world example project

master
TOJ 5 anos atrás
pai
commit
3963c6c140

+ 2
- 1
.gitignore Ver arquivo

@@ -2,4 +2,5 @@ node_modules
2 2
 .DS_Store
3 3
 dist
4 4
 dist-ssr
5
-*.local
5
+*.local
6
+**/.env

+ 0
- 16
backend/config/dev.js Ver arquivo

@@ -1,16 +0,0 @@
1
-module.exports = {
2
-    /** Server info */
3
-    host: 'localhost',
4
-    port: 3001,
5
-
6
-    db: 'test',
7
-    dbPort: 3306,
8
-    dbDialect: 'mysql', // even for mariadb
9
-
10
-    /** URL preceding endpoints */
11
-    apiBase: 'api',
12
-
13
-    /** Uncomment for cross-origin */
14
-    corsSupported: false
15
-}
16
-

+ 12
- 0
backend/lib/models/user.js Ver arquivo

@@ -0,0 +1,12 @@
1
+const Schwifty = require('@hapipal/schwifty');
2
+const Joi = require('joi');
3
+
4
+module.exports = class User extends Schwifty.Model {
5
+    static get tableName() { return 'users' }
6
+    static get joiSchema() {
7
+        return Joi.object({
8
+            id: Joi.number().required(),
9
+            name: Joi.string().required()
10
+        })
11
+    }
12
+}

backend/src/plugins/index.js → backend/lib/plugins/index.js Ver arquivo

@@ -1,10 +1,9 @@
1
-const config = require('../../config/dev');
2 1
 
3 2
 const UserPlugin = require('./user');
4 3
 const TestPlugin = require('./test');
5 4
 
6 5
 const pluginOptions = {
7
-    routes: { prefix: `/${config.apiBase}` }
6
+    routes: { prefix: `/api` }
8 7
 }
9 8
 
10 9
 module.exports = {

backend/src/plugins/test.js → backend/lib/plugins/test.js Ver arquivo


+ 14
- 0
backend/lib/plugins/user.js Ver arquivo

@@ -0,0 +1,14 @@
1
+const Schwifty = require('@hapipal/schwifty');
2
+
3
+const UserModel = require('../models/user');
4
+const UserCurrentRoute = require('../routes/user/current');
5
+
6
+module.exports = {
7
+    name: 'my-user-plugin',
8
+    version: '1.0.0',
9
+    register: async server => {
10
+        await server.register(Schwifty)
11
+        await server.registerModel(UserModel)
12
+        await server.route(UserCurrentRoute)
13
+    }
14
+}

backend/src/plugins/user.js → backend/lib/routes/user/current.js Ver arquivo

@@ -1,10 +1,8 @@
1
-const Schwifty = require('@hapipal/schwifty');
1
+'use strict';
2
+
2 3
 const Joi = require('joi');
3 4
 
4 5
 const pluginConfig = {
5
-    name: 'my-user-plugin',
6
-    version: '1.0.0',
7
-    tableName: 'users',
8 6
     handlerType: 'user',
9 7
     docs: {
10 8
         get: {
@@ -14,52 +12,42 @@ const pluginConfig = {
14 12
     }
15 13
 }
16 14
 
17
-class User extends Schwifty.Model {
18
-    static get tableName() { return pluginConfig.tableName }
19
-    static get joiSchema() {
20
-        return Joi.object({
21
-            id: Joi.number().required(),
22
-            name: Joi.string().required()
15
+
16
+/** Validator functions by request method */
17
+const validators = {
18
+    get: {
19
+        params: Joi.object({
20
+            name: Joi.string().min(3).max(11),
21
+            all: Joi.array()
23 22
         })
24 23
     }
25 24
 }
26 25
 
27
-const handlers = {
28
-    get: async request => {
26
+module.exports = {
27
+    method: 'get',
28
+    path: '/user/{name}',
29
+    // auth: 'jwt',
30
+    handler: async request => {
29 31
         try {
30 32
             /** Get the data for your endpoint */
31 33
             const { User } = request.models()
32 34
             const all = await User.query()
33 35
 
34
-            return { 
36
+            return {
35 37
                 ok: true,
36 38
                 handler: pluginConfig.handlerType,
37 39
                 data: { name: request.params.name, all },
38 40
             }
39 41
         }
40 42
         catch(err) {
41
-            return { 
43
+            return {
42 44
                 ok: false,
43 45
                 handler: pluginConfig.handlerType,
44 46
                 data: { error: err },
45 47
             }
46 48
         }
47
-    }
48
-}
49
-
50
-/** Validator functions by request method */
51
-const validators = {
52
-    get: {
53
-        params: Joi.object({
54
-            name: Joi.string().min(3).max(11),
55
-            all: Joi.array()
56
-        })
57
-    }
58
-}
59
-
60
-/** Plugin options by request method */
61
-const options = {
62
-    get: {
49
+    },
50
+    options: {
63 51
         ...pluginConfig.docs.get,
64 52
         tags: ['api'],
65 53
         validate: validators.get,
@@ -72,19 +60,5 @@ const options = {
72 60
             failAction: 'log'
73 61
         }
74 62
     }
75
-}
76 63
 
77
-module.exports = {
78
-    name: pluginConfig.name,
79
-    version: pluginConfig.version,
80
-    register: async server => {
81
-        await server.register(Schwifty)  
82
-        await server.registerModel(User)
83
-        await server.route({
84
-            method: 'get',
85
-            path: '/users/{name}',
86
-            handler: handlers.get,
87
-            options: options.get
88
-        })
89
-    }
90 64
 }

+ 96
- 0
backend/package-lock.json Ver arquivo

@@ -9,11 +9,14 @@
9 9
       "version": "1.0.0",
10 10
       "license": "UNLICENSED",
11 11
       "dependencies": {
12
+        "@hapi/glue": "^8.0.0",
12 13
         "@hapi/hapi": "^20.1.3",
13 14
         "@hapi/inert": "^6.0.3",
14 15
         "@hapi/vision": "^6.0.1",
16
+        "@hapipal/confidence": "^6.0.1",
15 17
         "@hapipal/schwifty": "^6.0.0",
16 18
         "dotenv": "^10.0.0",
19
+        "exiting": "^6.0.1",
17 20
         "hapi-swagger": "^14.1.3",
18 21
         "joi": "^17.4.0",
19 22
         "knex": "^0.21.19",
@@ -57,6 +60,18 @@
57 60
         "@hapi/hoek": "9.x.x"
58 61
       }
59 62
     },
63
+    "node_modules/@hapi/bossy": {
64
+      "version": "5.1.0",
65
+      "resolved": "https://registry.npmjs.org/@hapi/bossy/-/bossy-5.1.0.tgz",
66
+      "integrity": "sha512-sVZC6GucPaG2Pugldj476ZtGevkFCOoJSf4Ay9HJXxAOjyyBhb0AnxtxYdrf1tvTBV2hAMytV3RASQXudB3rnQ==",
67
+      "dependencies": {
68
+        "@hapi/boom": "9.x.x",
69
+        "@hapi/bounce": "2.x.x",
70
+        "@hapi/bourne": "2.x.x",
71
+        "@hapi/hoek": "9.x.x",
72
+        "@hapi/validate": "1.x.x"
73
+      }
74
+    },
60 75
     "node_modules/@hapi/bounce": {
61 76
       "version": "2.0.0",
62 77
       "resolved": "https://registry.npmjs.org/@hapi/bounce/-/bounce-2.0.0.tgz",
@@ -124,6 +139,16 @@
124 139
       "resolved": "https://registry.npmjs.org/@hapi/file/-/file-2.0.0.tgz",
125 140
       "integrity": "sha512-WSrlgpvEqgPWkI18kkGELEZfXr0bYLtr16iIN4Krh9sRnzBZN6nnWxHFxtsnP684wueEySBbXPDg/WfA9xJdBQ=="
126 141
     },
142
+    "node_modules/@hapi/glue": {
143
+      "version": "8.0.0",
144
+      "resolved": "https://registry.npmjs.org/@hapi/glue/-/glue-8.0.0.tgz",
145
+      "integrity": "sha512-dqAQ401MTDpTUnPUtUZ/RIJOE+ROTjhq1YgPeuAVMYpoYlh55PNNJq6YBDBlye5VcF9uYtL1h3VnRMZz2NSlXw==",
146
+      "dependencies": {
147
+        "@hapi/hapi": "20.x.x",
148
+        "@hapi/hoek": "9.x.x",
149
+        "@hapi/validate": "1.x.x"
150
+      }
151
+    },
127 152
     "node_modules/@hapi/hapi": {
128 153
       "version": "20.1.3",
129 154
       "resolved": "https://registry.npmjs.org/@hapi/hapi/-/hapi-20.1.3.tgz",
@@ -335,6 +360,20 @@
335 360
         "@hapi/hoek": "9.x.x"
336 361
       }
337 362
     },
363
+    "node_modules/@hapipal/confidence": {
364
+      "version": "6.0.1",
365
+      "resolved": "https://registry.npmjs.org/@hapipal/confidence/-/confidence-6.0.1.tgz",
366
+      "integrity": "sha512-bhJriclaN5W8TJG950Al/lSaej2hi6byQNUmk0JUvuB7mys7oLGUZlbEz3k73s6hF7sKChfYofvjcFr2GLQAYQ==",
367
+      "dependencies": {
368
+        "@hapi/bossy": ">=5.1.0 <6",
369
+        "@hapi/bourne": "2.x.x",
370
+        "@hapi/hoek": "9.x.x",
371
+        "joi": "17.x.x"
372
+      },
373
+      "bin": {
374
+        "confidence": "bin/confidence"
375
+      }
376
+    },
338 377
     "node_modules/@hapipal/schwifty": {
339 378
       "version": "6.0.0",
340 379
       "resolved": "https://registry.npmjs.org/@hapipal/schwifty/-/schwifty-6.0.0.tgz",
@@ -1184,6 +1223,21 @@
1184 1223
         "node": ">=4"
1185 1224
       }
1186 1225
     },
1226
+    "node_modules/exiting": {
1227
+      "version": "6.0.1",
1228
+      "resolved": "https://registry.npmjs.org/exiting/-/exiting-6.0.1.tgz",
1229
+      "integrity": "sha512-0kUQkyWTMJUZ2wKkxjducVojsL5vtDxw26q9sd07SwyWZswbHOrWN9Bs2jk9uXffatsGp2QP5tmQUYXiPi1Z2A==",
1230
+      "dependencies": {
1231
+        "@hapi/bounce": "^2.0.0",
1232
+        "@hapi/hoek": "^9.0.2"
1233
+      },
1234
+      "engines": {
1235
+        "node": ">=12.13.0"
1236
+      },
1237
+      "peerDependencies": {
1238
+        "@hapi/hapi": ">=17.9.0"
1239
+      }
1240
+    },
1187 1241
     "node_modules/expand-brackets": {
1188 1242
       "version": "2.1.4",
1189 1243
       "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
@@ -3979,6 +4033,18 @@
3979 4033
         "@hapi/hoek": "9.x.x"
3980 4034
       }
3981 4035
     },
4036
+    "@hapi/bossy": {
4037
+      "version": "5.1.0",
4038
+      "resolved": "https://registry.npmjs.org/@hapi/bossy/-/bossy-5.1.0.tgz",
4039
+      "integrity": "sha512-sVZC6GucPaG2Pugldj476ZtGevkFCOoJSf4Ay9HJXxAOjyyBhb0AnxtxYdrf1tvTBV2hAMytV3RASQXudB3rnQ==",
4040
+      "requires": {
4041
+        "@hapi/boom": "9.x.x",
4042
+        "@hapi/bounce": "2.x.x",
4043
+        "@hapi/bourne": "2.x.x",
4044
+        "@hapi/hoek": "9.x.x",
4045
+        "@hapi/validate": "1.x.x"
4046
+      }
4047
+    },
3982 4048
     "@hapi/bounce": {
3983 4049
       "version": "2.0.0",
3984 4050
       "resolved": "https://registry.npmjs.org/@hapi/bounce/-/bounce-2.0.0.tgz",
@@ -4043,6 +4109,16 @@
4043 4109
       "resolved": "https://registry.npmjs.org/@hapi/file/-/file-2.0.0.tgz",
4044 4110
       "integrity": "sha512-WSrlgpvEqgPWkI18kkGELEZfXr0bYLtr16iIN4Krh9sRnzBZN6nnWxHFxtsnP684wueEySBbXPDg/WfA9xJdBQ=="
4045 4111
     },
4112
+    "@hapi/glue": {
4113
+      "version": "8.0.0",
4114
+      "resolved": "https://registry.npmjs.org/@hapi/glue/-/glue-8.0.0.tgz",
4115
+      "integrity": "sha512-dqAQ401MTDpTUnPUtUZ/RIJOE+ROTjhq1YgPeuAVMYpoYlh55PNNJq6YBDBlye5VcF9uYtL1h3VnRMZz2NSlXw==",
4116
+      "requires": {
4117
+        "@hapi/hapi": "20.x.x",
4118
+        "@hapi/hoek": "9.x.x",
4119
+        "@hapi/validate": "1.x.x"
4120
+      }
4121
+    },
4046 4122
     "@hapi/hapi": {
4047 4123
       "version": "20.1.3",
4048 4124
       "resolved": "https://registry.npmjs.org/@hapi/hapi/-/hapi-20.1.3.tgz",
@@ -4245,6 +4321,17 @@
4245 4321
         "@hapi/hoek": "9.x.x"
4246 4322
       }
4247 4323
     },
4324
+    "@hapipal/confidence": {
4325
+      "version": "6.0.1",
4326
+      "resolved": "https://registry.npmjs.org/@hapipal/confidence/-/confidence-6.0.1.tgz",
4327
+      "integrity": "sha512-bhJriclaN5W8TJG950Al/lSaej2hi6byQNUmk0JUvuB7mys7oLGUZlbEz3k73s6hF7sKChfYofvjcFr2GLQAYQ==",
4328
+      "requires": {
4329
+        "@hapi/bossy": ">=5.1.0 <6",
4330
+        "@hapi/bourne": "2.x.x",
4331
+        "@hapi/hoek": "9.x.x",
4332
+        "joi": "17.x.x"
4333
+      }
4334
+    },
4248 4335
     "@hapipal/schwifty": {
4249 4336
       "version": "6.0.0",
4250 4337
       "resolved": "https://registry.npmjs.org/@hapipal/schwifty/-/schwifty-6.0.0.tgz",
@@ -4890,6 +4977,15 @@
4890 4977
       "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
4891 4978
       "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
4892 4979
     },
4980
+    "exiting": {
4981
+      "version": "6.0.1",
4982
+      "resolved": "https://registry.npmjs.org/exiting/-/exiting-6.0.1.tgz",
4983
+      "integrity": "sha512-0kUQkyWTMJUZ2wKkxjducVojsL5vtDxw26q9sd07SwyWZswbHOrWN9Bs2jk9uXffatsGp2QP5tmQUYXiPi1Z2A==",
4984
+      "requires": {
4985
+        "@hapi/bounce": "^2.0.0",
4986
+        "@hapi/hoek": "^9.0.2"
4987
+      }
4988
+    },
4893 4989
     "expand-brackets": {
4894 4990
       "version": "2.1.4",
4895 4991
       "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",

+ 4
- 1
backend/package.json Ver arquivo

@@ -4,18 +4,21 @@
4 4
   "description": "",
5 5
   "main": "index.js",
6 6
   "scripts": {
7
-    "start": "nodemon src/index.js",
7
+    "start": "nodemon server",
8 8
     "migrate": "knex migrate:latest",
9 9
     "test": "echo \"Error: no test specified\" && exit 1"
10 10
   },
11 11
   "author": "TOJ",
12 12
   "license": "UNLICENSED",
13 13
   "dependencies": {
14
+    "@hapi/glue": "^8.0.0",
14 15
     "@hapi/hapi": "^20.1.3",
15 16
     "@hapi/inert": "^6.0.3",
16 17
     "@hapi/vision": "^6.0.1",
18
+    "@hapipal/confidence": "^6.0.1",
17 19
     "@hapipal/schwifty": "^6.0.0",
18 20
     "dotenv": "^10.0.0",
21
+    "exiting": "^6.0.1",
19 22
     "hapi-swagger": "^14.1.3",
20 23
     "joi": "^17.4.0",
21 24
     "knex": "^0.21.19",

+ 7
- 0
backend/server/.env.sample Ver arquivo

@@ -0,0 +1,7 @@
1
+# Rename me to .env then fill me with runtime configuration and credentials
2
+# Just don't try to check me into your repo :)
3
+# Confused? See https://github.com/motdotla/dotenv
4
+#
5
+# e.g.
6
+# PORT=4000
7
+APP_SECRET=mysecret

+ 26
- 0
backend/server/index.js Ver arquivo

@@ -0,0 +1,26 @@
1
+const Glue = require('@hapi/glue');
2
+const Exiting = require('exiting');
3
+const Manifest = require('./manifest');
4
+
5
+exports.deployment = async ({ start } = {}) => {
6
+    const manifest = Manifest.get('/', process.env)
7
+    const server = await Glue.compose(manifest, { relativeTo: __dirname })
8
+
9
+    if (start) {
10
+        await Exiting.createManager(server).start()
11
+        server.log(['start'], `Server started at ${server.info.uri}`);
12
+        return server
13
+    }
14
+
15
+    await server.initialize()
16
+
17
+    return server
18
+}
19
+
20
+if (require.main === module) {
21
+    exports.deployment({ start: true })
22
+
23
+    process.on('unhandledRejection', (err) => {
24
+        throw err
25
+    })
26
+}

+ 72
- 0
backend/server/manifest.js Ver arquivo

@@ -0,0 +1,72 @@
1
+const Dotenv = require('dotenv');
2
+const Confidence = require('@hapipal/confidence');
3
+const Inert = require('@hapi/inert');
4
+const Vision = require('@hapi/vision');
5
+const Schwifty = require('@hapipal/schwifty');
6
+const HapiSwagger = require('hapi-swagger');
7
+const AppPlugin = require('../lib/plugins');
8
+// Pull .env into process.env
9
+Dotenv.config({ path: `${__dirname}/.env` });
10
+
11
+// Glue manifest as a confidence store
12
+module.exports = new Confidence.Store({
13
+    server: {
14
+        host: 'localhost',
15
+        port: {
16
+            $filter: 'NODE_ENV',
17
+            $default: {
18
+                $param: 'PORT',
19
+                $coerce: 'number',
20
+                $default: 3001
21
+            },
22
+            test: { $value: undefined }         // Let the server find an open port
23
+        },
24
+        debug: {
25
+            $filter: 'NODE_ENV',
26
+            $default: {
27
+                log: ['error', 'start'],
28
+                request: ['error']
29
+            },
30
+            production: {
31
+                request: ['implementation']
32
+            }
33
+        }
34
+    },
35
+    register: {
36
+        plugins: [
37
+            AppPlugin,
38
+            // Documentaion deps
39
+            Inert,
40
+            Vision,
41
+            {
42
+                plugin: HapiSwagger,
43
+                options: {
44
+                    info: { title: 'Test API Documentation' }
45
+                }
46
+            },
47
+            {
48
+                plugin: Schwifty,
49
+                options: {
50
+                    $filter: 'NODE_ENV',
51
+                    $default: {},
52
+                    $base: {
53
+                        migrateOnStart: true,
54
+                        knex: {
55
+                            client: 'mysql',
56
+                            useNullAsDefault: true,
57
+                            connection: {
58
+                                host : 'localhost',
59
+                                user : 'root',
60
+                                password : 'root',
61
+                                database : 'test'
62
+                            }
63
+                        }
64
+                    },
65
+                    production: {
66
+                        migrateOnStart: false
67
+                    }
68
+                }
69
+            }
70
+        ]
71
+    }
72
+});

+ 0
- 51
backend/src/index.js Ver arquivo

@@ -1,51 +0,0 @@
1
-const Hapi = require('@hapi/hapi');
2
-const Inert = require('@hapi/inert');
3
-const Vision = require('@hapi/vision');
4
-const Schwifty = require('@hapipal/schwifty');
5
-const HapiSwagger = require('hapi-swagger');
6
-
7
-const config = require('../config/dev');
8
-
9
-const AppPlugin = require('./plugins');
10
-
11
-(async () => {
12
-    const server = Hapi.server({
13
-        port: config.port,
14
-        host: config.host,
15
-        routes: {
16
-            cors: config.corsSupported
17
-        }
18
-    })
19
-
20
-    await server.register([ 
21
-        AppPlugin,
22
-        // Documentaion deps
23
-        Inert,
24
-        Vision,
25
-        {
26
-            plugin: HapiSwagger,
27
-            options: {
28
-                info: { title: 'Test API Documentation' }
29
-            }
30
-        },
31
-        // DB and model connectors
32
-        {
33
-            plugin: Schwifty,
34
-            options: {
35
-                knex: {
36
-                    client: config.dbDialect,
37
-                    useNullAsDefault: true,
38
-                    connection: {
39
-                        host : config.host,
40
-                        user : 'root',
41
-                        password : 'root',
42
-                        database : config.db
43
-                    }
44
-                }
45
-            }
46
-        }
47
-    ])
48
-
49
-    await server.start()
50
-    console.log(`Ready to go! See ${server.info.uri}`)
51
-})();

Carregando…
Cancelar
Salvar