博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
用 Flask 来写个轻博客 (33) — 使用 Flask-RESTful 来构建 RESTful API 之二
阅读量:5738 次
发布时间:2019-06-18

本文共 5418 字,大约阅读时间需要 18 分钟。

Blog 项目源码:

目录

前文列表

扩展阅读

构建 RESTful Flask API

为什么要构建 RESTful API ?

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

定义资源路由

首先我们要有一个大概的需求, 如果希望通过 HTTP 请求来完成对服务端资源的操作, 我们需要解决那些问题?

1. 首先要定位到该资源
2. 告诉服务端我要对该资源做那种操作
3. 前提还可能需要满足身份鉴权(这个需求, 我们后期再实现)

  • 安装 Flask-RESTful
pip install Flask-Restfulpip freeze > requirements.txt
  • 初始化 restful_api 对象
    vim jmilkfansblog/extensions.py
from flask.ext.restful import Api...#### Create the Flask-Restful's instancerestful_api = Api()
  • 实现 PostApi 资源类
    我们将 posts 博客文章定义为一类资源, 只有定义了资源并且对外公开后, 才能被外部所调用.
    vim jmilkfansblog/controllers/flask_restful/posts.py
from flask.ext.restful import Resourceclass 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'}

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

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/
', endpoint='restful_api_post')

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'}

格式化输出

在上一篇博文中提到, 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_withfrom jmilkfansblog.controllers.flask_restful import fields as jf_fields...# String format output of tagnested_tag_fields = {    'id': fields.String(),    'name': fields.String()}# String format output of postpost_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'}

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 HTMLParserfrom flask.ext.restful import fieldsclass 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()

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

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

转载于:https://www.cnblogs.com/jmilkfan-fanguiju/p/10589845.html

你可能感兴趣的文章
第二十五天,一排房子
查看>>
Runtime.getRuntime().exec(cmd)的超时处理
查看>>
Linux下导入SQL文件
查看>>
jsp中动态添加全选复选框
查看>>
iOS通过rumtime给类别添加动态属性
查看>>
Redis Set
查看>>
121 项目 005 笔记向 spring mvc 首页配置
查看>>
Android开发把项目打包成apk
查看>>
【转】Git详解之九 Git内部原理
查看>>
目前世界最流行的Web开发框架
查看>>
mysql误删除root用户或者忘记root密码时的解决办法
查看>>
圣杯布局(你听说过么?)
查看>>
点击按钮,浏览器返回上一页,离开页面提示
查看>>
Jenkins+Ansible+Gitlab自动化部署三剑客
查看>>
经典的软件开发哲学
查看>>
Session与Cookie
查看>>
hadoop2.6.0集群搭建
查看>>
wordpress 伪静态nginx设置
查看>>
Hive lateral view 和 explode 详解
查看>>
Spring 拦截器 学习
查看>>