1 | # loopback-with-admin
|
2 |
|
3 | Run loopback server easier.
|
4 |
|
5 | # features
|
6 | - passing model definitions via arguments (no need to generate JSON files)
|
7 | - switching environment easier
|
8 | - admin role, which can access to all endpoints
|
9 | - easier ACL settings
|
10 | - easier custom role settings
|
11 | - easier push notification settings
|
12 |
|
13 |
|
14 | # install
|
15 |
|
16 | ```bash
|
17 | npm install loopback-with-admin
|
18 | ```
|
19 |
|
20 | # usage
|
21 | ## simplest run
|
22 |
|
23 | ```javascript
|
24 | // model definitions
|
25 | // see "models" section for more detail
|
26 | const models = {
|
27 | user: {
|
28 | base: 'User'
|
29 | }
|
30 | };
|
31 |
|
32 | require('loopback-with-admin').run(models).then(lbInfo => {
|
33 | // see "LoopbackInfo" section for more detail
|
34 | console.log(lbInfo.getURL()) // loopback api root
|
35 | console.log(lbInfo.getAdminTokens()) // access tokens of admin
|
36 | })
|
37 | ```
|
38 |
|
39 | Or more strictly, pass `models` like
|
40 |
|
41 | ```javascript
|
42 | require('loopback-with-admin').run({models: models})
|
43 | ```
|
44 |
|
45 |
|
46 | ## run with config dir
|
47 |
|
48 | before running, you can prepare a directory which contains custom config information.
|
49 |
|
50 | ```text
|
51 | (config-dir) # any name is acceptable
|
52 | |-- common
|
53 | | |-- server.coffee
|
54 | |-- development
|
55 | | `-- datasources.coffee
|
56 | `-- production
|
57 | `-- datasources.coffee
|
58 | ```
|
59 |
|
60 | ```javascript
|
61 | const lbWithAdmin = require('loopback-with-admin')
|
62 | const configDir = '/path/to/config-dir'
|
63 |
|
64 | lbWithAdmin.run({models: models}, configDir).then(lbInfo => {
|
65 | // loopback started with the config
|
66 | })
|
67 |
|
68 |
|
69 | ```
|
70 | See "configs" section for more details.
|
71 |
|
72 |
|
73 | ## run with config object
|
74 |
|
75 | ```javascript
|
76 |
|
77 | const lbWithAdmin = require('loopback-with-admin')
|
78 | const config = {server: {port: 3001}}
|
79 | lbWithAdmin.run({models: models}, config)
|
80 | ```
|
81 |
|
82 | ## switching environment
|
83 |
|
84 | ```javascript
|
85 |
|
86 | const configDir = '/path/to/config-dir'
|
87 |
|
88 | require('loopback-with-admin').run({models: models}, configDir, {env: 'production'})
|
89 | ```
|
90 | env is set following the rules.
|
91 |
|
92 | - uses the passed value if exists
|
93 | - uses NODE_ENV if exists
|
94 | - default value is 'development'
|
95 |
|
96 |
|
97 | When your config dir is
|
98 |
|
99 | ```text
|
100 | (config-dir) # any name is acceptable
|
101 | |-- common
|
102 | | |-- server.coffee
|
103 | |-- development
|
104 | | `-- datasources.coffee
|
105 | |-- local
|
106 | | `-- datasources.coffee
|
107 | |-- production
|
108 | | `-- datasources.coffee
|
109 | ```
|
110 |
|
111 |
|
112 | and launching script like
|
113 |
|
114 | ```bash
|
115 | $ NODE_ENV=local node app.js
|
116 | ```
|
117 | then, loopback-with-admin selects configs in "local" directory.
|
118 |
|
119 |
|
120 |
|
121 | # model definitions
|
122 |
|
123 | ```javascript
|
124 | const models = {
|
125 | player: { // model name
|
126 | base: 'User', // following loopback model definition
|
127 | aclType: 'admin' // only 'aclType' is the specific property for loopback-with-admin
|
128 | },
|
129 |
|
130 | instrument: { // another model
|
131 | aclType: 'owner-read'
|
132 | }
|
133 | }
|
134 |
|
135 | require('loopback-with-admin').run({models: models})
|
136 | ```
|
137 |
|
138 | - Models should be the same format as [loopback model definition](http://docs.strongloop.com/display/public/LB/Customizing+models) except `aclType` value.
|
139 | - `name` is automatically set from definition information.
|
140 | - `plural` is set to **the same value as the name** unless you set manually.
|
141 |
|
142 |
|
143 | ## aclType for easier ACL settings
|
144 | `aclType` is prepared for defining complicated acls easier.
|
145 | loopback-with-admin generates acls from aclType with the following rules.
|
146 |
|
147 | aclType | meaning
|
148 | ----------------------|-----------------------------------------------------
|
149 | admin | only admin can CRUD the model (_default_)
|
150 | owner | the owner of the model can CRUD
|
151 | public-read | everyone can READ the model and admin can CRUD
|
152 | member-read | authenticated users can READ the model and admin can CRUD
|
153 | public-read-by-owner | CRUD by the owner, and read by everyone
|
154 | member-read-by-owner | CRUD by the owner, and read by authenticated users
|
155 | none | everyone can CRUD the model
|
156 |
|
157 | ### more detailed settings
|
158 |
|
159 | ```javascript
|
160 | const models = {
|
161 | player: {
|
162 | base: 'User',
|
163 | aclType: {
|
164 | owner: 'rwx',
|
165 | member: 'r'
|
166 | }
|
167 | }
|
168 | }
|
169 | ```
|
170 |
|
171 | aclType can be an object, whose key contains the following roles.
|
172 |
|
173 | - owner: `$owner` role in LoopBack
|
174 | - member: `$authenticated` role in LoopBack
|
175 | - public: `$everyone` role in LoopBack
|
176 | - [custom roles] : see `custom roles` section.
|
177 |
|
178 | The values of the keys are `rwx`, which is the same as Unix permission.
|
179 | `x` here means `EXECUTE` accessType in LoopBack.
|
180 |
|
181 |
|
182 | See loopback roles for instructions.
|
183 | https://docs.strongloop.com/display/public/LB/Defining+and+using+roles
|
184 |
|
185 | ### custom roles
|
186 | You can define custom roles like the following code.
|
187 |
|
188 | ```javascript
|
189 | const customRoles = {
|
190 | 'doctor': '/path/to/doctor-role.js',
|
191 | 'patient': '/path/to/patient-role.js'
|
192 | }
|
193 |
|
194 | require('loopback-with-admin').run({models: models, customRoles: customRoles})
|
195 | ```
|
196 |
|
197 | #### role-defining JS file
|
198 |
|
199 | In the file, you must export a function, which will be passed to the 2nd argument of `Role.registerResolver` in LoopBack.
|
200 |
|
201 | See how to define custom roles in LoopBack.
|
202 | https://docs.strongloop.com/display/public/LB/Defining+and+using+roles
|
203 |
|
204 | Example:
|
205 |
|
206 | ```javascript
|
207 |
|
208 | module.exports = function(role, context, cb) {
|
209 | var app = this // `app` can be acquired via `this`
|
210 |
|
211 | function reject(err) {
|
212 | if (err) { return cb(err) }
|
213 | cb(null, false)
|
214 | }
|
215 |
|
216 | if (context.modelName !== 'patient') { return reject() }
|
217 |
|
218 | var userId = context.accessToken.userId
|
219 | if (!userId || userId === context.modelId) {
|
220 | return reject()
|
221 | }
|
222 |
|
223 | cb(null, true) // is in role
|
224 | ```
|
225 |
|
226 |
|
227 | # admin role
|
228 | **`admin` role is the role with which every REST APIs are available**.
|
229 | The role and one user with it are automatically generated at boot phase.
|
230 |
|
231 | ## admin access tokens
|
232 | To be `admin`, you need to know its access tokens. The following code can get those.
|
233 |
|
234 | ```javascript
|
235 | require('loopback-with-admin').run(models, config).then(lbInfo => {
|
236 | let tokens = lbInfo.getAdminTokens()
|
237 | console.log(tokens) // access tokens (String[]) of admin.
|
238 | })
|
239 | ```
|
240 |
|
241 | ## set `fetch` function to set tokens
|
242 | By default, the token is fixed and it's `loopback-with-admin-token`.
|
243 | **You must change the value by passing `fetch` function**.
|
244 |
|
245 | ```javascript
|
246 | const admin = {
|
247 | fetch: function() {
|
248 | return ['your-secret-token1', 'your-secret-token2']
|
249 | }
|
250 | }
|
251 |
|
252 | require('loopback-with-admin').run(models, config, { admin: admin })
|
253 | ```
|
254 |
|
255 | ## change tokens periodically
|
256 |
|
257 | ```javascript
|
258 | const admin = {
|
259 | fetch: function() {
|
260 | return generateSecretValuesByRandom().then(value => [ value ]) // fetch function allows Promise to return
|
261 | },
|
262 | intervalHours: 24 // change the value every day (by default, it's 12 hours)
|
263 | }
|
264 |
|
265 | require('loopback-with-admin').run(models, config, { admin: admin })
|
266 | ```
|
267 |
|
268 |
|
269 | ## admin user information
|
270 | property | value
|
271 | -------------|--------------------------------
|
272 | id | loopback-with-admin-user-id
|
273 | email | loopback-with-admin@example.com
|
274 | password | admin-user-password
|
275 |
|
276 | In fact, these value makes no sense as `admin` can **never be accessed via REST APIs**. No one can login with the account information.
|
277 |
|
278 |
|
279 |
|
280 | # configs
|
281 |
|
282 | Four types of configs are available.
|
283 |
|
284 | - datasources
|
285 | - middleware
|
286 | - server
|
287 | - push-credentials
|
288 |
|
289 | See JSON files in [default-values/non-model-configs directory](https://github.com/CureApp/loopback-with-admin/tree/master/default-values/non-model-configs).
|
290 |
|
291 | You can set the same properties as these JSONs.
|
292 |
|
293 |
|
294 | ## datasources
|
295 |
|
296 | config key | meaning
|
297 | -------------|---------------------------------
|
298 | memory | on memory datasource
|
299 | db | datasource for custom entities
|
300 |
|
301 | Each datasource name has its connectors.
|
302 |
|
303 | ### available loopback connectors
|
304 |
|
305 | Available datasources are
|
306 | - mongodb
|
307 | - memory
|
308 | - memory-idstr
|
309 |
|
310 | `memory-idstr` is the default connector, which stores data only in memory,
|
311 | and id type is string whereas id type of "memory" is number.
|
312 | See [loopback-connector-memory-idstr](https://github.com/CureApp/loopback-connector-memory-idstr).
|
313 |
|
314 | To use mongodb, add dependencies in package.json of your repository
|
315 |
|
316 | - loopback-connector-mongodb: "1.13.0"
|
317 | - mongodb: "2.0.35"
|
318 |
|
319 |
|
320 | ## server
|
321 |
|
322 | config key | meaning | default
|
323 | -------------|---------------|----------------
|
324 | restApiRoot | REST api root | /api
|
325 | port | port number | 3000
|
326 |
|
327 |
|
328 | ## push-credentials
|
329 |
|
330 | config key | meaning
|
331 | -----------------|-------------------------------------------
|
332 | gcmServerApiKey | api key for Google Cloud Messaging (GCM)
|
333 | apnsCertData | certificate pem contents for APNs
|
334 | apnsKeyData | key pem contents for APNs
|
335 |
|
336 | # LoopbackInfo
|
337 |
|
338 | `require('loopback-with-admin').run()` returns promise of `LoopbackInfo`.
|
339 |
|
340 | It contains the information of the launched loopback.
|
341 |
|
342 | - getURL()
|
343 | - getAdminTokens()
|
344 | - config
|
345 | - models
|
346 |
|
347 | ## getURL()
|
348 | Returns hosting URL.
|
349 |
|
350 | ```javascript
|
351 | const config = {
|
352 | server: {
|
353 | port: 4156,
|
354 | restApiRoot: 'awesome-endpoint'
|
355 | }
|
356 | }
|
357 | require('loopback-with-admin').run(models, config).then(lbInfo => {
|
358 | lbInfo.getURL() // localhost:4156/awesome-endpoint
|
359 | })
|
360 | ```
|
361 |
|
362 |
|
363 | ## getAdminTokens()
|
364 | Returns Array of access tokens (string).
|
365 |
|
366 | ```javascript
|
367 | const admin = {
|
368 | fetch: function() {
|
369 | return ['your-secret-token1', 'your-secret-token2']
|
370 | }
|
371 | }
|
372 |
|
373 | require('loopback-with-admin').run(models, config, { admin: admin }).then(lbInfo => {
|
374 | console.log(lbInfo.getAdminTokens()) // ['your-secret-token1', 'your-secret-token2']
|
375 | })
|
376 | ```
|
377 |
|
378 |
|
379 | ## getEnv()
|
380 | Returns environment name where loopback launched.
|
381 |
|
382 |
|
383 | ## config
|
384 | Contains all config values used to build loopback.
|
385 |
|
386 | - datasources
|
387 | - middleware
|
388 | - server
|
389 | - push-credentials
|
390 |
|
391 | See configs section above.
|
392 |
|
393 | ## models
|
394 | Contains model definitions used to build loopback
|
395 |
|
396 | See models section above.
|
397 |
|
398 | # push notification settings
|
399 | (coming soon)
|