forked from LeCoupa/awesome-cheatsheets
-
Notifications
You must be signed in to change notification settings - Fork 0
/
feathers.js
578 lines (448 loc) · 27.7 KB
/
feathers.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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
203
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
237
238
239
240
241
242
243
244
245
246
247
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
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
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
/* *******************************************************************************************
* FEATHERS.JS CHEATSHEET
* https://docs.feathersjs.com/api/readme.html
*
* 1. CORE: Feathers core functionality.
* 2. TRANSPORT: Expose a Feathers application as an API server.
* 3. CLIENT: More details on how to use Feathers on the client.
* 4. AUTHENTICATION: Feathers authentication mechanism.
* 5. DATABASE: Feathers common database adapter API and querying mechanism.
* ******************************************************************************************* */
/* *******************************************************************************************
* 1. CORE: Feathers core functionality.
* ******************************************************************************************* */
```
# Provides the ability to initialize new application instances
npm install @feathersjs/feathers --save
# Provides a set of standard error classes used by all other Feathers modules
npm install @feathersjs/errors --save
```
// --> APPLICATION <--
// https://docs.feathersjs.com/api/application.html
const feathers = require('@feathersjs/feathers');
const app = feathers(); // application initialization
app.mixins // contains a list of service mixins
app.use(path, service) // allows registering a service object on a given path
app.service(path) // returns the wrapped service object for the given path
app.hooks(hooks) // allows registration of application-level hooks
app.publish([event,], publisher) // registers a global event publisher
app.configure(callback) // runs a callback function that gets passed the application object
app.listen(port) // starts the application on the given port
app.setup([server]) // used to initialize all services by calling each services .setup(app, path) method (if available)
app.set(name, value) // assigns setting name to value
app.get(name) // retrieves the setting name
app.on(eventname, listener) // registers a listener method for the given eventname
app.emit(eventname, data) // emits the event eventname to all event listeners
app.removeListener(eventname, [ listener ]) // removes all or the given listener for eventname
// --> SERVICES <--
// https://docs.feathersjs.com/api/services.html
// "Services" are the heart of every Feathers application.
// Services are JavaScript objects (or instances of ES6 classes) that implement certain methods.
// Feathers itself will also add some additional methods and functionality to its services.
class MyService {
// Retrieves a list of all resources from the service.
// Provider parameters will be passed as params.query.
async find(params) {
return [];
}
// Retrieves a single resource with the given id from the service.
async get(id, params) {}
// Creates a new resource with data.
// The method should return the newly created data. data may also be an array.
async create(data, params) {}
// Replaces the resource identified by id with data.
// The method should return the complete, updated resource data.
// id can also be null when updating multiple records, with params.query containing the query criteria.
async update(id, data, params) {}
// Merges the existing data of the resource identified by id with the new data.
// id can also be null indicating that multiple resources should be patched with params.query containing the query criteria.
async patch(id, data, params) {}
// Removes the resource with id.
// The method should return the removed resource.
// id can also be null, which indicates the deletion of multiple resources, with params.query containing the query criteria.
async remove(id, params) {}
// A special method that initializes the service, passing an instance of the Feathers application
// and the path it has been registered on.
// For services registered before app.listen is invoked, the setup function of each registered service
// is called on invoking app.listen. For services registered after app.listen is invoked, setup is
// called automatically by Feathers when a service is registered.
setup(app, path) {}
}
params.query // contains the URL query parameters sent from the client
params.provider // for any service method call made through REST params.provider will be set to rest
app.use('/my-service', new MyService());
// Important: Always use the service returned by app.service(path)
const myService = app.service('my-service');
myService.hooks(hooks) // register hooks for this service
myService.publish([event,], publisher) // register an event publishing callback
myService.mixin(mixin) // extends the functionality of a service
myService.on(eventname, listener) // registers a listener method for the given eventname
myService.once(eventname, listener) // registers a listener method for the given eventname that will be triggered only one time
myService.emit(eventname, data) // emits the event eventname to all event listeners
myService.removeListener(eventname, [ listener ]) // removes all listeners (or the given listener) for eventname
// --> HOOKS <--
// https://docs.feathersjs.com/api/hooks.html
// Hooks are pluggable middleware functions that can be registered
// before, after or on errors of a service method. You can register a
// single hook function or create a chain of them to create complex work-flows.
app.service('my-service').hooks({
before: {
all: [
// Use normal functions
async function(context) { console.log('before all hook ran'); }
],
find: [
// Use ES6 arrow functions
context => console.log('before find hook 1 ran'),
async context => console.log('before find hook 2 ran')
],
async create (context) {
return context
},
},
after: {
all: [],
find: [],
get: [],
create: [],
update: [],
patch: [],
remove: []
},
// Here is an example for a very useful application hook that logs every service method error
// with the service and method name as well as the error stack
error(context) {
console.error(`Error in ${context.path} calling ${context.method} method`, context.error);
}
});
context.app // [read only] contains the Feathers application object
context.service // [read only] contains the service this hook currently runs on
context.path // [read only] contains the service name (or path) without leading or trailing slashes
context.method // [read only] contains the name of the service method (find, get, create, update...)
context.type // [read only] contains the hook type (one of before, after or error)
context.params // [writable] contains the service method parameters (including params.query)
context.id // [writable] contains the id for a get, remove, update and patch service method call
context.data // [writable] contains the data of a create, update and patch service method call
context.error // [writable] contains the error object that was thrown in a failed method call (only available in error hooks)
context.result // [writable] contains the result of the successful service method call (only available in after hooks)
context.dispatch // [writable and optional] contains a "safe" version of the data that should be sent to any client
// --> CHANNELS <--
// https://docs.feathersjs.com/api/channels.html
// A channel is an object that contains a number of connections.
// It can be created via app.channel and allows a connection to join or leave it.
app.channel(name) // when given a single name, returns an existing or new named channel
app.channel(name1, name2, ... nameN) // when given multiples names, will return a combined channel.
app.channels // returns a list of all existing channel names
channel.join(connection) // adds a connection to this channel
channel.leave(connection|fn) // removes a connection from this channel
channel.filter(fn) // returns a new channel filtered by a given function which gets passed the connection
channel.send(data) // returns a copy of this channel with customized data that should be sent for this event
channel.connections // contains a list of all connections in this channel
channel.length // returns the total number of connections in this channel
service.publish([event,] fn) // registers a publishing function for a specific service for a specific event or all events if no event name was given
app.publish([event,] fn) // registers an event publishing callback
app.on('connection', connection => {}) // fired every time a new real-time connection is established
app.on('disconnection', connection => {})
app.on('login', (authenticationResult, params, context) => {}) // sent by the authentication module and also contains the connection in the info object that is passed as the second parameter
/* *******************************************************************************************
* 2. TRANSPORT: Expose a Feathers application as an API server.
* ******************************************************************************************* */
```
# Contains Express framework integrations
npm install @feathersjs/express --save
# Allows to call service methods and receive real-time events
npm install @feathersjs/socketio --save
# Allows to call service methods and receive real-time events via Primus
npm install @feathersjs/primus --save
```
// --> EXPRESS <--
// https://docs.feathersjs.com/api/express.html
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
// Create an app that is a Feathers AND Express application
const app = express(feathers());
// If no Feathers application is passed, express() returns a plain Express application
// just like a normal call to Express would
const app = express();
app.use(path, service|mw) // registers either a service object or an Express middleware on the given path
app.listen(port) // will first call Express app.listen and then internally also call the Feathers app.setup(server)
app.setup(server) // usually called internally by app.listen but in the cases described below needs to be called explicitly
express.rest() // registers a Feathers transport mechanism that allows you to expose and consume services through a RESTful API.
app.configure(express.rest()) // configures the transport provider with a standard formatter sending JSON response via res.json
express.notFound() // returns middleware that returns a NotFound (404) Feathers error
express.errorHandler() // middleware that formats any error response to a REST call as JSON and sets the appropriate error code
app.use(express.errorHandler()) // set up the error handler with the default configuration
// --> SOCKET.IO <--
// https://docs.feathersjs.com/api/client/socketio.html
const feathers = require('@feathersjs/feathers');
const socketio = require('@feathersjs/socketio');
const app = feathers();
app.configure(socketio()); // sets up the Socket.io transport with the default configuration using either the server provided by app.listen or passed in app.setup(server)
app.configure(socketio(callback)) // sets up the Socket.io transport with the default configuration and call callback with the Socket.io server object
app.configure(socketio(options [, callback])) // sets up the Socket.io transport with the given Socket.io options object and optionally calls the callback
app.configure(socketio(port, [options], [callback])) // creates a new Socket.io server on a separate port. Options and a callback are optional
// --> PRIMUS <--
// https://docs.feathersjs.com/api/client/primus.html
app.configure(primus(options)) // sets up the Primus transport with the given Primus options
app.configure(primus(options, callback)) // sets up the Primus transport with the given Primus options and calls the callback with the Primus server instance
/* *******************************************************************************************
* 3. CLIENT: More details on how to use Feathers on the client.
* ******************************************************************************************* */
```
# Bundles the separate Feathers client side modules into one providing the code as ES5 (compatible with modern browsers)
# You do not have to install or load any of the other modules listed below
npm install @feathersjs/client --save
# Allows to connect to services through REST HTTP
npm install @feathersjs/rest-client --save
# Allows to connect to services through Socket.io
npm install @feathersjs/socketio-client --save
# Allows to connect to services through Primus
npm install @feathersjs/primus-client --save
# Allows you to easily authenticate against a Feathers server
npm install @feathersjs/authentication-client --save
```
// --> REST CLIENT <--
// https://docs.feathersjs.com/api/client/rest.html
rest([baseUrl]) // Initialize a client object with a base URL
app.configure(restClient.jquery(window.jQuery)); // connect to a service using jQuery
app.configure(restClient.request(requestClient)); // connect to a service using request
app.configure(restClient.superagent(superagent)); // connect to a service using Superagent
app.configure(restClient.axios(axios)); // connect to a service using Axios
app.configure(restClient.fetch(window.fetch)); // connect to a service using Fetch
// --> SOCKET.IO <--
// https://docs.feathersjs.com/api/client/socketio.html
socketio(socket) // initialize the Socket.io client using a given socket and the default options
socketio(socket, options) // initialize the Socket.io client using a given socket and the given options
// --> PRIMUS <--
// https://docs.feathersjs.com/api/client/primus.html
primus(socket) // initialize the Primus client using a given socket and the default options
primus(socket, options) // initialize the Primus client using a given socket and the given options
/* *******************************************************************************************
* 4. AUTHENTICATION: Feathers authentication mechanism.
* ******************************************************************************************* */
```
# Assists in using JWT for authentication
npm install @feathersjs/authentication --save
# Wraps the passport-local authentication strategy (username and password)
npm install @feathersjs/authentication-local --save
# Allows to use 180+ oAuth providers (Facebook, Google, Twitter etc.)
npm install @feathersjs/authentication-oauth --save
```
// --> SERVER <--
// https://docs.feathersjs.com/api/authentication/server.html
const options = {
"authentication": {
"secret": "CHANGE_ME", // The token signing secret
"entity": "user", // the entity that will be added to the request, socket, and context.params. (ie. req.user, socket.user, context.params.user)
"service": "users", // the service to look up the entity
"authStrategies": [ "jwt", "local" ], // The authentication strategies to allow to create a token
"jwtOptions": {
"header": { "typ": "access" }, // by default is an access token but can be any type
"audience": "https://yourdomain.com", // The resource server where the token is processed
"issuer": "feathers", // The issuing server, application or resource
"algorithm": "HS256", // the algorithm to use
"expiresIn": "1d" // the access token expiry
}
}
}
const { AuthenticationService, JWTStrategy } = require('@feathersjs/authentication');
let authService = new AuthenticationService(app);
service.register('jwt', new JWTStrategy());
app.use('/authentication', authService);
app.configure(expressOauth());
app.get('defaultAuthentication') // The name of the default authentication service
authService = app.service('authentication') // service for creating JWT (implements only the create and remove methods)
authService.hooks({ before }) // registers hooks for this service
authService.hooks({ after }) // registers hooks for this service
new AuthenticationService(app) // Create a new authentication service
class MyAuthenticationService extends AuthenticationService {} // Customize the authentication service
authService.authenticate(data, params, ...strategies) // Authenticate with strategies
authService.create(data, params) // Authenticate with data and params
authService.create({ // Authenticate and create a JWT using the local strategy email/password
strategy: 'local',
email: '[email protected]',
password: 'supersecret'
});
authService.remove(id, params) // removes the JWT token (mostly exists for the logout process)
authService.configuration // The current configuration
authService.register(name, strategy) // Register a new authentication strategy
authService.createAccessToken(payload) // Create a new access token with payload
authService.verifyAccessToken(accessToken) // Verify an existing access token
authService.getTokenOptions(authResult, params) // Get the options for a token
authService.getPayload(authResult, params) // Return the payload for an authentication result
authService.parse(req, res, ...strategies) // Parse an HTTP request and response with using a list of strategies
app.on('login', callback)) // emits an event whenever a client successfully authenticates
app.on('logout', callback)) // emits an event whenever a client successfully logout
// --> CLIENT <--
// https://docs.feathersjs.com/api/authentication/client.html
const options = {
storage: window.localStorage, // The storage to store the access token
path: '/authentication', // The path of the authentication service
locationKey: 'access_token', // The name of the window hash parameter to parse for an access token from the window.location. Usually used by the oAuth flow.
locationErrorKey: 'error', // The name of the window hash parameter to parse for authentication errors. Usually used by the oAuth flow.
jwtStrategy: 'jwt', // The access token authentication strategy
storageKey: 'feathers-jwt', // Key for storing the token in e.g. localStorage
header: 'Authorization', // Name of the accessToken header
scheme: 'Bearer', // The HTTP header scheme
Authentication: AuthenticationClient // Allows to provide a customized authentication client class
}
app.configure(auth(options)) // configure the authentication plugin with the given options
app.reAuthenticate() // authenticates using the JWT from the storage
app.authenticate(options) // authenticate with a Feathers server by passing a strategy and other properties as credentials
app.logout() // removes the JWT accessToken from storage on the client
const authenticationInfo = await app.get('authentication'); // The authenticatoin information (like the user)
app.on('login', callback) // emits an event whenever the client successfully authenticates
app.on('logout', callback) // emits an event whenever the client successfully authenticates
// --> LOCAL (EMAIL & PASSWORD) <--
// https://docs.feathersjs.com/api/authentication/local.html
const { LocalStrategy } = require('@feathersjs/authentication-local');
const options = {
usernameField: 'email', // Name of the username field in the (e.g. 'email')
passwordField: 'password', // Name of the password field (e.g. 'password')
hashSize: 10, // The BCrypt hash size
errorMessage: 'Invalid login', // The error message to return on errors
entityUsernameField: usernameField, // Name of the username field on the entity if authentication request data and entity field names are different
entityPasswordField: passwordField // Name of the password field on the entity if authentication request data and entity field names are different
}
authService.register('local', new LocalStrategy());
local.hooks.hashPassword() // hashes plain text passwords before they are saved to the database
local.hooks.protect('password') // makes sure that protected fields don't get sent to a client
// --> OAUTH <--
// https://docs.feathersjs.com/api/authentication/oauth.html
const { expressOauth, OAuthStrategy } = require('@feathersjs/authentication-oauth');
class GitHubStrategy extends OAuthStrategy {
async getEntityData(profile) {
const baseData = await super.getEntityData(profile);
return {
...baseData,
email: profile.email
};
}
}
authService.register('github', new MyGitHubStrategy());
const options = {
authentication: {
oauth: {
redirect: '/', // The redirect after a successful login
github: { // The per-strategy configuration
key: '<Client ID>',
secret: '<Client secret>'
}
}
}
}
app.configure(expressOauth(options));
/* *******************************************************************************************
* 5. DATABASE: Feathers common database adapter API and querying mechanism.
* ******************************************************************************************* */
```
# [MEMORY/FILESYSTEM] In-memory database adapter
npm install feathers-memory --save
# [MEMORY/FILESYSTEM] Database adapter for NeDB an in-memory or file system based standalone database
npm install feathers-nedb --save
# [MEMORY/FILESYSTEM] Adapter for Client side Feathers that can use the browsers LocalStorage or ReactNative's AsyncStorage
npm install feathers-localstorage --save
# [SQL] Adapter for KnexJS, an SQL query builder for NodeJS supporting PostgreSQL, MySQL, SQLite and MSSQL
npm install feathers-knex --save
# [SQL] Adapter for Sequelize an ORM for NodeJS supporting PostgreSQL, MySQL, SQLite and MSSQL
npm install feathers-sequelize --save
# [NOSSQL] Database adapter for MongoDB using the official NodeJS database driver
npm install feathers-mongodb --save
# [NOSSQL] Database adapter for Mongoose an Object Modelling library for NodeJS and MongoDB
npm install feathers-mongoose --save
# [NOSSQL] Database adapter for Elasticsearch
npm install feathers-elasticsearch --save
# [NOSSQL] Database adapter for RethinkDB a real-time database.
npm install feathers-rethinkdb --save
```
// --> COMMON API <--
// https://docs.feathersjs.com/api/databases/common.html
const service = require('feathers-<adaptername>');
app.use('/messages', service({
id: undefined, // (optional) name of the id field property (usually set by default to id or _id)
events: undefined, // (optional) list of custom service events sent by this service
paginate: { // (optional) a pagination object containing a default and max page size
default: undefined, // sets the default number of items when $limit is not set
max: undefined // sets the maximum allowed number of items per page (even if the $limit query parameter is set higher)
},
whitelist: [], // A list of additional non-standard query parameters to allow (e.g [ '$regex', '$populate' ])
multi: true // Allow create with arrays and update and remove with id null to change multiple items
}));
adapter.find() // returns a list of all records matching the query in params.query using the common querying mechanism
adapter.get(id, params) // retrieves a single record by its unique identifier (the field set in the id option during initialization)
adapter.create(data, params) // creates a new record with data. data can also be an array to create multiple records
adapter.update(id, data, params) // completely replaces a single record identified by id with data. Does not allow replacing multiple records (id can't be null). id can not be changed.
adapter.patch(id, data, params) // merges a record identified by id with data. id can be null to allow replacing multiple records (all records that match params.query the same as in .find). id can not be changed
adapter.remove(id, params) // removes a record identified by id. id can be null to allow removing multiple records (all records that match params.query the same as in .find)
// Hook-less
adapter._find()
adapter._get(id, params)
adapter._create(data, params)
adapter._update(id, data, params)
adapter._patch(id, data, params)
adapter._remove(id, params)
// --> QUERYING <--
// https://docs.feathersjs.com/api/databases/querying.html
app.service('messages').find({
query: {
$limit: 2, // will return only the number of results you specify
$select: [ 'text', 'userId' ], // allows to pick which fields to include in the result
$skip: 2, // will skip the specified number of results
$sort: { // will sort based on the object you provide. It can contain a list of properties by which to sort mapped to the order
createdAt: -1
},
$or: [ // find all records that match any of the given criteria
{ archived: { $ne: true } },
{ roomId: 2 }
],
read: false, // compared directly for equality
roomId: {
$in: [ 2, 5 ], // find all records where the property does match any of the given values
$nin: [ 1, 3 ] // find all records where the property does not match any of the given values
},
createdAt: {
$lt: new Date().getTime(), // find all records where the value is less to a given value
$lte: new Date().getTime(), // find all records where the value is less and equal to a given value
$gt: new Date().getTime(), // find all records where the value is more to a given value
$gte: new Date().getTime(), // find all records where the value is more and equal to a given value
},
archived: {
$ne: true // find all records that do not equal the given property value
}
}
});
// With pagination enabled, to just get the number of available records set $limit to 0.
// This will only run a (fast) counting query against the database and return a page object with
// the total and an empty data array.
/* *******************************************************************************************
* 5. APPLICATION ARCHITECTURE
* ******************************************************************************************* */
// .
// ├── config/ # contains the configuration files for the app
// │ ├── default.json # default configuration variables
// │ ├── production.json # override default configurations variables when NODE_ENV=production
// │ └── ...
// │
// ├── node_modules/ # project dependencies using NPM or Yarn
// │ └── ...
// │
// ├── public/ # contains static files to be served
// │ └── ...
// │
// ├── src/ # contains the Feathers server code
// │ ├── hooks/ # contains our custom hooks
// │ │ └── ...
// │ ├── middleware/ # contains our Express middlewares
// │ │ └── ...
// │ ├── services/ # contains our services
// │ │ └── ...
// │ │
// │ ├── index.js # is used to load and start the application
// │ ├── app.js # configures our Feathers application
// │ ├── app.hooks.js # contains hooks which that run for all services
// │ └── channels.js # set up Feathers event channels
// ├── tests/ # contains Mocha test files for the app, hooks and services
// │ └── ...
// ├── .editorconfig # helps developers define and maintain consistent coding styles
// ├── .eslintrc.json # eslint configuration
// └── package.json # express server for production