1. 什么是 RESTful API?
REST(Representational State Transfer,表述性状态转移)是一种软件架构风格,用于设计网络应用程序的接口。RESTful API 是基于 REST 原则设计的 API,它使用标准的 HTTP 方法(GET、POST、PUT、DELETE 等)对资源进行操作,并通过 HTTP 状态码和媒体类型(如 JSON、XML)进行通信。
RESTful API 的核心特征包括:
- 无状态(Stateless):每个请求都包含处理该请求所需的全部信息,服务器不保存客户端状态。
- 统一接口(Uniform Interface):使用标准的 HTTP 方法和资源标识符(URI)。
- 资源导向(Resource-Oriented):将数据和功能都视为资源,通过 URI 进行标识。
- 可缓存(Cacheable):响应应明确标识是否可缓存,以提高性能。
- 分层系统(Layered System):客户端无需知道是否直接连接到最终服务器。
2. RESTful API 请求详解
2.1 HTTP 方法(动词)
RESTful API 使用 HTTP 方法来定义对资源的操作意图:
- GET:获取资源(安全且幂等)。
- POST:创建新资源。
- PUT:更新整个资源(幂等)。
- PATCH:部分更新资源。
- DELETE:删除资源(幂等)。
- HEAD:获取资源的元信息。
- OPTIONS:获取资源支持的通信选项。
2.2 请求头(Headers)
请求头携带了关于请求的元数据,常见的有:
- Content-Type:请求体的媒体类型,如
application/json、application/xml。 - Accept:客户端期望的响应媒体类型。
- Authorization:身份验证凭证,如 Bearer Token。
- User-Agent:客户端软件信息。
2.3 请求体(Body)
对于 POST、PUT、PATCH 请求,通常需要携带请求体来传递数据。JSON 是目前最常用的格式。
// 创建用户的请求体示例
{
"username": "john_doe",
"email": "john@example.com",
"age": 30,
"active": true
}
2.4 查询参数(Query Parameters)与路径参数(Path Parameters)
路径参数用于标识特定资源,通常作为 URI 的一部分:
GET /api/users/123
GET /api/posts/456/comments
查询参数用于过滤、排序、分页等:
GET /api/users?role=admin&active=true
GET /api/products?category=electronics&sort=price&page=2&limit=20
3. RESTful API 响应详解
3.1 HTTP 状态码(Status Codes)
状态码表示请求的处理结果:
- 2xx 成功
- 200 OK:请求成功。
- 201 Created:资源创建成功。
- 204 No Content:请求成功,但无返回内容。
- 3xx 重定向
- 301 Moved Permanently:资源永久移动。
- 302 Found:资源临时移动。
- 4xx 客户端错误
- 400 Bad Request:请求语法错误。
- 401 Unauthorized:未认证。
- 403 Forbidden:无权限。
- 404 Not Found:资源不存在。
- 422 Unprocessable Entity:请求格式正确但语义错误。
- 5xx 服务器错误
- 500 Internal Server Error:服务器内部错误。
- 502 Bad Gateway:网关错误。
- 503 Service Unavailable:服务不可用。
3.2 响应头(Response Headers)
响应头携带了关于响应的元数据,常见的有:
- Content-Type:响应体的媒体类型。
- Content-Length:响应体的大小。
- Cache-Control:缓存控制指令。
- Location(常用于 201 Created):新创建资源的 URI。
3.3 响应体(Response Body)
响应体包含了请求的结果数据。成功的响应通常遵循一致的格式。
// 成功响应示例(包含数据)
{
"status": "success",
"data": {
"id": 123,
"username": "john_doe",
"email": "john@example.com"
},
"message": "User retrieved successfully"
}
// 错误响应示例
{
"status": "error",
"code": 400,
"message": "Invalid email format",
"details": {
"field": "email",
"reason": "Must be a valid email address"
}
}
4. 实战代码示例
4.1 使用 Python Flask 创建 RESTful API
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
app = Flask(name)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
db = SQLAlchemy(app)
数据模型
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
def to_dict(self):
return {
'id': self.id,
'username': self.username,
'email': self.email
}
创建数据库表
with app.app_context():
db.create_all()
获取所有用户 (GET /api/users)
@app.route('/api/users', methods=['GET'])
def get_users():
users = User.query.all()
return jsonify({
'status': 'success',
'data': [user.to_dict() for user in users],
'count': len(users)
}), 200
获取单个用户 (GET /api/users/<id>)
@app.route('/api/users/<int:user_id>', methods=['GET'])
def get_user(user_id):
user = User.query.get(user_id)
if not user:
return jsonify({
'status': 'error',
'code': 404,
'message': f'User with id {user_id} not found'
}), 404
return jsonify({
'status': 'success',
'data': user.to_dict()
}), 200
创建用户 (POST /api/users)
@app.route('/api/users', methods=['POST'])
def create_user():
data = request.get_json()
# 验证必要字段
if not data or 'username' not in data or 'email' not in data:
return jsonify({
'status': 'error',
'code': 400,
'message': 'Username and email are required'
}), 400
检查用户是否已存在
if User.query.filter_by(username=data['username']).first():
return jsonify({
'status': 'error',
'code': 409,
'message': f'Username {data["username"]} already exists'
}), 409
创建新用户
new_user = User(username=data['username'], email=data['email'])
db.session.add(new_user)
db.session.commit()
return jsonify({
'status': 'success',
'data': new_user.to_dict(),
'message': 'User created successfully'
}), 201
更新用户 (PUT /api/users/<id>)
@app.route('/api/users/<int:user_id>', methods=['PUT'])
def update_user(user_id):
user = User.query.get(user_id)
if not user:
return jsonify({
'status': 'error',
'code': 404,
'message': f'User with id {user_id} not found'
}), 404
data = request.get_json()
if 'username' in data:
user.username = data['username']
if 'email' in data:
user.email = data['email']
db.session.commit()
return jsonify({
'status': 'success',
'data': user.to_dict(),
'message': 'User updated successfully'
}), 200
删除用户 (DELETE /api/users/<id>)
@app.route('/api/users/<int:user_id>', methods=['DELETE'])
def delete_user(user_id):
user = User.query.get(user_id)
if not user:
return jsonify({
'status': 'error',
'code': 404,
'message': f'User with id {user_id} not found'
}), 404
db.session.delete(user)
db.session.commit()
return jsonify({
'status': 'success',
'message': f'User with id {user_id} deleted successfully'
}), 204
if name == 'main':
app.run(debug=True)
4.2 使用 JavaScript (Fetch API) 调用 RESTful API
// 基础配置
const API_BASE_URL = 'http://localhost:5000/api';
// 获取所有用户
async function fetchUsers() {
try {
const response = await fetch(${API_BASE_URL}/users);
if (!response.ok) {
throw new Error(HTTP error! status: ${response.status});
}
const result = await response.json();
console.log('Users:', result.data);
return result.data;
} catch (error) {
console.error('Error fetching users:', error);
throw error;
}
}
// 获取单个用户
async function fetchUser(userId) {
try {
const response = await fetch(${API_BASE_URL}/users/${userId});
if (!response.ok) {
if (response.status === 404) {
console.log(User ${userId} not found);
return null;
}
throw new Error(HTTP error! status: ${response.status});
}
const result = await response.json();
console.log('User:', result.data);
return result.data;
} catch (error) {
console.error(Error fetching user ${userId}:, error);
throw error;
}
}
// 创建用户
async function createUser(userData) {
try {
const response = await fetch(${API_BASE_URL}/users, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData)
});
const result = await response.json();
if (!response.ok) {
throw new Error(result.message || 'Failed to create user');
}
console.log('User created:', result.data);
return result.data;
} catch (error) {
console.error('Error creating user:', error);
throw error;
}
}
// 更新用户
async function updateUser(userId, updateData) {
try {
const response = await fetch(${API_BASE_URL}/users/${userId}, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(updateData)
});
const result = await response.json();
if (!response.ok) {
throw new Error(result.message || 'Failed to update user');
}
console.log('User updated:', result.data);
return result.data;
} catch (error) {
console.error(Error updating user ${userId}:, error);
throw error;
}
}
// 删除用户
async function deleteUser(userId) {
try {
const response = await fetch(${API_BASE_URL}/users/${userId}, {
method: 'DELETE'
});
if (!response.ok && response.status !== 204) {
const result = await response.json();
throw new Error(result.message || 'Failed to delete user');
}
console.log(User ${userId} deleted successfully);
return true;
} catch (error) {
console.error(Error deleting user ${userId}:, error);
throw error;
}
}
// 使用示例
async function exampleUsage() {
// 1. 获取所有用户
const users = await fetchUsers();
// 2. 创建新用户
const newUser = await createUser({
username: 'alice_smith',
email: 'alice@example.com'
});
// 3. 获取刚创建的用户
const user = await fetchUser(newUser.id);
// 4. 更新用户
await updateUser(newUser.id, {
email: 'alice.new@example.com'
});
// 5. 删除用户
await deleteUser(newUser.id);
}
// 运行示例
exampleUsage().catch(console.error);
4.3 使用 Java Spring Boot 创建 RESTful API
// User.java - 实体类
package com.example.restapi.model;
import jakarta.persistence.*;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String username;
@Column(unique = true, nullable = false)
private String email;
// 构造方法、Getter 和 Setter
public User() {}
public User(String username, String email) {
this.username = username;
this.email = email;
}
// Getters and Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
// ApiResponse.java - 统一响应格式
package com.example.restapi.dto;
public class ApiResponse<T> {
private String status;
private T data;
private String message;
public ApiResponse(String status, T data, String message) {
this.status = status;
this.data = data;
this.message = message;
}
// 成功响应工厂方法
public static <T> ApiResponse<T> success(T data) {
return new ApiResponse<>("success", data, null);
}
public static <T> ApiResponse<T> success(T data, String message) {
return new ApiResponse<>("success", data, message);
}
// 错误响应工厂方法
public static ApiResponse<?> error(String message) {
return new ApiResponse<>("error", null, message);
}
// Getters and Setters
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public T getData() { return data; }
public void setData(T data) { this.data = data; }
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; }
}
// UserController.java - 控制器
package com.example.restapi.controller;
import com.example.restapi.model.User;
import com.example.restapi.dto.ApiResponse;
import com.example.restapi.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
// GET /api/users - 获取所有用户
@GetMapping
public ResponseEntity<ApiResponse<List<User>>> getAllUsers() {
List<User> users = userService.getAllUsers();
return ResponseEntity.ok(ApiResponse.success(users, "Users retrieved successfully"));
}
// GET /api/users/{id} - 获取单个用户
@GetMapping("/{id}")
public ResponseEntity<

1067

被折叠的 条评论
为什么被折叠?



