目录
一、前言
本文主要对 FastAPI 与 Flask 框架进行对比,以助快速学习。进一步了解FastAPI的高级使用方法,可参考FastAPI官方文档。如果对你有帮助,欢迎三连 收藏点赞关注!!! Flask作为Python语言中的老牌Web框架,已经被应用于大量的Python Web开发项目,其使用简洁,支持工具众多,工具丰富,社区活跃,是Python Web框架中的佼佼者之一。而近来,FastAPI的出众表现,已使得其越来越受到众多开发者的关注,成为Web开发主流框架之一。
---- NickYoung
二、FastAPI 优势
- 高效运行:可与 NodeJS 和 Go 并肩的极高性能(归功于 Starlette 和 Pydantic)。史称最快的 Python web 框架之一。
- 高效编码:提高功能开发速度约 200% 至 300%。
- 更少 bug:减少约 40% 的人为(开发者)导致错误。
- 直观易用:支持强大的编辑器功能、自动补全和更少的调试时间。
- 简单易学:设计的易于使用和学习,阅读文档的时间更短。
- 降低冗余:使代码重复最小化。通过不同的参数声明实现丰富功能。
- 健壮可靠:生产可用级别的代码。还有自动生成的交互式文档。
- 标准化:基于(并完全兼容)API 的相关开放标准:OpenAPI (以前被称为 Swagger) 和 JSON Schema。
下面将会结合Flask的使用作为对比,来介绍FastAPI,作为FastAPI的入门教程。
本文使用的两个Web框架版本如下:
fastapi==0.101.1
Flask==2.3.3
三、Hello World
- Flask 代码
from flask import Flask
app = Flask(__name__)@app.route('/')defhome():return'hello world'if __name__ =='__main__':
app.run()
- FastAPI 代码
import uvicorn
from fastapi import FastAPI
app = FastAPI()@app.get('/')defhome():return'hello world'if __name__ =='__main__':
uvicorn.run(app)
两者的代码差别不多,运行时Flask的默认端口为5000,FastAPI的端口为8000,使用curl命令请求(FastAPI),返回结果如下:
$ curl localhost:8000/
"hello world"
在部署生产代码时,Flask使用gunicorn,示例命令如下:
gunicorn app:app
而FastAPI使用uvicorn,示例命令如下:
uvicorn app:app
当然,在实际部署时还可指定端口(port)、worker数量、最大连接数等,本文不再详述。
四、HTTP 方法
常见的HTTP请求方法有GET, POST, PUT, PATCH, DELETE等。
以POST方法为例
- Flask 代码
@app.route('/', methods=['POST'])defexample():...
- FastAPI 代码
@app.post('/')defexample():...
其它HTTP请求方法的使用方法如下:
@app.get('/')@app.put('/')@app.patch('/')@app.delete('/')
五、URL 变量
我们想从URL中获取user id,比如/users/1,然后将user id返回给用户。
- Flask 代码
@app.route('/users/<int:user_id>')defget_user_details(user_id):return{'user_id': user_id}
- FastAPI 代码
@app.get('/users/{user_id}')defget_user_details(user_id:int):return{'user_id': user_id}
使用curl命令模拟请求如下:
$ curl localhost:8000/users/2
{"user_id":2}
六、查询字符串
我们希望允许用户在URL中使用查询字符串 ?q=abc 来指定搜索词。
- Flask 代码
from flask import request
@app.route('/search')defsearch():
query = request.args.get('q')return{'query': query}
- FastAPI 代码
@app.get('/search')defsearch(q:str):return{'query': q}
使用curl命令模拟请求如下:
$ curl'localhost:8000/search?q=abcde'{"query":"abcde"}
如果要指定多个搜索词,可以&符号隔开,比如:
?name=Jack&id=1
七、POST 请求
我们希望发送一个带有text参数JSON POST请求,返回其小写形式。
# Request{"text":"HELLO"}# Response{"text":"hello"}
- Flask 代码
from flask import request
@app.route('/lowercase', methods=['POST'])deflower_case():
text = request.json.get('text')return{'text': text.lower()}
- FastAPI 代码
from typing import Dict
@app.post('/lowercase')deflower_case(json_data: Dict):
text = json_data.get('text')return{'text': text.lower()}
注意:FastAPI还有更优雅的处理方式,那就是引入Pydantic schema,它可以将JSON格式数据映射为schema对象,同时对该对象中的数据类型进行校验,如校验不通过,则会返回自动生成的校验错误。
- FastAPI 更优雅的代码
classSentence(BaseModel):
text:[email protected]('/lowercase')deflower_case(sentence: Sentence):return{'text': sentence.text.lower()}
使用curl命令模拟请求如下:
$ curl--location'localhost:8000/lowercase'\--header'Content-Type: application/json'\--data'{
"text": "HELLO"
}'{"text":"hello"}
在请求时,如果text对应的value为数字时,FastAPI会自动将数字转化为字符串,不会报错;如果text对应的value为null时,FastAPI将会报错,信息如下:
{"detail":[{"loc":["body","text"],"msg":"none is not an allowed value","type":"type_error.none.not_allowed"}]}
八、文件上传
我们来创建一个上传文件的API,返回上传文件的文件名。
- Flask 代码
from flask import Flask, request
app = Flask(__name__)@app.route('/upload', methods=['POST'])defupload_file():file= request.files.get('file')return{'name':file.filename}
- FastAPI 代码
from fastapi import FastAPI, UploadFile, File
app = FastAPI()@app.post('/upload')defupload_file(file: UploadFile = File(...)):return{'name':file.filename}
使用Postman模拟请求如下:
$ curl--location'localhost:8000/upload'\--header'Content-Type: multipart/form-data'\--form'file=@"/Users/admin/Documents/test.pdf"'{"name":"test.pdf"}
九、表单提交
我们希望从表单中获取text类型的变量,并返回它的值,如下:
- Flask 代码
from flask import Flask, request
app = Flask(__name__)@app.route('/submit', methods=['POST'])defecho():
city = request.form.get('city')return{'city': city}
- FastAPI 代码
from fastapi import FastAPI, Form
app = FastAPI()@app.post('/submit')defecho(city:str= Form(...)):return{'city': city}
使用curl命令模拟请求如下:
$ curl--location'localhost:8000/submit'\--form'city="shanghai"'{"city":"shanghai"}
十、Cookies
我们希望从请求的cookie中获取name字段的值。
- Flask 代码
from flask import Flask, request
app = Flask(__name__)@app.route('/profile')defprofile():
name = request.cookies.get('name')return{'name': name}
- FastAPI 代码
from fastapi import FastAPI, Cookie
app = FastAPI()@app.get('/profile')defprofile(name=Cookie(None)):return{'name': name}
十一、模块化视图
我们希望将单个的app.py文件分解成视图(多个独立的文件),如下:
- app.py
- views
- user.py
- Flask 代码
在Flask中,我们可以使用蓝图(Blueprint)来管理,代码如下:
from flask import Blueprint
user_blueprint = Blueprint('user', __name__)@user_blueprint.route('/users')deflist_users():return{'users':['a','b','c']}
from flask import Flask
from views.user import user_blueprint
app = Flask(__name__)
app.register_blueprint(user_blueprint)
- FastAPI 代码
在FastAPI中,与蓝图等价的实现形式为router,首先需创建一个user router如下:
from fastapi import APIRouter
router = APIRouter()@router.get('/users')deflist_users():return{'users':['a','b','c']}
# app.pyfrom fastapi import FastAPI
from routers import user
app = FastAPI()
app.include_router(user.router)
十二、数据校验
Flask本身并没有提供数据校验功能,可使用marshmalllow或pydantic模块来辅助实现。
而FastAPI在其框架中已包装pydantic模块,可轻松实现数据校验。示例代码如下:
import uvicorn
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()classUser(BaseModel):
name:str
age:[email protected]('/users')defsave_user(user: User):return{'name': user.name,'age': user.age}if __name__ =='__main__':
uvicorn.run(app)
关于pydantic的schema与JSON格式对应关系,在此给出三个例子:
- 例子1 键值对(key-value pairs)
{"name":"Isaac","age":60}
from pydantic import BaseModel
classUser(BaseModel):
name:str
age:int
- 例子2 列表
{"series":["GOT","Dark","Mr. Robot"]}
from pydantic import BaseModel
from typing import List
classMetadata(BaseModel):
series: List[str]
- 例子3 嵌套对象
{"users":[{"name":"xyz","age":25},{"name":"abc","age":30}],"group":"Group A"}
from pydantic import BaseModel
from typing import List
classUser(BaseModel):
name:str
age:intclassUserGroup(BaseModel):
users: List[User]
group:str
十三、自动化文档
Flask并没有提供内置的自动化文档生成,可使用flask-swagger或flask-restful模块来辅助实现。
FastAPI可生成自动化文档,文档风格包括swagger和redoc,其中swagger对应路径为/docs,redoc对应路径为/redoc,如下所示:
Swagger 风格
ReDoc 风格
十四、CORS跨域
- Flask本身不支持CORS,可使用flask-cors模块辅助实现,代码如下:
from flask import Flask
from flask_cors import CORS
app_ = Flask(__name__)
CORS(app_)
- FastAPI提供了内置的中间件来处理CORS,示例代码如下:
# app.pyfrom fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=['*'],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],)
版权归原作者 Nick Peng 所有, 如有侵权,请联系我们删除。