Skip to content

Feathers.js 快速上手 - 15分钟搭建你的第一个API

发布时间:2024-05-06
作者:一介布衣
标签:Feathers.js, 快速上手, API开发, 实战教程

前言

上一篇文章我们了解了 Feathers.js 的基本概念和优势,今天咱们就来动手实践,真正体验一下 Feathers.js 的魅力。说实话,当我第一次用 Feathers.js 搭建 API 的时候,那种"哇,这也太简单了吧"的感觉至今还记得。

我记得以前用 Express 搭建一个带实时功能的 API,光是配置 Socket.io 就要折腾半天,更别说处理各种边界情况了。但是用 Feathers.js,真的是几分钟就能搞定一个功能完整的 API。

今天我就带大家从零开始,15分钟内搭建一个完整的 API,包含 REST 接口和实时功能。

环境准备

系统要求

  • Node.js 16+ (推荐 18+)
  • npm 或 yarn
  • 代码编辑器(推荐 VS Code)

检查环境

bash
# 检查 Node.js 版本
node --version
# 应该显示 v16.0.0 或更高版本

# 检查 npm 版本
npm --version
# 应该显示 8.0.0 或更高版本

如果版本不够,建议使用 nvm 来管理 Node.js 版本:

bash
# 安装最新的 LTS 版本
nvm install --lts
nvm use --lts

安装 Feathers CLI

Feathers.js 提供了强大的命令行工具,能够快速生成项目结构:

bash
# 全局安装 Feathers CLI
npm install -g @feathersjs/cli

# 验证安装
feathers --version

如果你不想全局安装,也可以使用 npx:

bash
npx @feathersjs/cli --version

创建第一个项目

1. 生成项目

bash
# 创建新项目
feathers generate app

# 或者使用 npx
npx @feathersjs/cli generate app

CLI 会问你一系列问题,我们按照下面的选择:

? Project name: my-feathers-app
? Description: My first Feathers.js application
? What folder should the source files live in? src
? Which package manager are you using? npm
? What type of API are you making? REST, Realtime via Socket.io
? Which testing framework do you prefer? Jest
? This app uses authentication: Yes
? What authentication methods do you want to use? Email + Password
? What is the source of your database? SQL (PostgreSQL, MySQL, MariaDB, SQLite, MSSQL)
? Which database are you connecting to? SQLite
? Does your app require users to verify their email? No

2. 项目结构解析

生成的项目结构如下:

my-feathers-app/
├── config/                 # 配置文件
│   ├── default.json        # 默认配置
│   └── production.json     # 生产环境配置
├── src/                    # 源代码
│   ├── services/           # 服务目录
│   ├── hooks/              # 钩子目录
│   ├── models/             # 数据模型
│   ├── app.js              # 应用入口
│   └── index.js            # 服务器启动文件
├── test/                   # 测试文件
├── package.json
└── README.md

3. 启动项目

bash
# 进入项目目录
cd my-feathers-app

# 安装依赖
npm install

# 启动开发服务器
npm run dev

如果一切正常,你会看到:

info: Feathers application started on http://localhost:3030

测试基础功能

1. 访问 API

打开浏览器访问 http://localhost:3030,你会看到 Feathers.js 的欢迎页面。

2. 测试用户注册

bash
# 使用 curl 注册新用户
curl -X POST http://localhost:3030/users \
  -H "Content-Type: application/json" \
  -d '{
    "email": "test@example.com",
    "password": "password123"
  }'

你会得到类似这样的响应:

json
{
  "id": 1,
  "email": "test@example.com",
  "createdAt": "2024-05-06T10:00:00.000Z",
  "updatedAt": "2024-05-06T10:00:00.000Z"
}

3. 测试用户登录

bash
# 登录获取 JWT token
curl -X POST http://localhost:3030/authentication \
  -H "Content-Type: application/json" \
  -d '{
    "strategy": "local",
    "email": "test@example.com",
    "password": "password123"
  }'

响应会包含访问令牌:

json
{
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "authentication": {
    "strategy": "local"
  },
  "user": {
    "id": 1,
    "email": "test@example.com"
  }
}

创建第一个服务

现在我们来创建一个消息服务,体验 Feathers.js 的强大功能:

1. 生成服务

bash
# 生成消息服务
feathers generate service

# 按照提示选择:
? What kind of service is it? KnexJS (SQL)
? What is the name of the service? messages
? Which path should the service be registered on? /messages
? What is the database table name? messages
? Does the service require authentication? Yes

2. 查看生成的文件

CLI 会生成以下文件:

src/
├── services/
│   └── messages/
│       ├── messages.class.js      # 服务类
│       ├── messages.hooks.js      # 钩子配置
│       └── messages.service.js    # 服务注册
└── models/
    └── messages.model.js          # 数据模型

3. 查看消息模型

打开 src/models/messages.model.js

javascript
module.exports = function (app) {
  const db = app.get('knexClient');
  const tableName = 'messages';
  
  db.schema.hasTable(tableName).then(exists => {
    if (!exists) {
      db.schema.createTable(tableName, table => {
        table.increments('id');
        table.string('text').notNullable();
        table.integer('userId').unsigned().notNullable();
        table.timestamp('createdAt').defaultTo(db.fn.now());
        table.timestamp('updatedAt').defaultTo(db.fn.now());
        
        table.foreign('userId').references('id').inTable('users');
      })
      .then(() => console.log(`Created \${tableName} table`))
      .catch(e => console.error(`Error creating \${tableName} table`, e));
    }
  });

  return db;
};

4. 重启服务器

bash
# 重启服务器以应用更改
npm run dev

测试消息服务

1. 创建消息

首先需要获取认证令牌(使用之前登录获得的 token):

bash
# 创建新消息
curl -X POST http://localhost:3030/messages \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -d '{
    "text": "Hello, Feathers.js!"
  }'

2. 获取消息列表

bash
# 获取所有消息
curl -X GET http://localhost:3030/messages \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

3. 获取特定消息

bash
# 获取 ID 为 1 的消息
curl -X GET http://localhost:3030/messages/1 \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

实时功能测试

Feathers.js 的一大亮点就是实时功能。让我们创建一个简单的 HTML 页面来测试:

1. 创建测试页面

在项目根目录创建 public/index.html

html
<!DOCTYPE html>
<html>
<head>
  <title>Feathers.js 实时测试</title>
  <script src="//unpkg.com/@feathersjs/client@^5.0.0/dist/feathers.js"></script>
  <script src="/socket.io/socket.io.js"></script>
</head>
<body>
  <h1>Feathers.js 实时消息</h1>
  
  <div id="login-form">
    <h3>登录</h3>
    <input type="email" id="email" placeholder="邮箱" value="test@example.com">
    <input type="password" id="password" placeholder="密码" value="password123">
    <button onclick="login()">登录</button>
  </div>
  
  <div id="app" style="display: none;">
    <h3>发送消息</h3>
    <input type="text" id="messageText" placeholder="输入消息">
    <button onclick="sendMessage()">发送</button>
    
    <h3>消息列表</h3>
    <div id="messages"></div>
  </div>

  <script>
    // 连接到 Feathers.js 服务器
    const socket = io();
    const client = feathers();
    
    client.configure(feathers.socketio(socket));
    client.configure(feathers.authentication());

    // 登录函数
    async function login() {
      try {
        const email = document.getElementById('email').value;
        const password = document.getElementById('password').value;
        
        await client.authenticate({
          strategy: 'local',
          email,
          password
        });
        
        document.getElementById('login-form').style.display = 'none';
        document.getElementById('app').style.display = 'block';
        
        // 监听实时消息
        client.service('messages').on('created', (message) => {
          addMessageToList(message);
        });
        
        // 加载现有消息
        const messages = await client.service('messages').find();
        messages.data.forEach(addMessageToList);
        
      } catch (error) {
        alert('登录失败: ' + error.message);
      }
    }

    // 发送消息函数
    async function sendMessage() {
      const text = document.getElementById('messageText').value;
      if (!text) return;
      
      try {
        await client.service('messages').create({ text });
        document.getElementById('messageText').value = '';
      } catch (error) {
        alert('发送失败: ' + error.message);
      }
    }

    // 添加消息到列表
    function addMessageToList(message) {
      const messagesDiv = document.getElementById('messages');
      const messageDiv = document.createElement('div');
      messageDiv.innerHTML = `
        <p><strong>用户 \${message.userId}:</strong> \${message.text}</p>
        <small>\${new Date(message.createdAt).toLocaleString()}</small>
        <hr>
      `;
      messagesDiv.appendChild(messageDiv);
    }
  </script>
</body>
</html>

2. 配置静态文件服务

修改 src/app.js,在认证配置之前添加:

javascript
// 配置静态文件服务
app.use(express.static(app.get('public')));

确保 config/default.json 中有 public 目录配置:

json
{
  "host": "localhost",
  "port": 3030,
  "public": "../public/",
  // ... 其他配置
}

3. 测试实时功能

  1. 重启服务器:npm run dev
  2. 打开浏览器访问 http://localhost:3030
  3. 使用之前创建的账号登录
  4. 打开多个浏览器标签页,在一个页面发送消息,其他页面会实时收到!

添加消息验证

让我们给消息服务添加一些验证逻辑:

1. 修改消息钩子

编辑 src/services/messages/messages.hooks.js

javascript
const { authenticate } = require('@feathersjs/authentication').hooks;

module.exports = {
  before: {
    all: [ authenticate('jwt') ],
    find: [],
    get: [],
    create: [
      // 添加用户ID
      context => {
        context.data.userId = context.params.user.id;
        return context;
      },
      // 验证消息内容
      context => {
        const { text } = context.data;
        
        if (!text || text.trim().length === 0) {
          throw new Error('消息内容不能为空');
        }
        
        if (text.length > 280) {
          throw new Error('消息长度不能超过280个字符');
        }
        
        // 清理消息内容
        context.data.text = text.trim();
        
        return context;
      }
    ],
    update: [],
    patch: [],
    remove: []
  },

  after: {
    all: [],
    find: [],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: []
  },

  error: {
    all: [],
    find: [],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: []
  }
};

2. 测试验证功能

重启服务器后,尝试发送空消息或超长消息,你会看到相应的错误提示。

项目总结

恭喜!在短短15分钟内,我们完成了:

搭建了完整的 Feathers.js 应用

  • 用户注册和认证系统
  • JWT 令牌管理
  • SQLite 数据库集成

创建了消息服务

  • REST API 接口
  • 数据验证和清理
  • 用户权限控制

实现了实时功能

  • WebSocket 连接
  • 实时消息推送
  • 多客户端同步

添加了前端界面

  • 用户登录
  • 消息发送
  • 实时显示

下一步学习建议

  1. 深入理解核心概念

    • Services 服务架构
    • Hooks 钩子系统
    • Channels 实时频道
  2. 数据库集成

    • MongoDB 适配器
    • 复杂查询和关联
    • 数据迁移
  3. 高级功能

    • 文件上传
    • 邮件发送
    • 第三方认证

常见问题

Q: 为什么选择 SQLite?

A: SQLite 不需要额外安装数据库服务器,非常适合开发和学习。生产环境建议使用 PostgreSQL 或 MySQL。

Q: 如何部署到生产环境?

A: 修改 config/production.json 配置,使用 PM2 或 Docker 部署。

Q: 实时功能的性能如何?

A: Feathers.js 基于 Socket.io,性能很好。对于高并发场景,可以配置 Redis 适配器。

Q: 如何添加更多认证方式?

A: Feathers.js 支持 OAuth、GitHub、Google 等多种认证策略,通过插件即可集成。

总结

通过这个快速上手教程,相信你已经感受到了 Feathers.js 的强大和简洁。仅仅几行代码,我们就实现了一个功能完整的实时 API,这在传统框架中是很难想象的。

Feathers.js 的魅力在于:

  • 约定优于配置 - 遵循最佳实践,减少决策疲劳
  • 实时优先 - 实时功能不是附加品,而是核心特性
  • 渐进式增强 - 可以从简单开始,逐步添加复杂功能

下一篇文章,我们将深入学习 Feathers.js 的核心概念,包括 Services、Hooks 和 Channels 的详细用法。


相关文章推荐:

有问题欢迎留言讨论,我会及时回复大家!