Python flask-restful框架讲解

Flask-RESTful 是一个 Flask 扩展,它添加了快速构建 REST APIs 的支持。它当然也是一个能够跟你现有的ORM/库协同工作的轻量级的扩展。Flask-RESTful 鼓励以最小设置的最佳实践。如果你熟悉 Flask 的话,Flask-RESTful 应该很容易上手。
关于flask的使用,参考我的之前的博客:https://blog.csdn.net/shifengboy/article/details/114274271

flask-restful官方文档:https://flask-restful.readthedocs.io/en/lates
中文文档:http://www.pythondoc.com/Flask-RESTful/

flask-restful 安装

pip install flask-restful

flask-restful使用

简单上手

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)

运行结果:

$ curl http://127.0.0.1:5000/
{"hello": "world"}

Resourceful 路由

Flask-RESTful 提供的主要构建块是资源。资源构建在 Flask 可插入视图之上,只需在资源上定义方法,就可以轻松访问多个 HTTP 方法。一个 todo 应用程序的基本 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):

return {todo_id: todos[todo_id]}



<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">put</span>(<span class="hljs-params">self, todo_id</span>):</span>
    todos[todo_id] = request.form[<span class="hljs-string">'data'</span>]
    <span class="hljs-keyword">return</span> {todo_id: todos[todo_id]}




api.add_resource(TodoSimple, '/<string:todo_id>')


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">put</span>(<span class="hljs-params">self, todo_id</span>):</span>
    todos[todo_id] = request.form[<span class="hljs-string">'data'</span>]
    <span class="hljs-keyword">return</span> {todo_id: todos[todo_id]}
if name == 'main':

app.run(debug=True)

运行结果:

chenshifengdeMacBook-Pro:~ chenshifeng$ curl http://localhost:5000/todo1 -d "data=Remember the milk" -X PUT
{
    "todo1": "Remember the milk"
}
chenshifengdeMacBook-Pro:~ chenshifeng$ curl http://localhost:5000/todo1
{
    "todo1": "Remember the milk"
}
chenshifengdeMacBook-Pro:~ chenshifeng$ curl http://localhost:5000/todo2 -d "data=Change my brakepads" -X PUT
{
    "todo2": "Change my brakepads"
}
chenshifengdeMacBook-Pro:~ chenshifeng$ curl http://localhost:5000/todo2
{
    "todo2": "Change my brakepads"
}
chenshifengdeMacBook-Pro:~ chenshifeng$ 

Restful 能够从 view 方法中理解多种返回值。类似于 Flask,你可以返回任何可迭代的并且它将被转换成一个响应,包括原始 Flask 响应对象。还支持使用多个返回值设置响应代码和响应头,如下所示:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
@author:chenshifeng
@file:flask_restful_demo.py
@time:2021/03/05
"""
from flask import Flask, request
from flask_restful import Resource, Api


app = Flask(name)

api = Api(app)




class Todo1(Resource):

def get(self):

# Default to 200 OK

return {'task': 'Hello world'}




class Todo2(Resource):

def get(self):

# Set the response code to 201

return {'task': 'Hello world'}, 201




class Todo3(Resource):

def get(self):

# Set the response code to 201 and return custom headers

return {'task': 'Hello world'}, 201, {'Etag': 'some-opaque-string'}




api.add_resource(Todo1,'/todo1')

api.add_resource(Todo2,'/todo2')

api.add_resource(Todo3,'/todo3')


if name == 'main':

app.run(debug=True)

运行结果:

chenshifengdeMacBook-Pro:~ chenshifeng$ curl -i  http://127.0.0.1:5000/todo1 
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 30
Server: Werkzeug/1.0.1 Python/3.9.2
Date: Fri, 05 Mar 2021 16:08:28 GMT


{

"task": "Hello world"

}

chenshifengdeMacBook-Pro:~ chenshifeng$ curl -i  http://127.0.0.1:5000/todo2

HTTP/1.0 201 CREATED

Content-Type: application/json

Content-Length: 30

Server: Werkzeug/1.0.1 Python/3.9.2

Date: Fri, 05 Mar 2021 16:08:32 GMT




{

"task": "Hello world"

}

chenshifengdeMacBook-Pro:~ chenshifeng$ curl -i  http://127.0.0.1:5000/todo3

HTTP/1.0 201 CREATED

Content-Type: application/json

Content-Length: 30

Etag: some-opaque-string

Server: Werkzeug/1.0.1 Python/3.9.2

Date: Fri, 05 Mar 2021 16:08:34 GMT




{

"task": "Hello world"

}

chenshifengdeMacBook-Pro:~ chenshifeng$



Endpoints 端点

很多时候,在一个 API 中,你的资源会有多个 url。可以将多个 url 传递给 Api 对象上的 add _ resource ()方法。每一个都将被路由到Resource

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

您还可以将路径的某些部分作为变量匹配到Resource。

api.add_resource(Todo,
    '/todo/<int:todo_id>', endpoint='todo_ep')

演示代码:

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




class Todo(Resource):

def get(self, todo_id):

# Default to 200 OK

return {'task': 'Hello world'}




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

api.add_resource(Todo, '/todo/<int:todo_id>', endpoint='todo_ep')


if name == 'main':

app.run(debug=True)

演示结果:

chenshifengdeMacBook-Pro:~ chenshifeng$ curl  http://127.0.0.1:5000/
{
    "hello": "world"
}
chenshifengdeMacBook-Pro:~ chenshifeng$ curl  http://127.0.0.1:5000/hello
{
    "hello": "world"
}
chenshifengdeMacBook-Pro:~ chenshifeng$ curl  http://127.0.0.1:5000/todo/1
{
    "task": "Hello world"
}
chenshifengdeMacBook-Pro:~ chenshifeng$ curl  http://127.0.0.1:5000/todo/2
{
    "task": "Hello world"
}

参数解析

虽然 Flask 可以方便地访问请求数据(即 querystring 或 POST 表单编码的数据) ,但验证表单数据仍然是一件痛苦的事情。使用类似于 argparse 的库对请求数据验证提供内置支持。

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


app = Flask(name)

api = Api(app)




parser = reqparse.RequestParser()

parser.add_argument('rate', type=int, help='Rate to charge for this resource')




class Todo(Resource):

def post(self):

args = parser.parse_args()

print(args)

# Default to 200 OK

return {'task': 'Hello world'}




api.add_resource(Todo,'/todos' )


if name == 'main':

app.run(debug=True)

chenshifengdeMacBook-Pro:~ chenshifeng$ curl -d 'rate=100' http://127.0.0.1:5000/todos
{
    "task": "Hello world"
}
chenshifengdeMacBook-Pro:~ chenshifeng$ curl -d 'rate=foo' http://127.0.0.1:5000/todos
{
    "message": {
        "rate": "Rate to charge for this resource"
    }
}

与 argparse 模块不同,reqparse. RequestParser.parse _ args ()返回 Python 字典,而不是自定义数据结构。

输入模块提供了许多常用的转换函数,例如 inputs.date ()和 inputs.url ()。
使用 strict = True 调用 parse _ args 可以确保在请求包含您的解析器没有定义的参数时抛出错误。

args = parser.parse_args(strict=True)
$ curl -d 'rate2=foo' http://127.0.0.1:5000/todos
{
    "message": "Unknown arguments: rate2"
}

数据格式化

默认情况下,在你的返回迭代中所有字段将会原样呈现。尽管当你刚刚处理 Python 数据结构的时候,觉得这是一个伟大的工作,但是当实际处理它们的时候,会觉得十分沮丧和枯燥。为了解决这个问题,Flask-RESTful 提供了 fields 模块和 marshal_with() 装饰器。类似 Django ORM 和 WTForm,你可以使用 fields 模块来在你的响应中格式化结构。

from flask import Flask
from flask_restful import fields, marshal_with, Resource, Api


app = Flask(name)

api = Api(app)




resource_fields = {

'task':   fields.String,

'uri':    fields.Url('todo')

}




class TodoDao(object):

def init(self, todo_id, task):

self.todo_id = todo_id

self.task = task



    <span class="hljs-comment"># This field will not be sent in the response</span>
    self.status = <span class="hljs-string">'active'</span>




class Todo(Resource):

    @marshal_with(resource_fields)

def get(self, **kwargs):

return TodoDao(todo_id='my_todo', task='Remember the milk')




api.add_resource(Todo,'/todo')


    <span class="hljs-comment"># This field will not be sent in the response</span>
    self.status = <span class="hljs-string">'active'</span>
if name == 'main':

app.run(debug=True)

上面的例子接受一个 python 对象并准备将其序列化。marshal_with() 装饰器将会应用到由 resource_fields 描述的转换。从对象中提取的唯一字段是 task。fields.Url 域是一个特殊的域,它接受端点(endpoint)名称作为参数并且在响应中为该端点生成一个 URL。许多你需要的字段类型都已经包含在内。请参阅 fields 指南获取一个完整的列表。

$ curl  http://127.0.0.1:5000/todo
{
    "task": "Remember the milk",
    "uri": "/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

# shows a single todo item and lets you delete a todo item

class Todo(Resource):

def get(self, todo_id):

abort_if_todo_doesnt_exist(todo_id)

return TODOS[todo_id]



<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">delete</span>(<span class="hljs-params">self, todo_id</span>):</span>
    abort_if_todo_doesnt_exist(todo_id)
    <span class="hljs-keyword">del</span> TODOS[todo_id]
    <span class="hljs-keyword">return</span> <span class="hljs-string">''</span>, <span class="hljs-number">204</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">put</span>(<span class="hljs-params">self, todo_id</span>):</span>
    args = parser.parse_args()
    task = {<span class="hljs-string">'task'</span>: args[<span class="hljs-string">'task'</span>]}
    TODOS[todo_id] = task
    <span class="hljs-keyword">return</span> task, <span class="hljs-number">201</span>




# TodoList

# shows a list of all todos, and lets you POST to add new tasks

class TodoList(Resource):

def get(self):

return TODOS



<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">post</span>(<span class="hljs-params">self</span>):</span>
    args = parser.parse_args()
    todo_id = <span class="hljs-built_in">int</span>(<span class="hljs-built_in">max</span>(TODOS.keys()).lstrip(<span class="hljs-string">'todo'</span>)) + <span class="hljs-number">1</span>
    todo_id = <span class="hljs-string">'todo%i'</span> % todo_id
    TODOS[todo_id] = {<span class="hljs-string">'task'</span>: args[<span class="hljs-string">'task'</span>]}
    <span class="hljs-keyword">return</span> TODOS[todo_id], <span class="hljs-number">201</span>




##

## Actually setup the Api resource routing here

##

api.add_resource(TodoList, '/todos')

api.add_resource(Todo, '/todos/<todo_id>')


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">delete</span>(<span class="hljs-params">self, todo_id</span>):</span>
    abort_if_todo_doesnt_exist(todo_id)
    <span class="hljs-keyword">del</span> TODOS[todo_id]
    <span class="hljs-keyword">return</span> <span class="hljs-string">''</span>, <span class="hljs-number">204</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">put</span>(<span class="hljs-params">self, todo_id</span>):</span>
    args = parser.parse_args()
    task = {<span class="hljs-string">'task'</span>: args[<span class="hljs-string">'task'</span>]}
    TODOS[todo_id] = task
    <span class="hljs-keyword">return</span> task, <span class="hljs-number">201</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">post</span>(<span class="hljs-params">self</span>):</span>
    args = parser.parse_args()
    todo_id = <span class="hljs-built_in">int</span>(<span class="hljs-built_in">max</span>(TODOS.keys()).lstrip(<span class="hljs-string">'todo'</span>)) + <span class="hljs-number">1</span>
    todo_id = <span class="hljs-string">'todo%i'</span> % todo_id
    TODOS[todo_id] = {<span class="hljs-string">'task'</span>: args[<span class="hljs-string">'task'</span>]}
    <span class="hljs-keyword">return</span> TODOS[todo_id], <span class="hljs-number">201</span>
if name == 'main':

app.run(debug=True)

获取列表

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

获取一个单独的任务

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

删除一个任务

$ curl http://localhost:5000/todos/todo2 -X DELETE -v
*   Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 5000 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 5000 (#0)
> DELETE /todos/todo2 HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.64.1
> Accept: */*
> 
* HTTP 1.0, assume close after body
< HTTP/1.0 204 NO CONTENT
< Content-Type: application/json
< Server: Werkzeug/1.0.1 Python/3.9.2
< Date: Sat, 06 Mar 2021 03:29:33 GMT
< 
* Closing connection 0

增加一个新的任务

$ curl http://localhost:5000/todos -d "task=something new" -X POST -v
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 5000 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 5000 (#0)
> POST /todos HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.64.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/1.0.1 Python/3.9.2
< Date: Sat, 06 Mar 2021 03:31:02 GMT
< 
{
    "task": "something new"
}
* Closing connection 0

更新一个任务

$  curl http://localhost:5000/todos/todo3 -d "task=something different" -X PUT -v
*   Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 5000 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 5000 (#0)
> PUT /todos/todo3 HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.64.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/1.0.1 Python/3.9.2
< Date: Sat, 06 Mar 2021 03:32:44 GMT
< 
{
    "task": "something different"
}
* Closing connection 0

获取最新列表

$ curl http://localhost:5000/todos
{
    "todo1": {
        "task": "build an API"
    },
    "todo3": {
        "task": "something different"
    },
    "todo4": {
        "task": "something new"
    }
}
posted @   R-Bear  阅读(681)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
点击右上角即可分享
微信分享提示