feathers.js入门
Quick Start
按官方的Quick Start理解如下:
安装
npm install @feathersjs/feathers --save
服务端
创建一个类来管理一种资源,并且其同步async方法与REST的各种操作相对应,如messages资源。这个类称之为Service服务。
操作CRUD | REST HTTP | feathers class async 函数 | 完成事件 |
---|---|---|---|
增 create | POST | async create(data, params) // 其中data为通过POST发送来的JSON,并且已经JSON.parse成了对象。params可选,下同 | created |
删 delete | DELETE | remove(id, params) | removed |
替换改 update | PUT | update(id, data, params) | updated |
合并改 update | PATCH | patch(id, data, params) | patched |
查所有 read | GET messages | async find(params) //返回值为GET的返回值,为JS对象。JSON化(JSON.stringify)由feathers完成,不需要我们操作 | - |
查部分 read | GET mesages?xx=x&xxx=xx | async get(id, params) {} | - |
另外有个查header的REST HEAD
似乎没有对应,这个命令和GET类似,只是不返回内容只返回header
class MessageService {
//初始化时候需要创建一个存储资源的地方,示例中先在内存中建立了一个数组,后面估计可以改为数据库的访问
constructor() {
this.messages = [];
}
async find () {
// Just return all our messages
return this.messages;
}
async create (data) {
// The new message is the data merged with a unique identifier
// using the messages length since it changes whenever we add one
const message = {
id: this.messages.length,
text: data.text
}
// Add new message to the list
this.messages.push(message);
return message;
}
app.use('/messages', new MessageService()); // 这儿注册资源的url地址和资源的class服务
完整代码:
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const socketio = require('@feathersjs/socketio');
// A messages service that allows to create new
// and return all existing messages
class MessageService {
constructor() {
this.messages = [];
}
async find () {
// Just return all our messages
return this.messages;
}
async create (data) {
// The new message is the data merged with a unique identifier
// using the messages length since it changes whenever we add one
const message = {
id: this.messages.length,
text: data.text
}
// Add new message to the list
this.messages.push(message);
return message;
}
}
// Creates an ExpressJS compatible Feathers application 创建一个Express兼容的Feathers APP
const app = express(feathers());
// Parse HTTP JSON bodies.
// 从这儿开始注册中间件,先是自动对JSON数据解析的,也就是请求时header写着 ‘content-type: application/json’ 的
app.use(express.json());
// Parse URL-encoded params
// 解析 URL-encoded 格式的请求体数据,也就是请求时header写着‘content-type: application/x-www-form-urlencoded’ 的
app.use(express.urlencoded({ extended: true }));
// Host static files from the current folder
// 这个替代了nginx作用了,对.html .css等静态文件做http服务
app.use(express.static(__dirname));
// Add REST API support
app.configure(express.rest());
// Configure Socket.io real-time APIs
app.configure(socketio());
// Register an in-memory messages service,
// 这个是一句抵6句的REST注册了,否则要app.get/app.post/app.delete一个一个去搞定REST接口
app.use('/messages', new MessageService());
// Register a nicer error handler than the default Express one
app.use(express.errorHandler());
// Add any new real-time connection to the `everybody` channel
// 一个连接connection类似一个会话session,一个频道channel类似MQTT的一个topic,
// 这儿在一个连接产生时将这个连接加入到everybody的频道中
app.on('connection', connection =>
app.channel('everybody').join(connection)
);
// Publish all events to the `everybody` channel
// 一个事件events类似于MQTT的一个消息,当然这个events也是node的标准events,data是消息内容,
// publish的操作类似于MQTT的pub。sub操作是通过监听事件 .on 来做的,具体来说可以是监听created事件。
app.publish(data => app.channel('everybody'));
// Start the server
app.listen(3030).on('listening', () =>
console.log('Feathers server listening on localhost:3030')
);
// For good measure let's create a message
// So our API doesn't look so empty 先自行加一条数据到messages资源中
app.service('messages').create({
text: 'Hello world from the server'
});
客户端
直接访问http://localhost:3030/messages
就相当于GET操作REST API
再创建一个index.html作为客户端来访问
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Feathers Example</title>
<link rel="stylesheet" href="//unpkg.com/feathers-chat@4.0.0/public/base.css">
<link rel="stylesheet" href="//unpkg.com/feathers-chat@4.0.0/public/chat.css">
</head>
<body>
<main id="main" class="container">
<h1>Welcome to Feathers</h1>
<form class="form" onsubmit="sendMessage(event.preventDefault())">
<input type="text" id="message-text" placeholder="Enter message here">
<button type="submit" class="button button-primary">Send message</button>
</form>
<h2>Here are the current messages:</h2>
</main>
<script src="//unpkg.com/@feathersjs/client@^4.3.0/dist/feathers.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.4/socket.io.js"></script>
<script type="text/javascript">
// Set up socket.io 实时连接监听地址
const socket = io('http://localhost:3030');
// Initialize a Feathers app
const app = feathers();
// Register socket.io to talk to our server
app.configure(feathers.socketio(socket));
// Form submission handler that sends a new message
async function sendMessage () {
const messageInput = document.getElementById('message-text');
// Create a new message with the input field value, 通过REST POST发送消息,当然这一切都隐藏了
await app.service('messages').create({
text: messageInput.value
});
messageInput.value = '';
}
// Renders a single message on the page,增加一条新的message
function addMessage (message) {
document.getElementById('main').innerHTML += `<p>${message.text}</p>`;
}
const main = async () => {
// Find all existing messages
const messages = await app.service('messages').find();
// Add existing messages to the list
messages.forEach(addMessage);
// Add any newly created message to the list in real-time
app.service('messages').on('created', addMessage);
};
main();
</script>
</body>
</html>
除了REST以外的概念
如果只是实现REST就不想要下面这些了
实时通讯
类似MQTT咯。REST只能根据客户端的请求相应,而实时通讯可以根据事件主动向客户端推送消息
Channels 实时通讯通道,类似于MQTT的topic吧
Events 事件系统
使用cli构建
安装cli: npm install @feathersjs/cli -g
使用cli
mkdir feathers-chat
cd feathers-chat/
feathers generate app
交互式命令行输出:
D:\r\feathers_proj\feather-chat>feathers generate app
? Do you want to use JavaScript or TypeScript? JavaScript
? Project name feather-chat
? Description
? What folder should the source files live in? src
? Which package manager are you using (has to be installed globally)? npm
? What type of API are you making? REST, Realtime via Socket.io
? Which testing framework do you prefer? Mocha + assert
? This app uses authentication Yes
? Which coding style do you want to use? ESLint
? What authentication strategies do you want to use? (See API docs for all 180+ supported oAuth providers) Username + Pa
ssword (Local)
? What is the name of the user (entity) service? users
? What kind of service is it? NeDB
? What is the database connection string? nedb://../data
create package.json
create config\default.json
create public\favicon.ico
create public\index.html
create .editorconfig
create src\app.hooks.js
create src\channels.js
create src\index.js
create src\logger.js
create src\middleware\index.js
create src\services\index.js
create .gitignore
create README.md
create src\app.js
create test\app.test.js
create .eslintrc.json
create config\production.json
create config\test.json
create src\services\users\users.service.js
create src\authentication.js
create test\authentication.test.js
create src\services\users\users.class.js
create src\models\users.model.js
create src\services\users\users.hooks.js
create test\services\users.test.js
.....
目录简述
- config/ 配置
- public/ html静态文件,大概意思是nginx都不用装了
- src/ 源码。包括
hooks
钩子和services
服务。services里默认有一个users
服务。 - middleware/ 放express的中间件
- models/ 放数据库模型,也就是和数据库的链接映射。里面默认有一个users.model.js提供与users表的映射
- test/ 测试
根目录文件简述
- app.js feathers应用的配置
- app.hooks.js app的钩子
- authentication.js 认证系统
- channels.js 频道系统,用于实时通讯
- index.js 入口
运行命令
# 启动
npm start
# 测试
npm test
# 开发模式,代码更新自动重运行
npm run dev
通过cli创建services
feathers generate service
通过cli交互创建需要的文件
λ feathers generate service
? What kind of service is it? NeDB
? What is the name of the service? messages
? Which path should the service be registered on? /messages
? Does the service require authentication? Yes
create src\services\messages\messages.service.js
force src\services\index.js
create src\services\messages\messages.class.js
create src\models\messages.model.js
create src\services\messages\messages.hooks.js
create test\services\messages.test.js
npm WARN ws@7.4.6 requires a peer of bufferutil@^4.0.1 but none is installed. You must install peer dependencies yourself.
npm WARN ws@7.4.6 requires a peer of utf-8-validate@^5.0.2 but none is installed. You must install peer dependencies yourself.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.3.2 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.3.2: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
up to date in 8.347s
npm WARN ws@7.4.6 requires a peer of bufferutil@^4.0.1 but none is installed. You must install peer dependencies yourself.
npm WARN ws@7.4.6 requires a peer of utf-8-validate@^5.0.2 but none is installed. You must install peer dependencies yourself.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.3.2 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.3.2: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
up to date in 4.056s
基本是创建了src/services目录下的三个文件,挂载到index.js上,并创建连接数据库的对应model.js和测试文件
Hooks钩子
钩子可以在服务的前、后、错误时运行。钩子与服务是多对多的关系,相当于对多个不同服务中类似的功能提取公因数。
const createdAt = async context => {
context.data.createdAt = new Date();
return context;
};
app.service('messages').hooks({
before: {
create: [ createdAt ]
}
});
Cli方式创建钩子
命令是:
feathers generate hook
交互示意:
λ feathers generate hook
? What is the name of the hook? process-message
? What kind of hook should it be? before
? What service(s) should this hook be for (select none to add it yourself)?
messages
? What methods should the hook be for (select none to add it yourself)? create
create src\hooks\process-message.js
force src\services\messages\messages.hooks.js