nails-boilerplate 2.0.10 → 2.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +419 -345
- package/lib/database_connector.js +1 -0
- package/lib/model_v2.js +10 -0
- package/lib/nails.js +7 -1
- package/lib/sequelize_connector.js +4 -2
- package/package.json +6 -6
- package/templates/bin/start.sh +1 -1
- package/templates/config/db.js +6 -9
- package/templates/default/bin/promote.sh +20 -0
- package/templates/default/bin/rollout.sh +74 -0
- package/templates/default/bin/server.js +6 -0
- package/templates/default/bin/start.sh +16 -0
- package/templates/default/common/readme_fetcher.js +4 -0
- package/templates/default/config/db.js +19 -0
- package/templates/default/config/mimes.js +59 -0
- package/templates/default/config/routes.js +38 -0
- package/templates/default/config/service.js +45 -0
- package/templates/default/config/ssl/certificate.pem +22 -0
- package/templates/default/config/ssl/csr.csr +17 -0
- package/templates/default/config/ssl/key.pem +28 -0
- package/templates/default/config/ssl/private_key.pem +30 -0
- package/templates/default/config/ssl/public_key.pem +9 -0
- package/templates/default/package-lock.json +9048 -0
- package/templates/default/package.json +43 -0
- package/templates/default/public/README.xml +332 -0
- package/templates/default/public/css/styles.css +17 -0
- package/templates/default/public/download.jpg +0 -0
- package/templates/default/public/favicon.ico +0 -0
- package/templates/default/public/index.html +9 -0
- package/templates/default/public/js/client.js +1 -0
- package/templates/default/server/controllers/home_controller.js +34 -0
- package/templates/default/server/models/User.js +18 -0
- package/templates/default/server/views/home/index.ejs +14 -0
- package/templates/default/server/views/partials/javascripts.ejs +1 -0
- package/templates/default/server/views/partials/reactapp.ejs +1 -0
- package/templates/default/server/views/partials/styles.ejs +3 -0
- package/templates/default/spec/User.test.js +20 -0
- package/templates/default/spec/home_controller.test.js +28 -0
- package/templates/default/spec/setupTests.js +0 -0
- package/templates/default/src/AboutPage.jsx +9 -0
- package/templates/default/src/HomePage.jsx +9 -0
- package/templates/default/src/Layout.jsx +78 -0
- package/templates/default/src/ReadmePage.jsx +7 -0
- package/templates/default/src/app.jsx +29 -0
- package/templates/default/src/components/ReadmeLoader.jsx +13 -0
- package/templates/default/src/styles/appstyles.css +3 -0
- package/templates/default/vite.config.ts +42 -0
- package/templates/public/README.xml +72 -13
- package/templates/spec/User.test.js +1 -0
- package/templates/spec/home_controller.test.js +1 -0
- package/templates/vite.config.ts +4 -1
package/README.md
CHANGED
|
@@ -1,345 +1,419 @@
|
|
|
1
|
-
# Nails-Boilerplate: A Node Webservice Framework
|
|
2
|
-
|
|
3
|
-
This framework is designed to provide a lightweight, configurable MVC backend
|
|
4
|
-
for node developers. With minimal dependencies, Nails offers a greater
|
|
5
|
-
syntactical familiarity than php alongside the creative freedom of well developed
|
|
6
|
-
server framework solutions like Rails and Django.
|
|
7
|
-
|
|
8
|
-
This boilerplate offers the basic necessities to get your MVC site off the ground.
|
|
9
|
-
The modules used in Nails Boilerplate can be easily extended to produce the custom
|
|
10
|
-
functionality to fit your needs, and you are encouraged to do so.
|
|
11
|
-
|
|
12
|
-
## Install
|
|
13
|
-
|
|
14
|
-
```
|
|
15
|
-
sudo npm install -g nails-boilerplate
|
|
16
|
-
|
|
17
|
-
nails init <app_name>
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
This will initialize a barebones app in the directory of the same name. Take a
|
|
21
|
-
look at the self-documented config files and example controller and view before
|
|
22
|
-
getting started. Additional controllers and views will automatically be imported
|
|
23
|
-
into nails. Now just hook the new controllers in with some new routes and you're
|
|
24
|
-
off to a good start.
|
|
25
|
-
|
|
26
|
-
```
|
|
27
|
-
cd app_name
|
|
28
|
-
|
|
29
|
-
npm install
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Getting to know your Nails service
|
|
35
|
-
|
|
36
|
-
For your convenience, here is a quick outline of the main components of a nails service.
|
|
37
|
-
Remember: each object comes with an example file to use for reference when building your service.
|
|
38
|
-
|
|
39
|
-
### Config
|
|
40
|
-
Your configuration files are stored in app_name/config/. There are three default config files:
|
|
41
|
-
|
|
42
|
-
```
|
|
43
|
-
service.js
|
|
44
|
-
routes.js
|
|
45
|
-
db.js
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
Each default config file is annotated with comments documenting each field to
|
|
49
|
-
help you tailor your service to your needs.
|
|
50
|
-
|
|
51
|
-
#### service.js
|
|
52
|
-
service.js contains information necessary to run your server. By default, it
|
|
53
|
-
specifies the port and the location of important libraries.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
PORT:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
*
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
**
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
* *
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
`
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
//
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
// Routes requests to /
|
|
203
|
-
['get', '/
|
|
204
|
-
//
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
* **
|
|
236
|
-
the
|
|
237
|
-
* **
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
Params
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
```js
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
1
|
+
# Nails-Boilerplate: A Node Webservice Framework
|
|
2
|
+
|
|
3
|
+
This framework is designed to provide a lightweight, configurable MVC backend
|
|
4
|
+
for node developers. With minimal dependencies, Nails offers a greater
|
|
5
|
+
syntactical familiarity than php alongside the creative freedom of well developed
|
|
6
|
+
server framework solutions like Rails and Django.
|
|
7
|
+
|
|
8
|
+
This boilerplate offers the basic necessities to get your MVC site off the ground.
|
|
9
|
+
The modules used in Nails Boilerplate can be easily extended to produce the custom
|
|
10
|
+
functionality to fit your needs, and you are encouraged to do so.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
sudo npm install -g nails-boilerplate
|
|
16
|
+
|
|
17
|
+
nails init <app_name>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
This will initialize a barebones app in the directory of the same name. Take a
|
|
21
|
+
look at the self-documented config files and example controller and view before
|
|
22
|
+
getting started. Additional controllers and views will automatically be imported
|
|
23
|
+
into nails. Now just hook the new controllers in with some new routes and you're
|
|
24
|
+
off to a good start.
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
cd app_name
|
|
28
|
+
|
|
29
|
+
npm install
|
|
30
|
+
|
|
31
|
+
npm start
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Getting to know your Nails service
|
|
35
|
+
|
|
36
|
+
For your convenience, here is a quick outline of the main components of a nails service.
|
|
37
|
+
Remember: each object comes with an example file to use for reference when building your service.
|
|
38
|
+
|
|
39
|
+
### Config
|
|
40
|
+
Your configuration files are stored in app_name/config/. There are three default config files:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
service.js
|
|
44
|
+
routes.js
|
|
45
|
+
db.js
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Each default config file is annotated with comments documenting each field to
|
|
49
|
+
help you tailor your service to your needs.
|
|
50
|
+
|
|
51
|
+
#### service.js
|
|
52
|
+
service.js contains information necessary to run your server. By default, it
|
|
53
|
+
specifies the port and the location of important libraries.
|
|
54
|
+
```js
|
|
55
|
+
export default {
|
|
56
|
+
...
|
|
57
|
+
SERVER_ROOT: "/path/to/my/nails/service",
|
|
58
|
+
PORT: 3333,
|
|
59
|
+
SSL_PORT: 3334,
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
While most of these values don't need to be changed, feel free to add custom
|
|
64
|
+
fields. The resulting config will be available to your service through the nails
|
|
65
|
+
module:
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
import nails from 'nails-boilerplate';
|
|
69
|
+
|
|
70
|
+
const service_config = nails.config
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
If the config contains a custom field,
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
export default {
|
|
77
|
+
...
|
|
78
|
+
PORT: 3000,
|
|
79
|
+
yourCustomField: 'yourCustomValue'
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
then `service_config.yourCustomField` as defined above will be equal to
|
|
84
|
+
`'yourCustomValue'`.
|
|
85
|
+
|
|
86
|
+
#### routes.js
|
|
87
|
+
*routes.js* is a list defining mappings from a url path to a *Controller* and
|
|
88
|
+
*Action*. Each entry in the list is an array with three elements:
|
|
89
|
+
`[method, path, options]`
|
|
90
|
+
|
|
91
|
+
**method** is a string defining the HTTP request method of the route. Supported
|
|
92
|
+
methods are *GET*, *PUT*, *POST*, *DELETE*, and *ALL*. All is a special case
|
|
93
|
+
which matches all HTTP request methods. Lastly, *WS* routes will handle WebSocket connections.
|
|
94
|
+
|
|
95
|
+
**path** is a string or regular expression which matches the path of the
|
|
96
|
+
incoming request. If *path* is a string, then the request must match exactly*.
|
|
97
|
+
You can use route parameters to dynamically match parts of the path and assign
|
|
98
|
+
them to the *params* object. For example, if you define a route with the path:
|
|
99
|
+
`'/users/:userId'`
|
|
100
|
+
and your service receives a request with the path:
|
|
101
|
+
`'/users/777'`
|
|
102
|
+
then *userId* will be set in the params object:
|
|
103
|
+
```js
|
|
104
|
+
{ userId: 777 }
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
You can define *:controller* and *:action* as route parameters as well. Not only
|
|
108
|
+
will those values be set in the params object, but the request will be routed
|
|
109
|
+
to the matching controller and action. See
|
|
110
|
+
[express routes][express_routing_docs] for more information on how route
|
|
111
|
+
parameters work.
|
|
112
|
+
|
|
113
|
+
\*requests for static assets will only match the prefix of the path.
|
|
114
|
+
|
|
115
|
+
**options** is a JSON object which modifies how the request will be routed:
|
|
116
|
+
* *controller* a String indicating the controller to route to.
|
|
117
|
+
* *action* a String indicating the action to route to.
|
|
118
|
+
* *json* a boolean indicating whether to render a JSON response rather than an
|
|
119
|
+
HTML response. If true, nails will not attempt to render a view for this
|
|
120
|
+
route. Instead, your service will respond with JSON for this route.
|
|
121
|
+
* *public* a boolean indicating whether this route is for static assets. If
|
|
122
|
+
true, the router will only attempt to match the prefix of the request path.
|
|
123
|
+
The child portion of the path will be forwarded to the *public/* folder in
|
|
124
|
+
your service directory. For route:
|
|
125
|
+
`['GET', '/public_url_path', {public: true}]`
|
|
126
|
+
if your service receives a request to:
|
|
127
|
+
`/public_url_path/js/index.js`
|
|
128
|
+
then the response will be the file:
|
|
129
|
+
`your_service_root_path/public/js/index.js`
|
|
130
|
+
* *0, 1, 2...* a string which gives regex captures named keys in the params
|
|
131
|
+
object. This will give your regex captures more meaningful named keys rather
|
|
132
|
+
than indices. You can name your regex captures "controller" and/or "action"
|
|
133
|
+
to dynamically route your request to the appropriate handler.
|
|
134
|
+
|
|
135
|
+
#### db.js
|
|
136
|
+
|
|
137
|
+
Quickly configure your database connection here. Nails comes pre-configured to
|
|
138
|
+
use the sequelize connector, giving your models sequelize support. The initial setup
|
|
139
|
+
uses a *sqlite3* database file `config/development.db` and an in-memory database in the test environment. Change the address to change the location and
|
|
140
|
+
version of your desired sql database. Check out [Sequelize](https://sequelize.org)
|
|
141
|
+
for more info.
|
|
142
|
+
|
|
143
|
+
Alternatively, you can configure a connection to MongoDB using the mongoose_connector.js.
|
|
144
|
+
If enabled, models will accept [Mongoose](https://mongoosejs.com/docs/) schemas and will
|
|
145
|
+
be backed by the desired MongoDB. Consider using the in-memory DB during development.
|
|
146
|
+
|
|
147
|
+
## Controller
|
|
148
|
+
|
|
149
|
+
Controllers are defined in app/controllers/. Each controller module should
|
|
150
|
+
define a Controller subclass. The name will be used to match routes defined in
|
|
151
|
+
config/routes.js for incoming requests. Methods on the controller can be used as
|
|
152
|
+
actions, receiving **params**, **request**, and **response** as arguments.
|
|
153
|
+
|
|
154
|
+
For Example:
|
|
155
|
+
``` js
|
|
156
|
+
// const Controller = requre("nails-boilerplate").Controller
|
|
157
|
+
import nails from 'nails-boilerplate';
|
|
158
|
+
|
|
159
|
+
class HomeController extends nails.Controller {
|
|
160
|
+
index(params, request, response) {
|
|
161
|
+
// default action
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
signin(params, request, response) {
|
|
165
|
+
// does something then renders a view
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
export default HomeController;
|
|
169
|
+
|
|
170
|
+
function helperMethod() {
|
|
171
|
+
// does something but does not have access to response
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
defines a controller which will match any route to *home#\<action\>*. **index**
|
|
176
|
+
and **signin** are actions which can be used to render a response to the client.
|
|
177
|
+
|
|
178
|
+
### Local Routes
|
|
179
|
+
|
|
180
|
+
You can define a local routing table directly in the controller.
|
|
181
|
+
Local routes take precidence over global routes. All local routes
|
|
182
|
+
are prefixed with the controller name unless they start with '/'.
|
|
183
|
+
For example, in HomeController the following route:
|
|
184
|
+
|
|
185
|
+
`["get", "data", {action: 'getData', json: true}],`
|
|
186
|
+
|
|
187
|
+
will accept GET requests to /home/data and respond with the json
|
|
188
|
+
object returned by the getData function. If the route is changed to:
|
|
189
|
+
|
|
190
|
+
`["get", "/data", {action: 'getData', json: true}],`
|
|
191
|
+
|
|
192
|
+
it will accept GET requests to /data instead. All local routes are
|
|
193
|
+
implicitly routed to their respective parent controllers.
|
|
194
|
+
|
|
195
|
+
```js
|
|
196
|
+
export default class UsersController extends nails.Controller {
|
|
197
|
+
routes = [
|
|
198
|
+
// Routes requests to /absolute/path
|
|
199
|
+
['get', '/absolute/path', {action: 'actionA'}],
|
|
200
|
+
// Routes requests to /users/relative/path
|
|
201
|
+
['get', './relative/path', {action: 'actionB'}],
|
|
202
|
+
// Routes requests to /users/relative/path
|
|
203
|
+
['get', 'relative/path', {action: 'actionB'}],
|
|
204
|
+
// If no action is provided, the last path segment
|
|
205
|
+
// is used as the action name.
|
|
206
|
+
['get', 'actionC']
|
|
207
|
+
]
|
|
208
|
+
|
|
209
|
+
// Handles requests to /absolute/path
|
|
210
|
+
actionA(request, response, params) {}
|
|
211
|
+
|
|
212
|
+
// Handles requests to /users/relative/path
|
|
213
|
+
actionB(request, response, params) {}
|
|
214
|
+
|
|
215
|
+
// Handles requests to /users/actionC
|
|
216
|
+
actionC(request, response, params) {}
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Actions
|
|
221
|
+
Actions are used to define how nails should respond to an incoming request.
|
|
222
|
+
If no action has been defined for a route, nails will default to the index
|
|
223
|
+
action.*
|
|
224
|
+
|
|
225
|
+
For example, HomeController#index will attempt to render the view defined in
|
|
226
|
+
//app/views/home/index.jsx
|
|
227
|
+
|
|
228
|
+
The view each action searches for will always follow the pattern:
|
|
229
|
+
//app/views/*\[controller name\]*/*\[action name\]*.jsx
|
|
230
|
+
|
|
231
|
+
The file extension may differ based on which template engine you configure.
|
|
232
|
+
|
|
233
|
+
Depending on the return value, Nails will pass a different set of parameters to
|
|
234
|
+
the view engine:
|
|
235
|
+
* **undefined** If there is no return statement in the action, Nails will pass
|
|
236
|
+
the *params* obect to the rendering engine.
|
|
237
|
+
* **Object** If a generic object is returned, Nails will attempt to autorender
|
|
238
|
+
the view immediately using the returned object instead of *params*.**
|
|
239
|
+
* **Promise** If a promise is returned, Nails will wait to autorender the view
|
|
240
|
+
until the *Promise* resolves. If it resolves with no return value, the view
|
|
241
|
+
is rendered using *params*. Otherwise, the view is rendered using the
|
|
242
|
+
resolved value of the *Promise*\**
|
|
243
|
+
|
|
244
|
+
\*If a response has already been sent to the client, autorender will be skipped.
|
|
245
|
+
\*\*For JSON routes, the returned object will be rendered as stringified JSON.
|
|
246
|
+
|
|
247
|
+
#### Params
|
|
248
|
+
Params is a generic JSON object which represents the request details. Usually,
|
|
249
|
+
Params will correspond to the query portion of your request.
|
|
250
|
+
|
|
251
|
+
For example, a GET request to *//some/path?item0=a&item1=b* will generate the
|
|
252
|
+
params object:
|
|
253
|
+
``` js
|
|
254
|
+
{
|
|
255
|
+
item0: "a",
|
|
256
|
+
item1: "b"
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
#### Request
|
|
261
|
+
An [express Request object][express_request_docs].
|
|
262
|
+
|
|
263
|
+
#### Response
|
|
264
|
+
The response object provided by *express.js*. The *#render()* method has been
|
|
265
|
+
overridden to allow for the rendering of views by name.
|
|
266
|
+
|
|
267
|
+
#### JSON Actions
|
|
268
|
+
JSON actions only return JSON objects in the response instead of text or HTML. These actions are ideal for building an API Server. There are three ways to designate JSON Actions:
|
|
269
|
+
|
|
270
|
+
##### Express Response Object
|
|
271
|
+
```js
|
|
272
|
+
response.json({your: 'jsonresponse'})
|
|
273
|
+
```
|
|
274
|
+
Simply use the express Response object directly
|
|
275
|
+
|
|
276
|
+
##### JSON Routes
|
|
277
|
+
You can configure an individual route to respond with JSON by setting the `json` option to `true`.
|
|
278
|
+
```js
|
|
279
|
+
['get', '/your/json/route', {json: true}],
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
##### API Controllers
|
|
283
|
+
By setting `json` to `true`, all actions in a controller will respond with JSON.
|
|
284
|
+
|
|
285
|
+
```js
|
|
286
|
+
class YourApiController extends nails.Controller {
|
|
287
|
+
json = true;
|
|
288
|
+
|
|
289
|
+
action(params, request, response) {
|
|
290
|
+
return {your: 'jsonresponse'};
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## Model
|
|
296
|
+
|
|
297
|
+
Models are programmatic representations of data you wish to persist in a
|
|
298
|
+
database. The constructor for Model accepts two arguments: the `modelName` and an
|
|
299
|
+
`options` object which is passed to the database connector module.
|
|
300
|
+
|
|
301
|
+
### Sequelize Models
|
|
302
|
+
|
|
303
|
+
Sequelize models are subclasses of
|
|
304
|
+
[Sequelize Models][sequelize_model_docs], and come with the `count()`, `findAll()`,
|
|
305
|
+
and `create()` methods, to name a few. You can define your own models by
|
|
306
|
+
extending an instance of the `Model` class provided by Nails:
|
|
307
|
+
|
|
308
|
+
```js
|
|
309
|
+
// const Model = require("nails-boilerplate").Model;
|
|
310
|
+
import nails from 'nails-boilerplate';
|
|
311
|
+
import {DataTypes} from 'sequelize';
|
|
312
|
+
schema = {
|
|
313
|
+
name: {type: DataTypes.STRING, allowNull: false},
|
|
314
|
+
email: {type: DataTypes.STRING, allowNull: false}
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
options = {
|
|
318
|
+
indexes: [
|
|
319
|
+
{
|
|
320
|
+
unique: true,
|
|
321
|
+
fields: ['email'],
|
|
322
|
+
},
|
|
323
|
+
],
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
export default class User extends new Model("User", {schema, options}) {
|
|
327
|
+
someHelperMethod() {
|
|
328
|
+
// This method will be available on all instances of User and is
|
|
329
|
+
// an ideal way to simplify data manipulation.
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Mongoose Models
|
|
336
|
+
Mongoose models are subclasses of
|
|
337
|
+
[Mongoose Models][mongoose_model_docs], and come with the `save()`, `find()`,
|
|
338
|
+
and `where()` methods, to name a few. You can define your own models by
|
|
339
|
+
extending an instance of the `Model` class provided by Nails:
|
|
340
|
+
|
|
341
|
+
``` js
|
|
342
|
+
// const Model = require("nails-boilerplate").Model;
|
|
343
|
+
import nails from 'nails-boilerplate';
|
|
344
|
+
const userSchema = {name: String, email: String};
|
|
345
|
+
export default class User extends new Model("User", {schema: userSchema}) {
|
|
346
|
+
// Define your helper methods here
|
|
347
|
+
};
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
The `schema` option for Mongoose Models accepts a schema field that is used
|
|
351
|
+
to define how documents are stored in MongoDB.
|
|
352
|
+
|
|
353
|
+
### Model Library
|
|
354
|
+
Nails will store all instantialized models in a single object called `MODELS`. By accessing these models via the library, you can avoid circular dependencies and ensure all models have been fully initialized.
|
|
355
|
+
|
|
356
|
+
```js
|
|
357
|
+
class User extends nails.Model("User", {schema, options}) {
|
|
358
|
+
// A helper method which depends on anoher model using the
|
|
359
|
+
// Nails Model Library rather than directly importing the model.
|
|
360
|
+
async findFriends() {
|
|
361
|
+
return nails.MODELS.Friend.findByUserId(this.id);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
This design pattern is not always necessary, but will help avoid circular dependencies.
|
|
366
|
+
|
|
367
|
+
### Database Connectors
|
|
368
|
+
|
|
369
|
+
Database connectors are intermediaries which define how a Model interacts with
|
|
370
|
+
a database. Database connector modules need to export two methods:
|
|
371
|
+
* _connect(db_config)_ uses the db config defined in *db.js* to connect to
|
|
372
|
+
a database. This function will be called once by Nails.
|
|
373
|
+
* _generateModelSuperclass(name, options)_ uses the provided Model name and
|
|
374
|
+
options to generate a Model prototype for use as an interface. A Model
|
|
375
|
+
interface is generated for each of your models, allowing them to interact with
|
|
376
|
+
a database. Ideally, interfaces will define save() and find() methods, but
|
|
377
|
+
these methods and their implementations are up to the individual connector.
|
|
378
|
+
|
|
379
|
+
## View
|
|
380
|
+
Views are dynamic templates used to render an html response for a browser.
|
|
381
|
+
Nails comes prepackaged with EJS templates.
|
|
382
|
+
If no template engine is specified in the service config, Nails will default to
|
|
383
|
+
EJS. Nails will always attempt to autorender your views unless a response has
|
|
384
|
+
already been sent to the client.
|
|
385
|
+
|
|
386
|
+
### React Frontend with Vite
|
|
387
|
+
|
|
388
|
+
This project uses Vite to build the frontend React application. The source files for the React app are located in the `src` directory. The server is pre-configured to serve the built React application.
|
|
389
|
+
|
|
390
|
+
To rebuild the frontend application, you can run the following command:
|
|
391
|
+
|
|
392
|
+
```bash
|
|
393
|
+
npm run build
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
## Testing
|
|
397
|
+
|
|
398
|
+
This project uses [Vitest](https://vitest.dev/) for running tests. All test files are located in the `spec` folder. To run the tests, use the following command:
|
|
399
|
+
|
|
400
|
+
```bash
|
|
401
|
+
npm test
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
For more information on how to write tests with Vitest, please refer to the [official documentation](https://vitest.dev/guide/).
|
|
405
|
+
|
|
406
|
+
Stay tuned as nails evolves:
|
|
407
|
+
|
|
408
|
+
* Server/client redirects
|
|
409
|
+
* Custom Request middleware
|
|
410
|
+
* Fancy Logging
|
|
411
|
+
* Sessions
|
|
412
|
+
* Server security
|
|
413
|
+
|
|
414
|
+
Enjoy! Feature requests, bug reports, and comments are welcome on github.
|
|
415
|
+
|
|
416
|
+
[express_routing_docs]: https://expressjs.com/en/guide/routing.html
|
|
417
|
+
[express_request_docs]: https://expressjs.com/en/5x/api.html#req
|
|
418
|
+
[mongoose_model_docs]: https://mongoosejs.com/docs/api/model.html
|
|
419
|
+
[sequelize_model_docs]: https://sequelize.org/docs/v6/core-concepts/model-basics/
|