用 Flask 来写个轻博客 (33) — 使用 Flask-RESTful 来构建 RESTful API 之二

简介: 目录目录前文列表扩展阅读构建 RESTful Flask API定义资源路由格式化输出前文列表用 Flask 来写个轻博客 (1) — 创建项目 用 Flask 来写个轻博客 (2) — Hello World! 用 Flask ...

目录

前文列表

用 Flask 来写个轻博客 (1) — 创建项目
用 Flask 来写个轻博客 (2) — Hello World!
用 Flask 来写个轻博客 (3) — (M)VC_连接 MySQL 和 SQLAlchemy
用 Flask 来写个轻博客 (4) — (M)VC_创建数据模型和表
用 Flask 来写个轻博客 (5) — (M)VC_SQLAlchemy 的 CRUD 详解
用 Flask 来写个轻博客 (6) — (M)VC_models 的关系(one to many)
用 Flask 来写个轻博客 (7) — (M)VC_models 的关系(many to many)
用 Flask 来写个轻博客 (8) — (M)VC_Alembic 管理数据库结构的升级和降级
用 Flask 来写个轻博客 (9) — M(V)C_Jinja 语法基础快速概览
用 Flask 来写个轻博客 (10) — M(V)C_Jinja 常用过滤器与 Flask 特殊变量及方法
用 Flask 来写个轻博客 (11) — M(V)C_创建视图函数
用 Flask 来写个轻博客 (12) — M(V)C_编写和继承 Jinja 模板
用 Flask 来写个轻博客 (13) — M(V)C_WTForms 服务端表单检验
用 Flask 来写个轻博客 (14) — M(V)C_实现项目首页的模板
用 Flask 来写个轻博客 (15) — M(V)C_实现博文页面评论表单
用 Flask 来写个轻博客 (16) — MV(C)_Flask Blueprint 蓝图
用 Flask 来写个轻博客 (17) — MV(C)_应用蓝图来重构项目
用 Flask 来写个轻博客 (18) — 使用工厂模式来生成应用对象
用 Flask 来写个轻博客 (19) — 以 Bcrypt 密文存储账户信息与实现用户登陆表单
用 Flask 来写个轻博客 (20) — 实现注册表单与应用 reCAPTCHA 来实现验证码
用 Flask 来写个轻博客 (21) — 结合 reCAPTCHA 验证码实现用户注册与登录
用 Flask 来写个轻博客 (22) — 实现博客文章的添加和编辑页面
用 Flask 来写个轻博客 (23) — 应用 OAuth 来实现 Facebook 第三方登录
用 Flask 来写个轻博客 (24) — 使用 Flask-Login 来保护应用安全
用 Flask 来写个轻博客 (25) — 使用 Flask-Principal 实现角色权限功能
用 Flask 来写个轻博客 (26) — 使用 Flask-Celery-Helper 实现异步任务
用 Flask 来写个轻博客 (27) — 使用 Flask-Cache 实现网页缓存加速
用 Flask 来写个轻博客 (29) — 使用 Flask-Admin 实现后台管理 SQLAlchemy
用 Flask 来写个轻博客 (30) — 使用 Flask-Admin 增强文章管理功能
用 Flask 来写个轻博客 (31) — 使用 Flask-Admin 实现 FileSystem 管理
用 Flask 来写个轻博客 (32) — 使用 Flask-RESTful 来构建 RESTful API 之一

扩展阅读

使用 Flask 设计 RESTful APIs

快速入门 — Flask-RESTful 0.3.1 documentation

Python爬虫常用之HtmlParser

构建 RESTful Flask API

为什么要构建 RESTful API ?
对于一个 blog application 而言, 其实完全可以不用到 restful api 也能满足日常所需. 加入 restful api 的唯一目标就是加强该项目的可扩展性, 为后期所要实现的诸如: 博客迁移/数据备份/功能扩展 提供统一且可靠的接口.

定义资源路由

首先我们要有一个大概的需求, 如果希望通过 HTTP 请求来完成对服务端资源的操作, 我们需要解决那些问题?
1. 首先要定位到该资源
2. 告诉服务端我要对该资源做那种操作
3. 前提还可能需要满足身份鉴权(这个需求, 我们后期再实现)

  • 安装 Flask-RESTful
pip install Flask-Restful
pip freeze > requirements.txt
AI 代码解读
  • 初始化 restful_api 对象
    vim jmilkfansblog/extensions.py
from flask.ext.restful import Api
...

#### Create the Flask-Restful's instance
restful_api = Api()
AI 代码解读
  • 实现 PostApi 资源类
    我们将 posts 博客文章定义为一类资源, 只有定义了资源并且对外公开后, 才能被外部所调用.
    vim jmilkfansblog/controllers/flask_restful/posts.py
from flask.ext.restful import Resource

class PostApi(Resource):
    """Restful API of posts resource."""

    def get(self, post_id=None):
        """Can be execute when receive HTTP Method `GET`.
           Will be return the Dict object as post_fields.
        """
        return {'hello': 'world'}
AI 代码解读

NOTE 1: jmilkfansblog/controllers/flask_restful 会作为一个包, 所以要记得创建 __init__.py 文件, 否则无法作为导入路径.

NOTE 2: 每个 REST 资源类都需要继承 flask_restful 的 Resource 类. 其所有的子类都可以通过定义同名实例函数来将该函数绑定到 HTTP Methods 中. EG. GET <==> get(), 放接受定位到资源的 HTTP GET 方法时, 就会执行该资源类的实例函数 get() .

  • 将 restful_api 对象注册到 app 对象中
    vim jmilkfansblog/__init__.py
from jmilkfansblog.extensions import restful_api
from jmilkfansblog.controllers.flask_restful.posts import PostApi
...

def create_app(object_name):
    ...
    #### Init the Flask-Restful via app object
    # Define the route of restful_api
    restful_api.add_resource(
        PostApi,
        '/api/posts')
    restful_api.init_app(app)
AI 代码解读

NOTE 1: 在 restful_api.add_resource() 指定了资源类 PostApi 所对应的资源名称为 posts, 访问路由为 /api/posts, 这样才完成了对一个资源的完整定义.

NOTE 2: 同时再结合 PostApi 中的 get() 会自动的适配到 HTTP GET 方法, 这样就解决了我们之前所提出的 2 个问题.

现在我们引入一个新的问题, 通过上述定义的 get() 方法我们基本可以获取到数据库 posts 表中的所有记录(当然现在还没有连接数据库操作), 那么如果我只需要获取其中的某一条指定的记录呢?
这里需要在请求中指定 id 来完成单一的定位, 或者也可以传递一个 filters 来过滤若干条满足要求的数据记录.

  • 为资源 posts 添加多条路由
    vim jmilkfansblog/__init__.py
def create_app(object_name):
    ...
    #### Init the Flask-Restful via app object
    # Define the route of restful_api
    restful_api.add_resource(
        PostApi,
        '/api/posts',
        '/api/posts/<string:post_id>',
        endpoint='restful_api_post')
AI 代码解读

NOTE: add_resource() 允许为同一个资源类绑定多条路由, '/api/posts/<string:post_id>' 表示可以访问 posts 这一类资源中某一个 post_id 一致的资源对象.

  • 为 get() 方法添加 post_id 形参数
    vim jmilkfansblog/controllers/flask_restful/posts.py
class PostApi(Resource):
    """Restful API of posts resource."""

    def get(self, post_id=None):
        """Can be execute when receive HTTP Method `GET`.
           Will be return the Dict object as post_fields.
        """

        if post_id:
            return {'post_id': post_id}
        return {'hello': 'world'}
AI 代码解读

格式化输出

在上一篇博文中提到, REST 约束要求我们使用一致的数据包装形式来进行响应, 所以我们需要实现一致的格式化功能. 本项目使用最常见的 JSON 格式.

  • Flask-Restful 的格式化输出, 首先需要定义出一个类似模板的 Dict 类型对象
    其 keys 是资源对应的 Model 对象所拥有且需要输出的字段名, values 则声明了该字段的值以何种类型转换并输出. 然后把该字典模板传给装饰器 @marshal_with 并装饰到所有资源类中需要返回数据到客户端的实例方法中. 如此之后,实例方法在返回数据之前都会按照该模板将数据进行格式化转换.
    注意: 字典模板的 keys 最好与 models 模块中定义的字段名相同, 否则无法自动完成字典模板与 Model 对象的匹配.
    vim jmilkfansblog/controllers/flask_restful/posts.py
from flask.ext.restful import Resource, fields, marshal_with
from jmilkfansblog.controllers.flask_restful import fields as jf_fields

...

# String format output of tag
nested_tag_fields = {
    'id': fields.String(),
    'name': fields.String()}

# String format output of post
post_fields = {
    'author': fields.String(attribute=lambda x: x.user.username),
    'title': fields.String(),
    'text': jf_fields.HTMLField(),
    'tags': fields.List(fields.Nested(nested_tag_fields)),
    'publish_date': fields.DateTime(dt_format='iso8601')}

class PostApi(Resource):
    """Restful API of posts resource."""

    @marshal_with(post_fields)
    def get(self, post_id=None):
        """Can be execute when receive HTTP Method `GET`.
           Will be return the Dict object as post_fields.
        """

        if post_id:
            return {'post_id': post_id}
        return {'hello': 'world'}
AI 代码解读

NOTE 1: 这里需要使用到 flask_restful.fields, 其提供了绝大多数常用的格式类型定义, 具体格式类型列表可以查看官方文档. 当然, 我们也可以自定义一些格式类型, 例如 jf_fields.HTMLField()

NOTE 2: tags 和 author 字段并不存在与 posts 表中, 返回该字段是为了遵守 REST 的约束之一, RESTful API 返回的数据应该尽量满足客户端的需求. 所以我们一般会将表与表之前含有关联关系的字段都一同返回. 格式类型 List 可以接受另外一个格式化输出字典模板对象. 类似于 字典内嵌套字典的格式.

  • 自定义 fields 类型
    因为 posts 表中的 text 字段内容是一系列的 HTML 字符串(由 CKEditor 产生), 这些 HTML 字符串是不允许被 RESTful API 返回的, 因为要满足 REST 的约束之一, 服务端不参与用户界面表现层的业务逻辑(即 HTML 代码), 所以我们需要将该字段值中的 HTML 标签过滤掉.
    vim jmilkfansblog/controllers/flask_restful/fields.py
from HTMLParser import HTMLParser
from flask.ext.restful import fields


class HTMLField(fields.Raw):
    """Define a new fields for filter the HTML tags string."""

    def format(self, value):
        return strip_tags(str(value))


class HTMLStripper(HTMLParser):
    """HTML Parser of Stripper."""

    def __init__(self):
        self.reset()
        self.fed = []

    def handle_data(self, data_object):
        self.fed.append(data_object)

    def get_data(self):
        return ''.join(self.fed)


def strip_tags(html):
    """Filter the tags string of HTML for data object of Restful api."""

    stripper = HTMLStripper()
    stripper.feed(html)

    return stripper.get_data()
AI 代码解读

NOTE 1: 在 fields 模块中通过继承了 flask_restful.fields.Raw 类, 实现了新的格式类型 HTMLField .

NOTE 2: 使用 HTTPParser 来实现 HTML 解析, 重载 handle_data 方法用于将 HTML 标签之间的文本内容合并.

目录
打赏
0
0
0
0
37
分享
相关文章
构建智能天气助手:基于大模型API与工具函数的调用实践
在人工智能快速发展的今天,大语言模型(LLM)已经成为构建智能应用的重要基础设施。本文将介绍如何利用大模型API和工具函数集成,构建一个能够理解自然语言并提供精准天气信息的智能助手。
79 11
构建智能 API 开发环境:在 Cursor 中连接 Apifox MCP Server
本文介绍了如何将Apifox MCP Server与Cursor结合,通过AI直接获取和理解API文档,大幅提升开发效率。首先需配置Apifox的Access Token和项目ID,并在Cursor中设置MCP连接。实际应用场景包括快速生成模型代码、同步更新接口文档与代码、生成CRUD操作、搜索API文档及自动生成测试用例。此外,还提供了管理多项目、安全性实践和优化AI响应质量的技巧。这种组合可显著减少从API规范到代码实现的时间,降低错误率并加速迭代过程,为开发者带来更高效的体验。
Understanding RESTful API and Web Services: Key Differences and Use Cases
在现代软件开发中,RESTful API和Web服务均用于实现系统间通信,但各有特点。RESTful API遵循REST原则,主要使用HTTP/HTTPS协议,数据格式多为JSON或XML,适用于无状态通信;而Web服务包括SOAP和REST,常用于基于网络的API,采用标准化方法如WSDL或OpenAPI。理解两者区别有助于选择适合应用需求的解决方案,构建高效、可扩展的应用程序。
Python 高级编程与实战:构建 RESTful API
本文深入探讨了使用 Python 构建 RESTful API 的方法,涵盖 Flask、Django REST Framework 和 FastAPI 三个主流框架。通过实战项目示例,详细讲解了如何处理 GET、POST 请求,并返回相应数据。学习这些技术将帮助你掌握构建高效、可靠的 Web API。
解锁 DeepSeek API 接口:构建智能应用的技术密钥
在数字化时代,智能应用蓬勃发展,DeepSeek API 作为关键技术之一,提供了强大的自然语言处理能力。本文详细介绍 DeepSeek API,并通过 Python 请求示例帮助开发者快速上手。DeepSeek API 支持文本生成、问答系统、情感分析和文本分类等功能,具备高度灵活性和可扩展性,适用于多种场景。示例展示了如何使用 Python 调用 API 生成关于“人工智能在医疗领域的应用”的短文。供稿者:Taobaoapi2014。
自学记录HarmonyOS Next DRM API 13:构建安全的数字内容保护系统
在完成HarmonyOS Camera API开发后,我深入研究了数字版权管理(DRM)技术。最新DRM API 13提供了强大的工具,用于保护数字内容的安全传输和使用。通过学习该API的核心功能,如获取许可证、解密内容和管理权限,我实现了一个简单的数字视频保护系统。该系统包括初始化DRM模块、获取许可证、解密视频并播放。此外,我还配置了开发环境并实现了界面布局。未来,随着数字版权保护需求的增加,DRM技术将更加重要。如果你对这一领域感兴趣,欢迎一起探索和进步。
124 18
深入浅出Node.js:从零开始构建RESTful API
在数字化时代的浪潮中,后端开发作为连接用户与数据的桥梁,扮演着至关重要的角色。本文将引导您步入Node.js的奇妙世界,通过实践操作,掌握如何使用这一强大的JavaScript运行时环境构建高效、可扩展的RESTful API。我们将一同探索Express框架的使用,学习如何设计API端点,处理数据请求,并实现身份验证机制,最终部署我们的成果到云服务器上。无论您是初学者还是有一定基础的开发者,这篇文章都将为您打开一扇通往后端开发深层知识的大门。
95 12
1688API最新指南:商品详情接口接入与应用
本指南介绍1688商品详情接口的接入与应用,该接口可获取商品标题、价格、规格、库存等详细信息,适用于电商平台开发、数据分析等场景。接口通过商品唯一标识查询,支持HTTP GET/POST请求,返回JSON格式数据,助力开发者高效利用1688海量商品资源。
京东API接口最新指南:店铺所有商品接口的接入与使用
本文介绍京东店铺商品数据接口的应用与功能。通过该接口,商家可自动化获取店铺内所有商品的详细信息,包括基本信息、销售数据及库存状态等,为营销策略制定提供数据支持。此接口采用HTTP请求(GET/POST),需携带店铺ID和授权令牌等参数,返回JSON格式数据,便于解析处理。这对于电商运营、数据分析及竞品研究具有重要价值。

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等