Network: Connected devices that can communicate
Internet: Global network of networks
World Wide Web (WWW): Information system on the Internet
HTTP: HyperText Transfer Protocol - communication protocol
import express from 'express';
const app = express();
const port = 3000;
// Middleware to parse JSON
app.use(express.json());
// Basic route
app.get('/hello', (req, res) => {
res.send('Hello World!');
});
// Start server
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
1. Query Parameters (req.query)
// URL: /search?name=John&age=25
app.get('/search', (req, res) => {
const name = req.query.name;
const age = req.query.age;
res.json({ name, age });
});
2. URL Parameters (req.params)
// URL: /users/123
app.get('/users/:id', (req, res) => {
const userId = req.params.id;
res.json({ userId });
});
3. Request Body (req.body)
// POST request with JSON body
app.post('/users', (req, res) => {
const { name, email } = req.body;
res.json({ name, email });
});
| Method | Operation | Description |
|---|---|---|
GET |
Read | Retrieve data from server |
POST |
Create | Create new resource |
PUT |
Update | Update existing resource |
DELETE |
Delete | Remove resource |
let books = [
{ id: 1, title: 'The Hobbit', author: 'J.R.R. Tolkien', year: 1937 }
];
// CREATE - Add new book
app.post('/books', (req, res) => {
const newBook = {
id: books.length + 1,
title: req.body.title,
author: req.body.author,
year: req.body.year
};
books.push(newBook);
res.status(201).json(newBook);
});
// READ - Get all books
app.get('/books', (req, res) => {
res.json(books);
});
// READ - Get single book
app.get('/books/:id', (req, res) => {
const book = books.find(b => b.id === parseInt(req.params.id));
if (!book) {
return res.status(404).json({ error: 'Book not found' });
}
res.json(book);
});
// UPDATE - Update book
app.put('/books/:id', (req, res) => {
const book = books.find(b => b.id === parseInt(req.params.id));
if (!book) {
return res.status(404).json({ error: 'Book not found' });
}
book.title = req.body.title;
book.author = req.body.author;
book.year = req.body.year;
res.json(book);
});
// DELETE - Remove book
app.delete('/books/:id', (req, res) => {
const index = books.findIndex(b => b.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({ error: 'Book not found' });
}
books.splice(index, 1);
res.status(204).send();
});
Installation:
npm install sync-request-curl
import request from 'sync-request-curl';
// GET request
const res = request(
'GET',
'http://localhost:3000/books/1'
);
const bodyObj = JSON.parse(String(res.getBody()));
console.log(bodyObj);
// POST request
const postRes = request(
'POST',
'http://localhost:3000/books',
{
json: {
title: 'New Book',
author: 'Author Name',
year: 2025
}
}
);
import request from 'sync-request-curl';
describe('Test GET /books/:id', () => {
test('Returns book info successfully', () => {
const res = request(
'GET',
'http://localhost:3000/books/1'
);
const bodyObj = JSON.parse(String(res.getBody()));
expect(bodyObj).toBe(JSON.stringify({
id: 1,
title: 'The Hobbit',
author: 'J.R.R. Tolkien',
year: 1937
}));
});
});
describe('Test POST /books', () => {
test('Creates new book successfully', () => {
const res = request(
'POST',
'http://localhost:3000/books',
{
json: {
title: 'New Book',
author: 'Author',
year: 2025
}
}
);
const bodyObj = JSON.parse(String(res.getBody()));
expect(bodyObj).toBe(JSON.stringify({
id: 2,
title: 'New Book',
author: 'Author',
year: 2025
}));
});
});
npx jest requests.test.ts
| Category | Range | Meaning |
|---|---|---|
| Success | 2xx | Request successful |
| Client Error | 4xx | Client made an error |
| Server Error | 5xx | Server encountered an error |
| Code | Status | Description |
|---|---|---|
| 200 | OK | Request successful |
| 201 | Created | Resource created successfully |
| 204 | No Content | Success but no content to return |
| 400 | Bad Request | Invalid request format |
| 404 | Not Found | Resource not found |
| 500 | Internal Server Error | Server encountered an error |
// Success with custom status
app.post('/books', (req, res) => {
// ... create book
res.status(201).json(newBook);
});
// Error handling
app.get('/books/:id', (req, res) => {
const book = books.find(b => b.id === parseInt(req.params.id));
if (!book) {
return res.status(404).json({ error: 'Book not found' });
}
res.status(200).json(book);
});
// Server error
app.get('/error', (req, res) => {
res.status(500).json({ error: 'Internal server error' });
});
Swagger (now called OpenAPI) is a standard for describing RESTful APIs in a machine and human-readable format.
import express from 'express';
const app = express();
const port = 3000;
const swaggerUi = require('swagger-ui-express');
const YAML = require('yamljs');
// Load Swagger YAML file
const swaggerDocument = YAML.load('swagger.yaml');
// Serve Swagger UI at /api-docs
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
// Access at: http://localhost:3000/api-docs
What HTTPS encrypts:
| Method | Visible in Logs | Cached | Browser History | Encrypted by HTTPS | Safe for Passwords |
|---|---|---|---|---|---|
| URL (query string) | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | ❌ No |
| POST body | ❌ No | ❌ No | ❌ No | ✅ Yes | ✅ Yes |
| Tool | Speed | Configuration | Recommendation |
|---|---|---|---|
ts-node |
Slower | Needs config | Legacy projects |
tsx |
Fast | Minimal config | ✅ Better choice |
Network (网络): 可以通信的连接设备
Internet (互联网): 全球网络的网络
World Wide Web (万维网): 互联网上的信息系统
HTTP: 超文本传输协议 - 通信协议
import express from 'express';
const app = express();
const port = 3000;
// 解析JSON的中间件
app.use(express.json());
// 基本路由
app.get('/hello', (req, res) => {
res.send('Hello World!');
});
// 启动服务器
app.listen(port, () => {
console.log(`服务器监听端口 ${port}`);
});
1. 查询参数 (req.query)
// URL: /search?name=John&age=25
app.get('/search', (req, res) => {
const name = req.query.name;
const age = req.query.age;
res.json({ name, age });
});
2. URL参数 (req.params)
// URL: /users/123
app.get('/users/:id', (req, res) => {
const userId = req.params.id;
res.json({ userId });
});
3. 请求体 (req.body)
// POST请求带JSON body
app.post('/users', (req, res) => {
const { name, email } = req.body;
res.json({ name, email });
});
| 方法 | 操作 | 描述 |
|---|---|---|
GET |
读取 | 从服务器获取数据 |
POST |
创建 | 创建新资源 |
PUT |
更新 | 更新现有资源 |
DELETE |
删除 | 删除资源 |
let books = [
{ id: 1, title: 'The Hobbit', author: 'J.R.R. Tolkien', year: 1937 }
];
// 创建 - 添加新书
app.post('/books', (req, res) => {
const newBook = {
id: books.length + 1,
title: req.body.title,
author: req.body.author,
year: req.body.year
};
books.push(newBook);
res.status(201).json(newBook);
});
// 读取 - 获取所有书籍
app.get('/books', (req, res) => {
res.json(books);
});
// 读取 - 获取单本书
app.get('/books/:id', (req, res) => {
const book = books.find(b => b.id === parseInt(req.params.id));
if (!book) {
return res.status(404).json({ error: '书籍未找到' });
}
res.json(book);
});
// 更新 - 更新书籍
app.put('/books/:id', (req, res) => {
const book = books.find(b => b.id === parseInt(req.params.id));
if (!book) {
return res.status(404).json({ error: '书籍未找到' });
}
book.title = req.body.title;
book.author = req.body.author;
book.year = req.body.year;
res.json(book);
});
// 删除 - 删除书籍
app.delete('/books/:id', (req, res) => {
const index = books.findIndex(b => b.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({ error: '书籍未找到' });
}
books.splice(index, 1);
res.status(204).send();
});
安装:
npm install sync-request-curl
import request from 'sync-request-curl';
// GET请求
const res = request(
'GET',
'http://localhost:3000/books/1'
);
const bodyObj = JSON.parse(String(res.getBody()));
console.log(bodyObj);
// POST请求
const postRes = request(
'POST',
'http://localhost:3000/books',
{
json: {
title: '新书',
author: '作者名',
year: 2025
}
}
);
import request from 'sync-request-curl';
describe('测试 GET /books/:id', () => {
test('成功返回书籍信息', () => {
const res = request(
'GET',
'http://localhost:3000/books/1'
);
const bodyObj = JSON.parse(String(res.getBody()));
expect(bodyObj).toBe(JSON.stringify({
id: 1,
title: 'The Hobbit',
author: 'J.R.R. Tolkien',
year: 1937
}));
});
});
describe('测试 POST /books', () => {
test('成功创建新书', () => {
const res = request(
'POST',
'http://localhost:3000/books',
{
json: {
title: '新书',
author: '作者',
year: 2025
}
}
);
const bodyObj = JSON.parse(String(res.getBody()));
expect(bodyObj).toBe(JSON.stringify({
id: 2,
title: '新书',
author: '作者',
year: 2025
}));
});
});
npx jest requests.test.ts
| 类别 | 范围 | 含义 |
|---|---|---|
| 成功 | 2xx | 请求成功 |
| 客户端错误 | 4xx | 客户端出错 |
| 服务器错误 | 5xx | 服务器遇到错误 |
| 代码 | 状态 | 描述 |
|---|---|---|
| 200 | OK | 请求成功 |
| 201 | Created | 资源创建成功 |
| 204 | No Content | 成功但无内容返回 |
| 400 | Bad Request | 无效的请求格式 |
| 404 | Not Found | 资源未找到 |
| 500 | Internal Server Error | 服务器遇到错误 |
// 成功并自定义状态码
app.post('/books', (req, res) => {
// ... 创建书籍
res.status(201).json(newBook);
});
// 错误处理
app.get('/books/:id', (req, res) => {
const book = books.find(b => b.id === parseInt(req.params.id));
if (!book) {
return res.status(404).json({ error: '书籍未找到' });
}
res.status(200).json(book);
});
// 服务器错误
app.get('/error', (req, res) => {
res.status(500).json({ error: '内部服务器错误' });
});
Swagger (现称为OpenAPI) 是一种以机器和人类可读格式描述RESTful API的标准。
import express from 'express';
const app = express();
const port = 3000;
const swaggerUi = require('swagger-ui-express');
const YAML = require('yamljs');
// 加载Swagger YAML文件
const swaggerDocument = YAML.load('swagger.yaml');
// 在 /api-docs 提供Swagger UI
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
// 访问地址: http://localhost:3000/api-docs
HTTPS加密的内容:
| 方法 | 日志中可见 | 被缓存 | 浏览器历史 | HTTPS加密 | 密码安全 |
|---|---|---|---|---|---|
| URL (查询字符串) | ✅ 是 | ✅ 是 | ✅ 是 | ✅ 是 | ❌ 否 |
| POST body | ❌ 否 | ❌ 否 | ❌ 否 | ✅ 是 | ✅ 是 |
| 工具 | 速度 | 配置 | 推荐 |
|---|---|---|---|
ts-node |
较慢 | 需要配置 | 旧项目 |
tsx |
快速 | 最少配置 | ✅ 更好选择 |