The Feathers generator (CLI)

Until now we wrote code by hand in a single file to get a better understanding how Feathers itself works. The Feathers CLI allows us to initialize a new Feathers application with a recommended structure. It also helps with

  • Configuring authentication
  • Generating database backed services
  • Setting up database connections
  • Generating hooks (with tests)
  • Adding Express middleware

In this chapter we will look at installing the CLI and common patterns the generator uses to structure our server application. Further use of the CLI will be discussed in the chat application guide.

Installing the CLI

The CLI should be installed globally via npm:

  1. npm install @feathersjs/cli -g

Once successful we should now have the feathers command available on the command line which we can check with:

  1. feathers --version

Which should show a version of 3.7.5 or later.

Configure functions

The most common pattern used in the generated application is configure functions, functions that take the Feathers app object and then use it, e.g. to register services. Those functions are then passed to app.configure.

Let’s look at our basic database example:

  1. const feathers = require('@feathersjs/feathers');
  2. const memory = require('feathers-memory');
  3. const app = feathers();
  4. app.use('messages', memory({
  5. paginate: {
  6. default: 10,
  7. max: 25
  8. }
  9. }));

Which could be split up using a configure function like this:

  1. const feathers = require('@feathersjs/feathers');
  2. const memory = require('feathers-memory');
  3. const configureMessages = function(app) {
  4. app.use('messages', memory({
  5. paginate: {
  6. default: 10,
  7. max: 25
  8. }
  9. }));
  10. };
  11. const app = feathers();
  12. app.configure(configureMessages);

Now we can move that function into a separate file like messages.service.js and set it as the default module export for that file:

  1. const memory = require('feathers-memory');
  2. module.exports = function(app) {
  3. app.use('messages', memory({
  4. paginate: {
  5. default: 10,
  6. max: 25
  7. }
  8. }));
  9. };

And then import it into app.js and use it:

  1. const feathers = require('@feathersjs/feathers');
  2. const memory = require('feathers-memory');
  3. const configureMessages = require('./messages.service.js');
  4. const app = feathers();
  5. app.configure(configureMessages);

This is the most common pattern how the generators split things up into separate files and any documentation example that uses the app object can be used in a configure function. You can create your own files that export a configure function and require and app.configure them in app.js

Note: Keep in mind that the order in which configure functions are called might matter, e.g. if it is using a service, that service has to be registered first.

Hook functions

We already saw in the hooks guide how we can create a wrapper function that allows to customize the options of a hook with the setTimestamp example:

  1. const setTimestamp = name => {
  2. return async context => {
  3. context.data[name] = new Date();
  4. return context;
  5. }
  6. }
  7. app.service('messages').hooks({
  8. before: {
  9. create: setTimestamp('createdAt'),
  10. update: setTimestamp('updatedAt')
  11. }
  12. });

This is also the pattern the hook generator uses but in its own file like hooks/set-timestamp.js which could look like this:

  1. module.exports = ({ name }) => {
  2. return async context => {
  3. context.data[name] = new Date();
  4. return context;
  5. }
  6. }

Now we can use that hook like this:

  1. const setTimestamp = require('./hooks/set-timestamp.js');
  2. app.service('messages').hooks({
  3. before: {
  4. create: setTimestamp({ name: 'createdAt' }),
  5. update: setTimestamp({ name: 'updatedAt' })
  6. }
  7. });

Note: We are using an options object here which allows us to more easily add new options than function parameters.

What’s next?

In this chapter we installed the Feathers CLI (and generator) and looked at patterns that are used in structuring the generated application. Now we can use the generator to build a full chat application complete with authentication and a JavaScript frontend!