Mastering the foundation of modern web APIs in COMP1531. 掌握 COMP1531 中现代 Web API 的基石。
Before handling any routes, every Express application needs a skeleton. The most critical part is middleware. 在处理任何路由之前,每个 Express 应用程序都需要一个骨架。最关键的部分是中间件。
import express from 'express'; const app = express(); const PORT = 3000; // CRITICAL: Middleware to parse JSON bodies // Without this, req.body will be undefined! app.use(express.json()); // Basic "Hello World" route app.get('/', (req, res) => { res.json({ message: 'Server is running!' }); });
app.use() defines middleware. Middleware
functions execute sequentially before the request reaches your specific route handler.
express.json() is a built-in middleware that looks at the
Content-Type: application/json header and extracts the raw bytes into a JavaScript
object.
app.use()
定义了中间件。中间件函数在请求到达具体路由处理器之前按顺序执行。express.json()
是一个内置中间件,它会检查 Content-Type: application/json 请求头,并将原始字节提取到 JavaScript 对象中。
Express provides three distinct ways to extract data from a request. Choosing the right one is key to good API design. Express 提供了三种不同的方式从请求中提取数据。选择正确的方式是优秀 API 设计的关键。
| Variable变量 | Extraction Type提取类型 | Data Format数据格式 | Best Practice最佳实践 |
|---|---|---|---|
req.body |
Payload载荷 | Objects/Arrays对象/数组 | New data for POST/PUTPOST/PUT 的新数据 |
req.params |
Route Variables路由变量 | Strings (IDs)字符串 (ID) | Specific Resource identification特定资源识别 |
req.query |
Question Mark URL问号 URL | Key-Value pairs键值对 | Filtering and Sorting过滤和排序 |
// 1. Using req.params (Path Variables) // URL: /user/123/profile app.get('/user/:userId/profile', (req, res) => { const id = parseInt(req.params.userId as string); res.json({ userId: id, name: 'Evan' }); }); // 2. Using req.query (Search Parameters) // URL: /search?type=admin&sort=desc app.get('/search', (req, res) => { const { type, sort } = req.query; res.json({ results: [], type, sort }); }); // 3. Using req.body (JSON Payload) // Method: POST | URL: /register | Body: {"email": "..."} app.post('/register', (req, res) => { const { email, password } = req.body; // Logic to save to data store res.json({ status: 'Success' }); });
Both req.params and req.query are parsed directly
from the URL. This means they are **ALWAYS** strings. If your data store uses numerical IDs, you
must use parseInt() or Number() before comparison.
Comparing "123" === 123 will return false!
req.params 和 req.query 都是直接从 URL
解析的。这意味着它们始终是字符串。如果你的数据存储使用数字 ID,你在比较之前必须使用
parseInt() 或 Number()。比较 "123" === 123 将返回
false!
To clear any final confusion, here is a definitive comparison table of the three ways to pass data: 为了让你不再混淆,我们看这张对比表:
| Source来源 | Example位置示例 | Extraction Code在 Express 中拿取的代码 | Usage Scenarios适用场景 |
|---|---|---|---|
| Path Params | /user/123 |
req.params.id |
Identify a unique resource (e.g., a specific user) 唯一定位一个资源 (如:看哪个特定用户) |
| Query Params | /user?id=123 |
req.query.id |
Filtering or searching results 过滤/搜索结果 (如:按 ID 搜索用户) |
| Body (JSON) | { "id": 123 } |
req.body.id |
Submitting/modifying large or sensitive data 提交或修改大量数据、敏感数据 |
Express matches routes in the order they are defined (Top-to-Bottom). Specific routes must come BEFORE generic routes. Express 按定义顺序(从上到下)匹配路由。具体路由必须在通用路由之前定义。
// Generic route matches first app.get('/user/:id', ...); // This will NEVER be reached! // 'me' is treated as an ':id' app.get('/user/me', ...);
// Specific route first app.get('/user/me', ...); // Generic route second app.get('/user/:id', ...);
If you call res.json() and then let the code continue into
another res.json(), the server will crash with
ERR_HTTP_HEADERS_SENT.
如果你调用 res.json() 后让代码继续执行到另一个
res.json(),服务器会崩溃并提示 ERR_HTTP_HEADERS_SENT。
if (error) { res.status(400).json({ error }); return; // DO NOT REMOVE THIS RETURN! } res.json({ data: 'Success' });
res.status(400).json() for errors in COMP1531. Don't mix res.send
and res.json.
一致性:在 COMP1531 中始终对错误使用
res.status(400).json()。不要混用 res.send 和
res.json。
/order/new) and follow the RESTful mindset even if not fully implementing it
yet.
路由命名:对资源使用名词(例如 /order/new),即使尚未完全实现,也要遵循
RESTful 思路。
sync-request-curl for
black-box testing. Ensure it covers success (200) and failure (400) cases.
测试:使用 sync-request-curl 进行黑盒测试。确保它涵盖了成功
(200) 和失败 (400) 的情况。
Test your understanding of route parameters, matching order, and error handling. 测试你对路由参数、匹配顺序和错误处理的理解。
🎯 Start 50-Question Challenge 🎯 开始 50 题挑战