RESTful 简介
1.1 为什么要使用 RESTful 架构?
Representational State Transfer(REST)是一种面向资源的架构风格,广泛应用于网络服务的设计和开发。使用RESTful架构有以下几个优点:
-
简单性和可扩展性: RESTful 架构基于简单的原则和标准,易于理解和实现。它的设计使得系统更具有可扩展性,便于适应不断变化的需求。
-
松耦合: RESTful 架构支持松耦合,客户端和服务器之间的交互是无状态的,每个请求都包含足够的信息使其独立完成。这促使系统组件之间的独立性,使得修改一个组件不会影响其他组件。
-
可见性: RESTful 架构通过使用统一的接口,使得资源的状态和操作对客户端可见。这提高了系统的可维护性和可理解性。
1.2 RESTful API 请求设计
设计 RESTful API 请求时应考虑以下几个方面:
-
资源标识: 每个资源都应有唯一的标识,通常通过 URI(Uniform Resource Identifier)表示。URI应该清晰地指示资源的位置和唯一性。
-
HTTP 方法: 使用 HTTP 方法(GET、POST、PUT、DELETE 等)来表示对资源的不同操作。例如,GET用于获取资源,POST用于创建资源,PUT用于更新资源,DELETE用于删除资源。
-
请求参数: 可以通过 URI 查询参数、请求头或请求体传递参数。参数的设计应符合标准,易于理解和使用。
1.3 RESTful API 响应设计
设计 RESTful API 响应时需要考虑以下几个方面:
-
状态码: 使用合适的 HTTP 状态码来表示请求的结果,如200 OK表示成功,404 Not Found表示资源未找到,等等。
-
响应体: 响应体应包含所请求资源的表示形式,通常使用 JSON 或 XML 格式。这使得数据在客户端和服务器之间的传输更加灵活和可扩展。
-
超媒体: 使用超媒体作为应用程序状态的引擎,使得客户端可以通过解析响应中的超媒体链接来发现和使用相关资源。
通过合理设计 RESTful API 请求和响应,可以构建出清晰、可维护、可扩展的系统,实现客户端和服务器之间的有效通信。
Flask例子
init.py
python
from flask import Flask
from .extensions import api, db
from .resources import ns
def create_app():
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///db.sqlite3"
api.init_app(app)
db.init_app(app)
api.add_namespace(ns)
return app
api_models.py
python
# 导入 Flask-Restx 框架的 fields 模块
from flask_restx import fields
# 从自定义的 extensions 模块中导入 api 对象
from .extensions import api
# 定义一个名为 "Student" 的模型,包含 id(整数)、name(字符串)和一个嵌套的 course_model 字段
student_model = api.model("Student", {
"id": fields.Integer, # 学生 ID,类型为整数
"name": fields.String, # 学生名称,类型为字符串
#"course": fields.Nested(course_model) # 嵌套的课程模型字段,该行代码被注释掉了
})
# 定义一个名为 "Course" 的模型,包含 id(整数)、name(字符串)和一个嵌套的 students 字段,是一个学生列表
course_model = api.model("Course", {
"id": fields.Integer, # 课程 ID,类型为整数
"name": fields.String, # 课程名称,类型为字符串
"students": fields.List(fields.Nested(student_model)) # 嵌套的学生列表字段
})
# 定义一个名为 "CourseInput" 的模型,用于接收创建课程时的输入数据
course_input_model = api.model("CourseInput", {
"name": fields.String, # 课程名称,类型为字符串
})
# 定义一个名为 "StudentInput" 的模型,用于接收创建学生时的输入数据
student_input_model = api.model("StudentInput", {
"name": fields.String, # 学生名称,类型为字符串
"course_id": fields.Integer # 所属课程的 ID,类型为整数
})
python
from flask_sqlalchemy import SQLAlchemy
from flask_restx import Api
api = Api()
db = SQLAlchemy()
python
from .extensions import db
class Course(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), unique=True)
students = db.relationship("Student", back_populates="course")
class Student(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), unique=True)
course_id = db.Column(db.ForeignKey("course.id"))
course = db.relationship("Course", back_populates="students")
python
# 导入 Flask-Restx 框架的 Resource 类和 Namespace 类
from flask_restx import Resource, Namespace
# 导入自定义的 API 模型和数据库模型
from .api_models import course_model, student_model, course_input_model, student_input_model
from .extensions import db
from .models import Course, Student
# 创建一个命名空间对象,用于组织和管理 API 路由
ns = Namespace("api")
# 创建一个处理 "/hello" 路由的 Resource 类
@ns.route("/hello")
class Hello(Resource):
def get(self):
return {"hello": "restx"}
# 创建处理 "/courses" 路由的 Resource 类
@ns.route("/courses")
class CourseListAPI(Resource):
# 使用 course_model 进行响应数据的序列化
@ns.marshal_list_with(course_model)
def get(self):
# 返回所有课程的查询结果
return Course.query.all()
# 使用 course_input_model 进行请求数据的验证
# 使用 course_model 进行响应数据的序列化
@ns.expect(course_input_model)
@ns.marshal_with(course_model)
def post(self):
# 从请求中获取课程名称,并创建新的课程对象
course = Course(name=ns.payload["name"])
# 将新课程对象添加到数据库中
db.session.add(course)
# 提交数据库事务
db.session.commit()
# 返回创建的课程对象和状态码 201(表示资源创建成功)
return course, 201
# 创建处理 "/courses/<int:id>" 路由的 Resource 类
@ns.route("/courses/<int:id>")
class CourseAPI(Resource):
# 使用 course_model 进行响应数据的序列化
def get(self, id):
# 根据课程 ID 查询并返回相应的课程对象
course = Course.query.get(id)
return course
# 使用 course_input_model 进行请求数据的验证
# 使用 course_model 进行响应数据的序列化
def put(self, id):
# 根据课程 ID 查询相应的课程对象
course = Course.query.get(id)
# 更新课程对象的名称
course.name = ns.payload["name"]
# 提交数据库事务
db.session.commit()
# 返回更新后的课程对象
return course
# 删除指定 ID 的课程对象
def delete(self, id):
course = Course.query.get(id)
db.session.delete(course)
db.session.commit()
# 返回空响应体和状态码 204(表示资源删除成功)
return {}, 204
# 创建处理 "/students" 路由的 Resource 类
@ns.route("/students")
class StudentListAPI(Resource):
# 使用 student_model 进行响应数据的序列化
def get(self):
# 返回所有学生的查询结果
return Student.query.all()
# 使用 student_input_model 进行请求数据的验证
# 使用 student_model 进行响应数据的序列化
def post(self):
# 从请求中获取学生名称和所属课程 ID,并创建新的学生对象
student = Student(name=ns.payload["name"], course_id=ns.payload["course_id"])
# 将新学生对象添加到数据库中
db.session.add(student)
# 提交数据库事务
db.session.commit()
# 返回创建的学生对象和状态码 201(表示资源创建成功)
return student, 201
# 创建处理 "/students/<int:id>" 路由的 Resource 类
@ns.route("/students/<int:id>")
class StudentAPI(Resource):
# 使用 student_model 进行响应数据的序列化
def get(self, id):
# 根据学生 ID 查询并返回相应的学生对象
student = Student.query.get(id)
return student
# 使用 student_input_model 进行请求数据的验证
# 使用 student_model 进行响应数据的序列化
def put(self, id):
# 根据学生 ID 查询相应的学生对象
student = Student.query.get(id)
# 更新学生对象的名称和所属课程 ID
student.name = ns.payload["name"]
student.course_id = ns.payload["course_id"]
# 提交数据库事务
db.session.commit()
# 返回更新后的学生对象
return student
# 删除指定 ID 的学生对象
def delete(self, id):
student = Student.query.get(id)
db.session.delete(student)
db.session.commit()
# 返回空响应体和状态码 204(表示资源删除成功)
return {}, 204