Skip to content

实训:快速搭建 restful 后端

第 11 周的个人应用需要真正的后端,但此刻还没有学过后端开发——本实训的目标正是:不写(几行)后端代码,获得一个符合 REST 习惯、并进一步规范化为 JSON:API 形态的 API 服务,把精力留给前端。

两条路线:

  • 路线 A:json-server——5 分钟起步,零代码,满足大部分练习需求
  • 路线 B:30 行 express——亲手看清 JSON:API 信封是怎么包出来的

前置:Node 与 npm 已安装(见Node 环境构建;npm 基本命令见NPM)。工作目录:任意空文件夹 myapi/

路线 A:json-server,5 分钟得到 REST API

  1. 写数据文件 db.json——它就是你的"数据库":
import "./styles.css";

document.getElementById("app").innerHTML = `
<h1>Hello world</h1>
`;

  1. 启动服务(无需写任何服务器代码):
bash
npx json-server db.json --port 3000
  1. 用 REST 客户端验证五件套(工具见restful):
操作请求结果
列表GET http://localhost:3000/bookmarks全部书签
单个GET http://localhost:3000/bookmarks/1一条书签
新增POST 同 URL,请求体 JSON自动生成 id 并入库
修改PUT .../bookmarks/1,请求体 JSON整条替换
删除DELETE .../bookmarks/1从 db.json 移除
  1. 顺手体验查询能力(不写代码就有的):
plain
过滤与多值      GET /bookmarks?title=MDN
              GET /posts?id=1&id=2
全文搜索        GET /bookmarks?q=css
比较谓词        GET /products?price_gte=10&price_lte=80   (_gte _lte _ne _like)
排序、分页      GET /products?_sort=price&_order=asc
              GET /posts?_page=1&_limit=10
              GET /posts?_start=20&_end=30&_limit=10
关联查询        GET /comments?author.name=张三

打开 db.json 看——POST/PUT/DELETE 的结果真的写进了文件,这就是"持久化"。(Windows 下若用 --watch 无效的老版本,修改 db.json 后需重启服务。)

理解要点:json-server 把 db.json 的每个 key 自动映射为资源集合,资源的名词、动词的语义全部来自 REST 约定——你亲眼看到了规范带来的"零文档可用性"。

路线 B:30 行 express,看清 JSON:API 信封

json-server 返回的是"裸 JSON",不是 JSON:API 信封。想体会信封是怎么包出来的,手工写一遍最清楚。

  1. 初始化并安装依赖
bash
npm init -y
npm install express
  1. server.js——内存数据库 + 统一信封:
javascript
const express = require("express");
const app = express();
app.use(express.json());                 // 解析 JSON 请求体

let bookmarks = [                        // 内存数据库
  { id: 1, title: "MDN", url: "https://developer.mozilla.org" },
];

// 信封函数:把裸数据包成 JSON:API 形态——所有接口共用
const wrap = (b) => ({
  data: {
    type: "bookmarks",
    id: String(b.id),
    attributes: { title: b.title, url: b.url },
  },
});

app.get("/api/bookmarks", (req, res) =>
  res.json({ data: bookmarks.map(wrap) }));

app.get("/api/bookmarks/:id", (req, res) => {
  const b = bookmarks.find(x => x.id == req.params.id);
  if (!b) return res.status(404).json({ errors: [{ title: "未找到" }] });
  res.json(wrap(b));
});

app.post("/api/bookmarks", (req, res) => {
  const b = { id: Date.now(), ...req.body };
  bookmarks.push(b);
  res.status(201).json(wrap(b));         // 201 Created
});

app.delete("/api/bookmarks/:id", (req, res) => {
  bookmarks = bookmarks.filter(x => x.id != req.params.id);
  res.status(204).end();                 // 204 No Content
});

app.listen(3000, () => console.log("JSON:API on http://localhost:3000"));
  1. 启动并对比node server.js,再用 REST 客户端请求 http://localhost:3000/api/bookmarks

  2. 观察三个设计决定

    • wrap() 函数是全篇关键——信封与数据的分离只发生在一处,业务代码(增删查)完全不知道 JSON:API 的存在
    • 状态码开始"说话":201(已创建)、204(成功但无返回体)、404——它们是 API 语义的一部分(呼应HTTP协议
    • 错误用 errors 数组返回——前端从此可以用一套逻辑处理所有错误

收尾:两条路线怎么选

json-serverexpress 手写
代码量0 行~30 行
返回形态裸 JSON可控(示例为 JSON:API)
适用前端练习、原型需要自定义行为时
  • 第 11 周书签应用直接对接路线 A 即可;第 13 周 Node 之后回头看路线 B 会非常轻松
  • 生产中的后端框架会自动产出 JSON:API(如 NestJS、Laravel 的 jsonapi 扩展),本实训的 wrap() 就是它们的雏形
  • 走得更远:Supabase 提供带登录等功能模块的托管 restful 服务,可以纯前端技术开发功能完善的联网应用(超出本周范围,仅作了解)

验收标准

  • [ ] json-server 跑通 CRUD 五件套,POST 结果在 db.json 可见
  • [ ] 能说出 REST 四条主张里的至少两条
  • [ ] (选做)路线 B 跑通,并能指出 wrap() 在哪、201/204 各是什么含义