资讯专栏INFORMATION COLUMN

Flask 扩展系列之 Flask-RESTful

阿罗 / 3003人阅读

摘要:励以最少的安装方式进行最佳实践。上面的例子接收了一个对象并准备将其序列化。装饰器会通过进行转换。从对象中提取的唯一字段是。是一个特殊的字段,它接受端点名称并为响应中的端点生成一个。可以查看项查看完整列表。

大纲

简介

安装

快速入门

一个最小的 api 例子

资源丰富的路由

端点

参数解析

数据格式化

完整 TODO 应用例子

简介

Flask-RESTful是一个Flask的扩展,它增加了对快速构建REST APIs的支持。它是一种轻量级的抽象,可以与现有的ORM/库一起工作。Flask-RESTful励以最少的安装方式进行最佳实践。如果你对Flask很熟悉的,Flask-RESTful会很容易上手。

安装

本文环境:python3

pip3 install flask-restful
快速入门 一个最小的API

下面来编写一个最小的Flask-RESTful API:

from flask import Flask
from flask_restful import Resource, Api

app = Flask(__name__)
api = Api(app)

class HelloWorld(Resource):
    def get(self):
        return {"hello": "world"}

api.add_resource(HelloWorld, "/")

if __name__ == "__main__":
    app.run(debug=True) 

保存代码到api.py测试时打开debug模式会提供代码重载,以及更详细的错误信息。注意调试模式不可用在生产环境。接下来打开命令窗口输入命令执行py 文件

$ python api.py
 * Running on http://127.0.0.1:5000/
 * Restarting with reloader

新建一个命令窗口,使用curl测试下API

$ curl http://127.0.0.1:5000/
{"hello": "world"}
资源丰富的路由

Flask-RESTful 提供的最主要的基础就是资源,资源是构建在Flask 可插拔的视图之上,只要在你的资源上定义方法就能很容易的访问多个 HTTP 方法,一个待办事项应用的基础 CRUD资源的编写像这样:

from flask import Flask, request
from flask_restful import Resource, Api

app = Flask(__name__)
api = Api(app)

todos = {}

class TodoSimple(Resource):
    def get(self, todo_id):
        # 从 todos 字典中读取数据 注:此处没有对不存在的 key 做处理
        return {todo_id: todos[todo_id]}

    def put(self, todo_id):
        # 将数据保存到 todos 字典中
        todos[todo_id] = request.form["data"]
        return {todo_id: todos[todo_id]}

# 增加资源到 api, 匹配字符串到资源方法的变量
api.add_resource(TodoSimple, "/")

if __name__ == "__main__":
    app.run(debug=True)

保存到文件后执行,使用 curl测试一下

$ curl http://localhost:5000/todo1 -d "data=Remember the milk" -X PUT
{"todo1": "Remember the milk"}

$ curl http://localhost:5000/todo1
{"todo1": "Remember the milk"}

$ curl http://localhost:5000/todo2 -d "data=Change my brakepads" -X PUT
{"todo2": "Change my brakepads"}

$ curl http://localhost:5000/todo2
{"todo2": "Change my brakepads"}

如果有安装 python 的 requests 库也可以用以下方法测试 (Python库系列之requests):

>>> from requests import put, get
>>> put("http://localhost:5000/todo1", data={"data": "Remember the milk"}).json()
{"todo1": "Remember the milk"}
>>> get("http://localhost:5000/todo1").json()
{u"todo1": u"Remember the milk"}
>>> put("http://localhost:5000/todo2", data={"data": "Change my brakepads"}).json()
{u"todo2": u"Change my brakepads"}
>>> get("http://localhost:5000/todo2").json()
{u"todo2": u"Change my brakepads"}

Flask-RESTful支持视图方法多种类型的返回值,像 Flask 一样,你可以返回任何迭代器,它会被转化成一个包含原始响应对象的响应,Flask-RESTful还支持使用多个返回时来设置响应码以及响应头,如下:

class Todo1(Resource):
    def get(self):
        # 默认返回200
        return {"task": "Hello world"}

class Todo2(Resource):
    def get(self):
        # 将响应码设为201
        return {"task": "Hello world"}, 201

class Todo3(Resource):
    def get(self):
        # 将响应码设置为201,并返回自定义头
        return {"task": "Hello world"}, 201, {"Etag": "some-opaque-string"}

api.add_resource(Todo1, "/t1")
api.add_resource(Todo2, "/t2")
api.add_resource(Todo3, "/t3")

保存到文件后执行,使用 curl 测试一下

$curl http://127.0.0.1:5000/t1 -I
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 30
Server: Werkzeug/0.12.2 Python/3.6.4
Date: Wed, 03 Jan 2018 15:07:07 GMT

$curl http://127.0.0.1:5000/t2 -I
HTTP/1.0 201 CREATED
Content-Type: application/json
Content-Length: 30
Server: Werkzeug/0.12.2 Python/3.6.4
Date: Wed, 03 Jan 2018 15:07:10 GMT

$curl http://127.0.0.1:5000/t3 -I
HTTP/1.0 201 CREATED
Content-Type: application/json
Content-Length: 30
Etag: some-opaque-string
Server: Werkzeug/0.12.2 Python/3.6.4
Date: Wed, 03 Jan 2018 15:05:58 GMT
端点

很多时候在一个 API 中,你的资源可以通过多个URLs访问。你可以把多个 URLs 传给 Api 对象的 add_resource() 方法。每一个 URL 都能访问到你的资源

api.add_resource(HelloWorld,
    "/",
    "/hello")

你还可以将路径的部分匹配为资源方法的变量

api.add_resource(Todo,
    "/todo/", endpoint="todo_ep")
注:

如果一个请求与你的应用程序端点中的任何一个都不匹配,Flask-RESTful 将会返回404错误,并附带一段有关其它最相似匹配的端点建议。你可以通过在配置中将ERROR_404_HELP设置为 False禁用此项。

参数解析

尽管 Flask 提供了便捷的方式获取请求的数据(例:查询字符串或POST 表单编码的数据),验证表单依旧很痛苦。Flask-RESTful 内置了支持验证请求数据,它使用了一个类似argparse 的库。

from flask_restful import reqparse

parser = reqparse.RequestParser()
parser.add_argument("rate", type=int, help="Rate to charge for this resource")
args = parser.parse_args()
注:与 argparse 模块不同的是,reqparse.RequestParser.parse_args() 返回了 Python 字典而不是一个自定义的数据结构。

使用 reqparse 模块同样可以自由地提供全面的错误信息。如果一个参数没有通过校验,Flask-RESTful 将会以一个400的错误请求以及高亮的错误信息回应。

$ curl -d "rate=foo" http://127.0.0.1:5000/todos
{"status": 400, "message": "foo cannot be converted to int"}

inputs模块提供许多常用的转换函数,像 inputs.date() 和 inputs.url()。

调用 parse_args 传入 strict=True 能够确保当请求包含了你的解析器中未定义的参数时抛出一个异常。

args = parser.parse_args(strict=True)
数据格式化

默认情况下,在你的迭代返回中所有的字段都将会原样呈现。当你处理 Python 数据结构的时候会觉得它很棒,但在处理对象时会变得非常令人沮丧。为了解决这个问题,Flask-RESTful 提供了fields 模块以及 marshal_with()装饰器。类似 Django ORM 和 WTForm ,你可以使用 fields 模块来描述响应的数据结构。

from flask_restful import fields, marshal_with

resource_fields = {
    "task":   fields.String,
    "uri":    fields.Url("todo_ep")
}

class TodoDao(object):
    def __init__(self, todo_id, task):
        self.todo_id = todo_id
        self.task = task

        # This field will not be sent in the response
        self.status = "active"

class Todo(Resource):
    @marshal_with(resource_fields)
    def get(self, **kwargs):
        return TodoDao(todo_id="my_todo", task="Remember the milk")

上面的例子接收了一个 python对象并准备将其序列化。marshal_with()装饰器会通过resource_fields()进行转换。从对象中提取的唯一字段是 task。fields.Url是一个特殊的字段,它接受端点名称并为响应中的端点生成一个URL。您需要的许多字段类型已经包含在其中。可以查看 fields 项查看完整列表。

完整 TODO 应用例子
from flask import Flask
from flask_restful import reqparse, abort, Api, Resource

app = Flask(__name__)
api = Api(app)

TODOS = {
    "todo1": {"task": "build an API"},
    "todo2": {"task": "?????"},
    "todo3": {"task": "profit!"},
}


def abort_if_todo_doesnt_exist(todo_id):
    if todo_id not in TODOS:
        abort(404, message="Todo {} doesn"t exist".format(todo_id))

parser = reqparse.RequestParser()
parser.add_argument("task")


# Todo
# 显示单个待办任务,并允许删除待办任务项
class Todo(Resource):
    def get(self, todo_id):
        abort_if_todo_doesnt_exist(todo_id)
        return TODOS[todo_id]

    def delete(self, todo_id):
        abort_if_todo_doesnt_exist(todo_id)
        del TODOS[todo_id]
        return "", 204

    def put(self, todo_id):
        args = parser.parse_args()
        task = {"task": args["task"]}
        TODOS[todo_id] = task
        return task, 201


# TodoList
# 展示所有 todos 的列表,允许以POST的方式新建一个 tasks
class TodoList(Resource):
    def get(self):
        return TODOS

    def post(self):
        args = parser.parse_args()
        todo_id = int(max(TODOS.keys()).lstrip("todo")) + 1
        todo_id = "todo%i" % todo_id
        TODOS[todo_id] = {"task": args["task"]}
        return TODOS[todo_id], 201

# 设置 api 资源路由
api.add_resource(TodoList, "/todos")
api.add_resource(Todo, "/todos/")


if __name__ == "__main__":
    app.run(debug=True)

例子使用:

$ python api.py
 * Running on http://127.0.0.1:5000/
 * Restarting with reloader

获取 Todo 列表

$ curl http://localhost:5000/todos
{"todo1": {"task": "build an API"}, "todo3": {"task": "profit!"}, "todo2": {"task": "?????"}}

获取单个 Todo 任务

$ curl http://localhost:5000/todos/todo3
{"task": "profit!"}

删除一个任务

$ curl http://localhost:5000/todos/todo2 -X DELETE -v

> DELETE /todos/todo2 HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.52.1
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 204 NO CONTENT
< Content-Type: application/json
< Content-Length: 0
< Server: Werkzeug/0.12.2 Python/3.6.4
< Date: Wed, 03 Jan 2018 16:07:19 GMT

添加一个新的任务

$ curl http://localhost:5000/todos -d "task=something new" -X POST -v

> POST /todos HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.52.1
> Accept: */*
> Content-Length: 18
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 18 out of 18 bytes
* HTTP 1.0, assume close after body
< HTTP/1.0 201 CREATED
< Content-Type: application/json
< Content-Length: 32
< Server: Werkzeug/0.12.2 Python/3.6.4
< Date: Wed, 03 Jan 2018 16:05:27 GMT
<
{
    "task": "something new"
}
* Curl_http_done: called premature == 0
* Closing connection 0

更新任务

$ curl http://localhost:5000/todos/todo3 -d "task=something different" -X PUT -v

> PUT /todos/todo3 HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.52.1
> Accept: */*
> Content-Length: 24
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 24 out of 24 bytes
* HTTP 1.0, assume close after body
< HTTP/1.0 201 CREATED
< Content-Type: application/json
< Content-Length: 38
< Server: Werkzeug/0.12.2 Python/3.6.4
< Date: Wed, 03 Jan 2018 16:09:05 GMT
<
{
    "task": "something different"
}
* Curl_http_done: called premature == 0
* Closing connection 0
本文关键词

Python

Flask-RESTful

curl

requests

更多阅读

Flask-RESTful — Flask-RESTful 0.3.6 documentation

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/41177.html

相关文章

  • 使用 Flask 和 AngularJS 构建博客 - 1

    摘要:注原文作者,原文地址为在这个教程中,我们将使用和构建一个博客。在开发期间,这将允许我们把它们运行在不同的端口例如和。现在我们将进入目录并使用运行这个脚本。示例创建一篇文章为了创建一篇文章,你需要发送一个请求给。 注:原文作者 John Kevin M. Basco,原文地址为 Building a blog using Flask and AngularJS Part 1 在...

    刘玉平 评论0 收藏0
  • 使用 Flask 和 AngularJS 构建博客 - 1

    摘要:注原文作者,原文地址为在这个教程中,我们将使用和构建一个博客。在开发期间,这将允许我们把它们运行在不同的端口例如和。现在我们将进入目录并使用运行这个脚本。示例创建一篇文章为了创建一篇文章,你需要发送一个请求给。 注:原文作者 John Kevin M. Basco,原文地址为 Building a blog using Flask and AngularJS Part 1 在...

    lavnFan 评论0 收藏0
  • Flask-restful 用法及自定义参数错误信息

    摘要:是我们自定义的错误码为启动文件当我们运行的时候,程序便启动了起来。在中修改只要为,报参数错误正常返回消息把中的方法改为我们自己定义的方法现在再次运行浏览器输入即可得到输入检测一下正常输出完美 flask-restful 是一款比较好用的 flask 插件,它不仅自动为我们实现了数据的 json 化,还能对传入参数进行验证,优雅的替代了 form 表单。 代码结构: app |_api...

    Dogee 评论0 收藏0
  • Flask开发记录系列一项目骨架

    第一步,完成项目骨架。 https://github.com/xbynet/flask-skeleton backend all the requirements show the bellow: Flask==0.11.1 Werkzeug==0.11.11 Jinja2==2.8 SQLAlchemy==1.1.2 celery==3.1.23 Flask-sqlalchemy==2.1 f...

    xiaoqibTn 评论0 收藏0
  • 使用flask开发api——部署flask,使用gunicorn+gevent模式的http ser

    摘要:使用开发部署,使用模式的用开发了服务端的,记录部署上服务器的过程,以供后续使用。退出虚拟环境如果服务器中没有安装,先进行安装增加配置文件创建配置文件编辑内容如下更新会提示相关的进程已经被加入要关闭相关的进程可以用开启可以用 使用flask开发api——部署flask,使用gunicorn+gevent模式的http server 用flask开发了服务端的api,记录部署上服务器的过程...

    XboxYan 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<