1 | # Backrest [![npm](https://img.shields.io/npm/v/backrest.svg)](https://www.npmjs.com/package/backrest)
|
2 |
|
3 | Rails like Node framework to create simple, pure backend APIs.
|
4 |
|
5 | ## CLI
|
6 |
|
7 | ### Install
|
8 |
|
9 | `npm i backrest -g`
|
10 |
|
11 | ### Usage
|
12 |
|
13 | ```
|
14 | ❯ backrest help
|
15 |
|
16 | Usage: backrest [options] [command]
|
17 |
|
18 |
|
19 | Commands:
|
20 |
|
21 | init|i <name> create blank Backrest template
|
22 | start|s start the server
|
23 | stop stop the server
|
24 | help [cmd] display help for [cmd]
|
25 |
|
26 | Options:
|
27 |
|
28 | -h, --help output usage information
|
29 | ```
|
30 |
|
31 | ### Development
|
32 |
|
33 | Start the project and watch for file changes.
|
34 |
|
35 | `backrest s -w`
|
36 |
|
37 | ### Production
|
38 |
|
39 | Start the project in a background process.
|
40 |
|
41 | `NODE_ENV=production backrest s -d`
|
42 |
|
43 | To stop:
|
44 |
|
45 | `backrest stop`
|
46 |
|
47 | ## Package Module
|
48 |
|
49 | This project uses [ExpressJS](http://expressjs.com/) behind the scenes. Please visit their website to have a better understanding of how routing and requests work.
|
50 |
|
51 | ### Routing
|
52 |
|
53 | Creating routes are meant to be easy with a very simple structure.
|
54 | They are defined using an array format to allow defining route precedence.
|
55 | Former routes will take precedence over latter ones if they both match the requested URL.
|
56 |
|
57 | Location: `config/routes.js`
|
58 |
|
59 | Each route will need a couple things:
|
60 |
|
61 | * An action verb
|
62 | * URL end point
|
63 | * Controller name
|
64 | * Action name
|
65 |
|
66 | The layout of each route will be in the following format:
|
67 |
|
68 | ```
|
69 | ['{verb} {url}', '({controller}#){action}' || [{subroutes}]]
|
70 | ```
|
71 |
|
72 | * **verb**
|
73 | * `get`, `post`, `patch`, `put`, or `delete`
|
74 | * **url**
|
75 | * URL end point that begins at root (leading `/` is optional)
|
76 | * URLs are allowed to have parameters defined denoted using a colon (`:`)
|
77 | * Example: `users/:id`
|
78 | * **controller** (optional)
|
79 | * The controller name is the prefix of the file it is defined in. e.g. `users` for `app/controllers/users_controller.js`
|
80 | * May be omitted to set the controller name to the first part of the route **url**. e.g. `users` for `['get users/all', 'getAll']`
|
81 | * **action**
|
82 | * This is the name of the method to call defined in the controller.
|
83 | * **subroutes**
|
84 | * Subroutes may be defined instead of a controller and action.
|
85 |
|
86 | There are a couple ways to define how routes work:
|
87 |
|
88 | 1. Inline:
|
89 |
|
90 | ```javascript
|
91 | module.exports = [
|
92 | ['get users/all', 'users#getAll']
|
93 | ]
|
94 | ```
|
95 |
|
96 | 1. With subroutes:
|
97 |
|
98 | ```javascript
|
99 | module.exports = [
|
100 | ['users', [
|
101 | ['get all', 'users#getAll']
|
102 | ]]
|
103 | ]
|
104 | ```
|
105 |
|
106 | 1. Exclude controller name:
|
107 |
|
108 | If the root of the URL is the same as the controller name, you may exclude it in the route definition. Both of the following point to the `users` controller:
|
109 | ```javascript
|
110 | module.exports = [
|
111 | ['get users/all', 'getAll'],
|
112 | ['users', [
|
113 | ['get all', 'getAll']
|
114 | ]]
|
115 | ]
|
116 | ```
|
117 |
|
118 | 1. [With `resources` verb](#resources):
|
119 |
|
120 | ```javascript
|
121 | module.exports = [
|
122 | ['resources users']
|
123 | ]
|
124 | ```
|
125 |
|
126 | #### Resources
|
127 |
|
128 | Auto generate resource routes with the `['resources {name}']` route format.
|
129 |
|
130 | The **name** of the resource must be a single word.
|
131 |
|
132 | The following routes will be generated:
|
133 |
|
134 | ```javascript
|
135 | [{name}, [
|
136 | [`get /`, 'fetchAll'],
|
137 | [`get /:id`, 'fetch'],
|
138 | [`post /`, 'create'],
|
139 | [`patch /:id`, 'update'],
|
140 | [`put /:id`, 'replace'],
|
141 | [`delete /:id`, 'destroy']
|
142 | ]]
|
143 | ```
|
144 |
|
145 | ### Controllers
|
146 |
|
147 | Controllers are used to define the actions to take place on each request.
|
148 |
|
149 | They should be saved to the `app/controllers/` directory with the suffix `_controller.js` attached. For example `app/controllers/users_controller.js`
|
150 |
|
151 | #### Actions
|
152 |
|
153 | Each action function will have 2 arguments. `req` and `res` standing for `request` and `response` respectfully.
|
154 |
|
155 | ```javascript
|
156 | getAll(req, res) {
|
157 |
|
158 | }
|
159 | ```
|
160 |
|
161 | #### Before Filters
|
162 |
|
163 | Each before filter function will have 3 arguments: `req`, `res`, and `next`
|
164 |
|
165 | Before filters can do perform the following tasks:
|
166 | * Execute any code.
|
167 | * Make changes to the request and the response objects.
|
168 | * End the request-response cycle.
|
169 | * Call the next before filter or action function for the request.
|
170 |
|
171 | ##### Definition
|
172 |
|
173 | Before filters are set in the controller by calling `this.beforeFilter[s]` with object[s] from within the controller `constructor`.
|
174 | Each object should contain at least 1 property called `action` which is the reference to or string value of the function to be called.
|
175 | Other properties to be used are `only` OR `except` which tell the router which actions to call the before filters for.
|
176 | `only` and `except` can be either a string or array of strings denoting the name of the actions.
|
177 |
|
178 | Filters can also be skipped by calling `this.skipBeforeFilter[s]` with the same rules defined above
|
179 |
|
180 | Filters are executed in the same order they are defined.
|
181 |
|
182 | Examples:
|
183 |
|
184 | ```javascript
|
185 | constructor() {
|
186 | super()
|
187 |
|
188 | this.beforeFilters([
|
189 | { action: '_checkAdmin', except: ['getPublic'] },
|
190 | { action: this._sayHello }
|
191 | ])
|
192 | this.skipBeforeFilter(
|
193 | { action: this._checkAdmin, only: ['getPublic'] }
|
194 | )
|
195 | }
|
196 |
|
197 | _checkAdmin(req, res, next) {
|
198 | let user = getUserById(req.params.id)
|
199 | if(user.isAdmin)
|
200 | next() // Continues to the next filter in the chain.
|
201 | else
|
202 | res // Otherwise, respond to request with error.
|
203 | .status(401)
|
204 | .send('User is not admin. Action is prohibited.')
|
205 | }
|
206 |
|
207 | _sayHello(req, res, next) {
|
208 | console.log('Hello!')
|
209 | next()
|
210 | }
|
211 | ```
|
212 |
|
213 | ### Initializers
|
214 |
|
215 | Initializers are used to run scripts before the server is started. To create an initializer script, create a file with any name in the directory `config/initializers/`
|