服务

服务是每个Feathers应用程序的核心, 是JavaScript对象或实现某些 方法的类 的实例. 服务提供统一的, 独立于协议的界面, 用于如何与任何类型的数据交互:

  • 从数据库中读取和/或写入

  • 与文件系统交互

  • 调用另一个API

  • 调用其它其他服务

    • 发送电子邮件

    • 处理付款

    • 返回当前天气的位置等

独立于协议意味着对于Feathers服务而言, 如果它是通过REST API或websockets(我们将在稍后讨论)或其他任何方式在内部调用它并不重要.

服务方式

服务方法是服务对象可以实现的 CRUD 方法. Feathers服务方​​法有:

  • find - 查找所有数据(可能与查询匹配)

  • get - 通过其唯一标识符获取单个数据条目

  • create - 创建新数据

  • update - 通过完全替换现有数据条目来更新它

  • patch - 通过与新数据合并来更新一个或多个数据条目

  • remove - 删除一个或多个现有数据条目

下面是作为普通对象和JavaScript类的Feathers服务接口的示例:

const myService = {
  async find(params) { return []; },
  async get(id, params) {},
  async create(data, params) {},
  async update(id, data, params) {},
  async patch(id, data, params) {},
  async remove(id, params) {}
}
app.use(‘/my-service’, myService);
class myService {
  async find(params) { return []; }
  async get(id, params) {}
  async create(data, params) {}
  async update(id, data, params) {}
  async patch(id, data, params) {}
  async remove(id, params) {}
}
app.use(‘/my-service’, new myService());

服务方法的参数是:

  • id - 数据的唯一标识符

  • data - 用户发送的数据(用于创建和更新)

  • params (optional) - 其他参数, 例如经过身份验证的用户或查询

注解

服务不必实现所有这些方法, 但必须至少有一个.

小技巧

有关服务, 服务方法和参数的详细信息, 请参阅 ../api/services.

消息服务

现在我们知道了服务方法的样子, 我们可以实现自己的聊天消息服务, 允许我们在内存中查找, 创建, 删除和更新消息. 在这里, 我们将使用JavaScript类来处理我们的消息, 但正如我们在上面看到的, 它也可能是一个普通的对象.

下面是带有注释的完整更新的 app.js:

const feathers = require('@feathersjs/feathers');

class Messages {
  constructor() {
    this.messages = [];
    this.currentId = 0;
  }

  async find(params) {
    // Return the list of all messages
    return this.messages;
  }

  async get(id, params) {
    // Find the message by id
    const message = this.messages.find(message => message.id === parseInt(id, 10));

    // Throw an error if it wasn't found
    if(!message) {
      throw new Error(`Message with id ${id} not found`);
    }

    // Otherwise return the message
    return message;
  }

  async create(data, params) {
    // Create a new object with the original data and an id
    // taken from the incrementing `currentId` counter
    const message = Object.assign({
      id: ++this.currentId
    }, data);

    this.messages.push(message);

    return message;
  }

  async patch(id, data, params) {
    // Get the existing message. Will throw an error if not found
    const message = await this.get(id);

    // Merge the existing message with the new data
    // and return the result
    return Object.assign(message, data);
  }

  async remove(id, params) {
    // Get the message by id (will throw an error if not found)
    const message = await this.get(id);
    // Find the index of the message in our message array
    const index = this.messages.indexOf(message);

    // Remove the found message from our array
    this.messages.splice(index, 1);

    // Return the removed message
    return message;
  }
}

const app = feathers();

// Initialize the messages service by creating
// a new instance of our class
app.use('messages', new Messages());

使用服务

可以通过调用 app.use(path, service) 在Feathers应用程序上注册服务对象. path 将是服务的名称(以及URL, 如果它作为API公开, 我们将在后面介绍).

我们可以通过 app.service(path) 检索该服务, 然后调用它的任何服务方法. 将以下内容添加到 app.js 的末尾:

async function processMessages() {
  await app.service('messages').create({
    text: 'First message'
  });

  await app.service('messages').create({
    text: 'Second message'
  });

  const messageList = await app.service('messages').find();

  console.log('Available messages', messageList);
}

processMessages();

并运行它

node app.js

我们应该看到这一点:

Available messages [ { id: 1, text: 'First message' },
  { id: 2, text: 'Second message' } ]

服务事件

注册服务时, 它将自动成为 NodeJS EventEmitter, 当修改数据的服务方法时, 它会发送带有新数据的事件, (update, patchremove)返回. 可以使用 app.service('messages').on('eventName', data => {}) 来监听事件. 以下是服务方法及其相应事件的列表:

服务方式

服务事件

service.create()

service.on('created')

service.update()

service.on('updated')

service.patch()

service.on('patched')

service.remove()

service.on('removed')

我们稍后会看到, 这是Feathers如何实现实时功能的关键. 现在, 让我们更新 app.js 中的 processMessages 函数, 如下所示:

async function processMessages() {
  app.service('messages').on('created', message => {
    console.log('Created a new message', message);
  });

  app.service('messages').on('removed', message => {
    console.log('Deleted message', message);
  });

  await app.service('messages').create({
    text: 'First message'
  });

  const lastMessage = await app.service('messages').create({
    text: 'Second message'
  });

  // Remove the message we just created
  await app.service('messages').remove(lastMessage.id);

  const messageList = await app.service('messages').find();

  console.log('Available messages', messageList);
}

processMessages();

如果我们现在通过运行该文件

node app.js

我们将看到事件处理程序如何记录这样创建和删除的消息的信息:

Created a new message { id: 1, text: 'First message' }
Created a new message { id: 2, text: 'Second message' }
Deleted message { id: 2, text: 'Second message' }
Available messages [ { id: 1, text: 'First message' } ]

下一步是什么?

在本章中, 我们了解了作为Feathers核心概念的服务, 用于抽象数据操作. 我们还了解了服务如何发送我们稍后将用于创建实时应用程序的事件. 首先, 我们将看看 钩子, 这是Feathers如何工作的另一个关键部分.