欢迎访问我的网站,希望内容对您有用,感兴趣的可以加入我们的社群。

Flask教程(十六)RESTful-API

Flask Web 迷途小书童 4年前 (2020-08-26) 9031次浏览 2个评论

软硬件环境

  • windows 10 64bit
  • anaconda3 with python 3.7
  • pycharm 2020.1.2
  • flask 1.1.2
  • flask-restful 0.3.8

视频看这里

此处是 youtube 的播放链接,需要科学上网。喜欢我的视频,请记得订阅我的频道,打开旁边的小铃铛,点赞并分享,感谢您的支持。

简介

前面我们讲到 flask 路由的时候,可以通过 app.route 来指定 HTTP 的请求方法(GETPOSTPUTDELETE 等),并在请求函数中根据不同的请求方法,执行不同的业务逻辑。这样就已经实现一个简单的 Restful 请求了。但是在 flask 中有更好的方法来实现,那就是 flask-restful 扩展了。

RESTful 架构风格规定,数据的元操作,即CRUD(即数据的增删查改)操作,分别对应于 HTTP 方法,GET 用来获取资源,POST 用来新建资源(也可以用于更新资源),PUT 用来更新资源,DELETE 用来删除资源,这样就统一了数据操作的接口,仅仅通过 HTTP 方法,就可以完成对数据的增删查改工作。

安装flask-restful

常规操作,通过 pip 安装

pip install flask-restful

flask-restful基本使用

插件安装好后,就可以导入模块了,看下面的示例

from flask import Flask, jsonify
from flask_restful import Api, Resource, reqparse

USERS = [
    {"name": "zhangsan"},
    {"name": "lisi"},
    {"name": "wangwu"},
    {"name": "zhaoliu"}
]

class Users(Resource):
    def get(self):
        return jsonify(USERS)

    def post(self):
        args = reqparse.RequestParser() \
            .add_argument('name', type=str, location='json', required=True, help="名字不能为空") \
            .parse_args()

        if args['name'] not in USERS:
            USERS.append({"name": args['name']})

        return jsonify(USERS)

    def delete(self):
        USERS = []
        return jsonify(USERS)

app = Flask(__name__)
api = Api(app, default_mediatype="application/json")

api.add_resource(Users, '/users')

app.run(host='0.0.0.0', port=5001, use_reloader=True)

flask-restful 扩展通过 api.add_resource() 方法来添加路由,方法的第一个参数是一个类名,该类继承 Resource 基类,其成员方法定义了不同的 HTTP 请求方法的逻辑;第二个参数定义了 URL 路径。在 Users 类中,我们分别实现了 getpostdelete 方法,分别对应 HTTPGETPOSTDELETE 请求。

另外,flask-restful 还提供了 argparse,它可以方便地实现对 http 请求中客户端发送过来的数据进行校验处理,这有点像表单中的验证方法,在实际项目中非常实用。

程序启动以后,我们访问 http://127.0.0.1:5001/usersGET 请求时会给出 USERS 的内容、POST 请求时会在 USERS 中添加一项(如果不存在)并返回 USERS 更新后的内容。DELETE 请求则清空 USERS 并返回空。

客户端部分,我们使用 postman 来模拟请求

flask-restful-get

flask-restful-post

flask-restful-delete

GET方法中如何获取参数

针对每个用户名,我们写个类,同样继承自 Resource,在 get 方法中,接收参数 userid,简单起见,userid 定义为该用户名在 USERS 列表中的索引

class UserId(Resource):
    def get(self, userid):
        return jsonify(
            {"name": USERS[int(userid)].get("name")}
        )

api.add_resource(UserId, '/user/<userid>')

api.add_resource() 方法中,第二个参数 /user/<userid> 中的 <userid>,就是用户传递过来的参数,这点写法上跟 flask 路由的写法是一模一样的。程序启动后,访问 http://127.0.0.1:5001/user/0 获取的就是 USERS 列表中第一个用户的信息

flask-restful-get-param

在flask-restful中添加日志

Flask教程(十五)日志 已经提过如何在 flask 中使用日志功能。在 flask-restful 中,logger 的使用有更优雅的方式,来看示例

import logging.config
from flask import Flask, jsonify
from flask_restful import Api, Resource, reqparse

logging.config.dictConfig(
    {
        "version": 1,
        "disable_existing_loggers": False,
        "formatters": {
            "simple": {"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"}
        },
        "handlers": {
            "console": {
                "class": "logging.StreamHandler",
                "level": "DEBUG",
                "formatter": "simple",
                "stream": "ext://sys.stdout",
            },
            "info_file_handler": {
                "class": "logging.handlers.RotatingFileHandler",
                "level": "INFO",
                "formatter": "simple",
                "filename": "info.log",
                "maxBytes": 10485760,
                "backupCount": 50,
                "encoding": "utf8",
            },
            "error_file_handler": {
                "class": "logging.handlers.RotatingFileHandler",
                "level": "ERROR",
                "formatter": "simple",
                "filename": "errors.log",
                "maxBytes": 10485760,
                "backupCount": 20,
                "encoding": "utf8",
            },
            "debug_file_handler": {
                "class": "logging.handlers.RotatingFileHandler",
                "level": "DEBUG",
                "formatter": "simple",
                "filename": "debug.log",
                "maxBytes": 10485760,
                "backupCount": 50,
                "encoding": "utf8",
            },
        },
        "loggers": {
            "my_module": {"level": "ERROR", "handlers": ["console"], "propagate": "no"}
        },
        "root": {
            "level": "DEBUG",
            "handlers": ["error_file_handler", "debug_file_handler"],
        },
    }
)

USERS = [
    {"name": "zhangsan"},
    {"name": "lisi"},
    {"name": "wangwu"},
    {"name": "zhaoliu"}
]

class Users(Resource):
    def __init__(self, **kargs):
        self.logger = kargs.get('logger')

    def get(self):
        return jsonify(USERS)

    def post(self):
        args = reqparse.RequestParser() \
            .add_argument('name', type=str, location='json', required=True, help="名字不能为空") \
            .parse_args()

        self.logger.debug(args)

        if args['name'] not in USERS:
            USERS.append({"name": args['name']})

        return jsonify(USERS)

    def delete(self):
        USERS = []
        return jsonify(USERS)

app = Flask(__name__)
api = Api(app, default_mediatype="application/json")

api.add_resource(Users, '/users', resource_class_kwargs={
    "logger": logging.getLogger('/Users')
})

app.run(host='0.0.0.0', port=5001, use_reloader=True)

我们使用上次用到的 dictConfig,主要的区别在于 api.add_resource() 方法中,使用了参数 resource_class_kwargs,然后在 Resource 子类中的构造函数 __init__,将日志记录器获取到,后面就可以在各个处理方法中使用了。再次使用 postman 发起 POST 请求,可以看到 debug.log 是这个样子的

flask-restful-logging

源码下载

https://github.com/xugaoxiang/FlaskTutorial

Flask系列教程

更多 Flask 教程,请移步

https://xugaoxiang.com/category/python/flask/

参考资料

喜欢 (1)

您必须 登录 才能发表评论!

(2)个小伙伴在吐槽
  1. 这个地方稍微改一下是不是更好? users_list = list(map(lambda x: x.get('name'), USERS)) if args['name'] not in users_list: USERS.append({"name": args['name']})
    匿名2022-07-05 19:21