RESTful API 架构快速入门 Flask实现

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

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

# 导入 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,类型为整数
})

extensions.py

from flask_sqlalchemy import SQLAlchemy 
from flask_restx import Api

api = Api()
db = SQLAlchemy()

models.py

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")

resources.py

# 导入 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/191311.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

springboot 拦截器中使用@Value注解为null

拦截器中获取配置参数为null 代码如下&#xff1a; 解决方式一&#xff1a; 检查你的WebMvcConfigurer实现类&#xff0c;比如我的是CCBWebMvcConfig 将拦截器以bean的形式注入&#xff1a; 我之前的写法是new 一个放进去的&#xff0c;这种会导致Value为null AutowiredJSCCB…

图像分割模型及架构选型介绍(MMSegmentation|sssegmentation等)

参考&#xff1a; https://zhuanlan.zhihu.com/p/618226513 0. 图像分割概述 图像分割通过给出图像中每个像素点的标签&#xff0c;将图像分割成若干带类别标签的区块&#xff0c;可以看作对每个像素进行分类。图像分割是图像处理的重要组成部分&#xff0c;也是难点之一。随…

二次创作Z01语言

目录 一&#xff0c;字符集 二&#xff0c;编译分词 三&#xff0c;token含义 四&#xff0c;Z01翻译成C 五&#xff0c;执行翻译后的代码 六&#xff0c;打印Hello World! 一&#xff0c;字符集 假设有门语言叫Z01语言&#xff0c;代码中只有0和1这两种字符。 二&#…

使用花生壳外网远程ssh访问内网主机 亲测有效

经常会遇到远程访问其他电脑的需求&#xff0c;一般首选向日葵软件&#xff0c;傻瓜式的连接远程桌面控制&#xff0c;非常方便。但是仅限于远程桌面远程协助这种。 对于程序员来说最佳的登录方式是ssh&#xff0c;同时远程桌面连过来的时候分辨率比较低&#xff0c;图形效果相…

上海交通大学生存手册

强烈推荐所有大学生去阅读《上海交通大学生存手册》。虽然它可能有些冗长&#xff0c;但非常重要&#xff0c;因为它道出了大学教育的本质。 如果几年前我能够看到这本书&#xff0c;也许我的大学生活会有所不同。现在我将向正在上大学或者将要上大学的你推荐这本书。 无论你…

Less的函数的介绍

文章目录 前言描述style.less输出后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;Sass和Less &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不断努力填补技术短板。(如果出现错误&#xff0c;…

python--获取每张切片的不同PEF区间值的百分比

在全直径数字岩心中&#xff0c;如何获取每张切片的不同PEF区间值的百分比&#xff1f; import os import datetime from PIL import Image import numpy as np import csv import easygui as gclass Table(object):def __init__(self, table_data_path):self.table_data_path…

MySQL进阶_10.锁

文章目录 一、概述二、MySQL并发事务访问相同记录2.1、读-读2.2、写-写2.3、读-写2.4、并发问题的解决方案 三、锁的不同角度分类3.1、 读锁、写锁3.1.1、 锁定读 3.2、表级锁、页级锁、行锁3.2.1、表锁3.2.2、意向锁3.2.2.1、意向锁的作用3.2.2.2、意向锁的互斥性 3.2.3、自增…

正则表达式例题-PTA

PTA-7-55 判断指定字符串是否合法-CSDN博客 7-54 StringBuffer-拼接字符串 题目&#xff1a; 输入3个整数n、begin、end。 将从0到n-1的数字拼接为字符串str。如&#xff0c;n12&#xff0c;则拼接出来的字符串为&#xff1a;01234567891011 最后截取字符串str从begin到end(包…

基恩士软件的基本操作(五,日志记录与使用)

目录 基恩士是如何保存日志的&#xff1f; 如何使用日志功能 查看DM10的值1秒加1的记录日志 设定id与储存位置 软元件设定&#xff08; 日志ID有10个&#xff08;0~10&#xff09;&#xff0c;每一个ID最多添加512个软元件&#xff09; 设定触发 执行日志的梯形图程序 触…

电力感知边缘计算技术网关产品设计方案-硬件方案

网关硬件架构设计图: 1.配置方案 配置差异 A类网关 B类网关 CPU

Less 嵌套规则

文章目录 前言描述style.less输出后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;Sass和Less &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不断努力填补技术短板。(如果出现错误&#xff0c;…

P15 C++ 枚举

The ChenPi 前言 今天我们要讲的是 C 中的枚举。 enum 是 enumeration 的缩写&#xff0c;基本上可以说&#xff0c;它就是一个数值集合。如果你想要给枚举一个更实际的定义&#xff0c;它们是给一个值命名的一种方法。 所以我们不用一堆叫做 A、B、C 的整数。我们可以有一个…

【好玩的 Docker 项目】搭建一个完全自由的音乐播放软件 ————Navidrome 随时随地!想听就听!

前言 随着国内版权意识的提高,现在想听一首歌曲,往往我们可能要切换 3-4 个 APP—— 网易云音乐、QQ 音乐、咪咕音乐…… 切换起来很麻烦,有的 APP 就算你买了 VIP 服务,下载的歌曲还是加密的,一旦 VIP 到期后某些歌你还听不了,非常蛋疼。 顺哥博客 最近被朋友推荐入了…

【Amazon】通过直接连接的方式导入 KubeSphere集群至KubeSphere主容器平台

文章目录 一、设置主集群方式一&#xff1a;使用 Web 控制台方式二&#xff1a;使用 Kubectl命令 二、在主集群中设置代理服务地址方式一&#xff1a;使用 Web 控制台方式二&#xff1a;使用 Kubectl命令 三、登录控制台验证四、准备成员集群方式一&#xff1a;使用 Web 控制台…

《已解决: ImportError: Keras requires TensorFlow 2.2 or higher 问题》

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页: &#x1f405;&#x1f43e;猫头虎的博客&#x1f390;《面试题大全专栏》 &#x1f995; 文章图文并茂&#x1f996…

18. Python 数据处理之 Numpy

目录 1. 简介2. 安装和导入Numpy3. ndarray 对象4. 基本运算5. 索引、切片和迭代6. 条件和布尔数组7. 变换形状8. 操作数组 1. 简介 数据分析的流程概括起来主要是&#xff1a;读写、处理计算、分析建模和可视化4个部分。 Numpy 是Python 进行科学计算&#xff0c;数据分析时…

卷积神经网络经典backbone

特征提取是数据分析和机器学习中的基本概念&#xff0c;是将原始数据转换为更适合分析或建模的格式过程中的关键步骤。特征&#xff0c;也称为变量或属性&#xff0c;是我们用来进行预测、对对象进行分类或从数据中获取见解的数据点的特定特征或属性。 1.AlexNet paper&#…

C/C++ 通过SQLiteSDK增删改查

SQLite&#xff0c;作为一款嵌入式关系型数据库管理系统&#xff0c;一直以其轻量级、零配置以及跨平台等特性而备受青睐。不同于传统的数据库系统&#xff0c;SQLite是一个库&#xff0c;直接与应用程序一同编译和链接&#xff0c;无需单独的数据库服务器进程&#xff0c;实现…

[LaTex]arXiv投稿攻略——jpg/png转pdf

一、将图片复制进ppt&#xff0c;右键单击图片选择设置图片格式&#xff0c;获取图片高度和宽度 二、选择“设计-幻灯片大小-自定义幻灯片大小” 三、设置幻灯片大小为图片大小 四、 选择“最大化” 五、 检查幻灯片大小是否与图像大小一致 六、导出为PDF