您现在的位置是:网站首页 > RESTful API设计文章详情

RESTful API设计

RESTful API设计概述

RESTful API是一种基于HTTP协议的API设计风格,它利用HTTP方法(GET、POST、PUT、DELETE等)来操作资源。这种设计风格强调资源的唯一标识(URI)和统一接口,使得API更加简洁、可扩展和易于理解。

RESTful API的核心原则

资源导向

RESTful API的核心是资源,每个资源都有一个唯一的URI标识。资源可以是任何事物,如用户、订单、商品等。URI应该使用名词而不是动词,并且采用复数形式。

// 不好的设计
GET /getUsers
POST /createUser

// 好的设计
GET /users
POST /users

统一接口

RESTful API使用标准的HTTP方法来表示对资源的操作:

  • GET:获取资源
  • POST:创建资源
  • PUT:更新整个资源
  • PATCH:部分更新资源
  • DELETE:删除资源
// 获取所有用户
GET /users

// 创建新用户
POST /users
{
  "name": "张三",
  "email": "zhangsan@example.com"
}

// 更新用户信息
PUT /users/1
{
  "name": "张三",
  "email": "newemail@example.com"
}

// 删除用户
DELETE /users/1

无状态性

每个请求都应该包含处理该请求所需的所有信息,服务器不应该保存客户端的状态。这使得API更容易扩展和维护。

URI设计规范

资源命名

  • 使用名词而不是动词
  • 使用复数形式
  • 使用小写字母
  • 单词间用连字符(-)连接
// 不好的设计
GET /getUserOrders
POST /createNewProduct

// 好的设计
GET /users/1/orders
POST /products

层级关系

使用URI路径表示资源之间的关系:

// 获取用户1的所有订单
GET /users/1/orders

// 获取用户1的订单2的详细信息
GET /users/1/orders/2

查询参数

使用查询参数进行过滤、排序和分页:

// 过滤
GET /products?category=electronics

// 排序
GET /products?sort=price&order=desc

// 分页
GET /products?page=2&limit=10

HTTP状态码

使用合适的HTTP状态码表示请求结果:

  • 200 OK - 成功请求
  • 201 Created - 资源创建成功
  • 204 No Content - 成功但无返回内容
  • 400 Bad Request - 请求错误
  • 401 Unauthorized - 未授权
  • 403 Forbidden - 禁止访问
  • 404 Not Found - 资源不存在
  • 500 Internal Server Error - 服务器错误
// 成功创建资源
POST /users
Response: 201 Created

// 资源不存在
GET /users/999
Response: 404 Not Found

版本控制

API应该包含版本信息,可以通过以下方式实现:

  1. URI路径:
GET /v1/users
  1. 请求头:
GET /users
Headers: Accept: application/vnd.myapi.v1+json
  1. 查询参数:
GET /users?version=1

数据格式

请求和响应格式

通常使用JSON格式:

// 请求示例
POST /users
{
  "name": "李四",
  "email": "lisi@example.com"
}

// 响应示例
{
  "id": 2,
  "name": "李四",
  "email": "lisi@example.com",
  "createdAt": "2023-05-20T10:00:00Z"
}

错误响应

错误响应应该包含错误详情:

{
  "error": {
    "code": "invalid_email",
    "message": "邮箱格式不正确",
    "details": {
      "email": "不是有效的邮箱地址"
    }
  }
}

认证和授权

基本认证

Authorization: Basic base64(username:password)

Bearer Token

Authorization: Bearer <token>

JWT

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

缓存控制

使用HTTP缓存头提高性能:

Cache-Control: max-age=3600
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT

限流

防止API被滥用:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1684567890

HATEOAS

超媒体作为应用状态引擎,提供资源间的导航:

{
  "id": 1,
  "name": "张三",
  "links": [
    {
      "rel": "self",
      "href": "/users/1"
    },
    {
      "rel": "orders",
      "href": "/users/1/orders"
    }
  ]
}

Node.js实现示例

使用Express实现RESTful API:

const express = require('express');
const app = express();
app.use(express.json());

let users = [
  { id: 1, name: '张三' },
  { id: 2, name: '李四' }
];

// 获取所有用户
app.get('/users', (req, res) => {
  res.json(users);
});

// 获取单个用户
app.get('/users/:id', (req, res) => {
  const user = users.find(u => u.id === parseInt(req.params.id));
  if (!user) return res.status(404).json({ error: '用户不存在' });
  res.json(user);
});

// 创建用户
app.post('/users', (req, res) => {
  const user = {
    id: users.length + 1,
    name: req.body.name
  };
  users.push(user);
  res.status(201).json(user);
});

// 更新用户
app.put('/users/:id', (req, res) => {
  const user = users.find(u => u.id === parseInt(req.params.id));
  if (!user) return res.status(404).json({ error: '用户不存在' });
  
  user.name = req.body.name;
  res.json(user);
});

// 删除用户
app.delete('/users/:id', (req, res) => {
  users = users.filter(u => u.id !== parseInt(req.params.id));
  res.status(204).end();
});

app.listen(3000, () => console.log('服务器运行在3000端口'));

测试RESTful API

使用Postman或curl测试API:

# 获取所有用户
curl http://localhost:3000/users

# 创建用户
curl -X POST -H "Content-Type: application/json" -d '{"name":"王五"}' http://localhost:3000/users

# 更新用户
curl -X PUT -H "Content-Type: application/json" -d '{"name":"赵六"}' http://localhost:3000/users/1

# 删除用户
curl -X DELETE http://localhost:3000/users/1

文档化API

使用Swagger/OpenAPI规范文档化API:

openapi: 3.0.0
info:
  title: 用户API
  version: 1.0.0
paths:
  /users:
    get:
      summary: 获取所有用户
      responses:
        '200':
          description: 成功获取用户列表
    post:
      summary: 创建新用户
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/User'
      responses:
        '201':
          description: 用户创建成功
components:
  schemas:
    User:
      type: object
      properties:
        name:
          type: string
      required:
        - name

性能优化

压缩响应

const compression = require('compression');
app.use(compression());

数据库查询优化

// 不好的做法
app.get('/users', async (req, res) => {
  const users = await User.find();
  res.json(users);
});

// 好的做法 - 只返回需要的字段
app.get('/users', async (req, res) => {
  const users = await User.find().select('name email');
  res.json(users);
});

安全性考虑

输入验证

const { body, validationResult } = require('express-validator');

app.post('/users', 
  body('email').isEmail(),
  body('password').isLength({ min: 6 }),
  (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }
    // 处理请求
  }
);

CORS配置

const cors = require('cors');
app.use(cors({
  origin: ['https://example.com', 'https://another-domain.com'],
  methods: ['GET', 'POST', 'PUT', 'DELETE']
}));

监控和日志

const morgan = require('morgan');
app.use(morgan('combined'));

// 自定义中间件记录请求和响应
app.use((req, res, next) => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
  next();
});

微服务架构中的RESTful API

在微服务架构中,每个服务通常提供一组RESTful API:

// 用户服务
GET /api/users

// 订单服务
GET /api/orders

// 商品服务
GET /api/products

GraphQL与RESTful API对比

虽然RESTful API是主流,但GraphQL提供了更灵活的数据查询:

// RESTful - 多个请求
GET /users/1
GET /users/1/orders

// GraphQL - 单个请求
query {
  user(id: 1) {
    name
    orders {
      id
      total
    }
  }
}

实际项目中的最佳实践

  1. 使用中间件处理公共逻辑
// 认证中间件
const authenticate = (req, res, next) => {
  const token = req.headers.authorization;
  if (!token) return res.status(401).json({ error: '未授权' });
  // 验证token
  next();
};

app.get('/profile', authenticate, (req, res) => {
  // 返回用户资料
});
  1. 使用路由分离
// routes/users.js
const router = express.Router();
router.get('/', getUserList);
router.post('/', createUser);
module.exports = router;

// app.js
const userRoutes = require('./routes/users');
app.use('/users', userRoutes);
  1. 使用环境变量配置
// .env
API_PORT=3000
DB_URL=mongodb://localhost:27017/myapp

// app.js
require('dotenv').config();
const port = process.env.API_PORT || 3000;
app.listen(port);

我的名片

网名:~川~

岗位:console.log 调试员

坐标:重庆市-九龙坡区

邮箱:cc@qdcc.cn

沙漏人生

站点信息

  • 建站时间:2013/03/16
  • 本站运行
  • 文章数量
  • 总访问量
微信公众号
每次关注
都是向财富自由迈进的一步