FastAPI 快速学习之 Flask 框架对比

目录

一、前言

本文主要对 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框架版本如下:

shell 复制代码
fastapi==0.101.1
Flask==2.3.3

三、Hello World

  • Flask 代码
python 复制代码
from flask import Flask

app = Flask(__name__)

@app.route('/')
def home():
    return 'hello world'

if __name__ == '__main__':
    app.run()
  • FastAPI 代码
python 复制代码
import uvicorn
from fastapi import FastAPI

app = FastAPI()


@app.get('/')
def home():
    return 'hello world'


if __name__ == '__main__':
    uvicorn.run(app)

两者的代码差别不多,运行时Flask的默认端口为5000,FastAPI的端口为8000,使用curl命令请求(FastAPI),返回结果如下:

shell 复制代码
$ 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 代码
python 复制代码
@app.route('/', methods=['POST'])
def example():
    ...
  • FastAPI 代码
python 复制代码
@app.post('/')
def example():
    ...

其它HTTP请求方法的使用方法如下:

python 复制代码
@app.get('/')
@app.put('/')
@app.patch('/')
@app.delete('/')

五、URL 变量

我们想从URL中获取user id,比如/users/1,然后将user id返回给用户。

  • Flask 代码
python 复制代码
@app.route('/users/<int:user_id>')
def get_user_details(user_id):
    return {'user_id': user_id}
  • FastAPI 代码
python 复制代码
@app.get('/users/{user_id}')
def get_user_details(user_id: int):
    return {'user_id': user_id}

使用curl命令模拟请求如下:

shell 复制代码
$ curl localhost:8000/users/2
{"user_id":2}

六、查询字符串

我们希望允许用户在URL中使用查询字符串 ?q=abc 来指定搜索词。

  • Flask 代码
python 复制代码
from flask import request

@app.route('/search')
def search():
    query = request.args.get('q')
    return {'query': query}
  • FastAPI 代码
python 复制代码
@app.get('/search')
def search(q: str):
    return {'query': q}

使用curl命令模拟请求如下:

shell 复制代码
$ curl 'localhost:8000/search?q=abcde'
{"query":"abcde"}

如果要指定多个搜索词,可以&符号隔开,比如:?name=Jack&id=1

七、POST 请求

我们希望发送一个带有text参数JSON POST请求,返回其小写形式。

python 复制代码
# Request
{"text": "HELLO"}

# Response
{"text": "hello"}
  • Flask 代码
python 复制代码
from flask import request

@app.route('/lowercase', methods=['POST'])
def lower_case():
    text = request.json.get('text')
    return {'text': text.lower()}
  • FastAPI 代码
python 复制代码
from typing import Dict

@app.post('/lowercase')
def lower_case(json_data: Dict):
    text = json_data.get('text')
    return {'text': text.lower()}

注意:FastAPI还有更优雅的处理方式,那就是引入Pydantic schema,它可以将JSON格式数据映射为schema对象,同时对该对象中的数据类型进行校验,如校验不通过,则会返回自动生成的校验错误。

  • FastAPI 更优雅的代码
python 复制代码
class Sentence(BaseModel):
    text: str

@app.post('/lowercase')
def lower_case(sentence: Sentence):
    return {'text': sentence.text.lower()}

使用curl命令模拟请求如下:

shell 复制代码
$ curl --location 'localhost:8000/lowercase' \
--header 'Content-Type: application/json' \
--data '{
"text": "HELLO"
}'
{"text":"hello"}

在请求时,如果text对应的value为数字时,FastAPI会自动将数字转化为字符串,不会报错;如果text对应的value为null时,FastAPI将会报错,信息如下:

json 复制代码
{
  "detail": [
    {
      "loc": [
        "body",
        "text"
      ],
      "msg": "none is not an allowed value",
      "type": "type_error.none.not_allowed"
    }
  ]
}

八、文件上传

我们来创建一个上传文件的API,返回上传文件的文件名。

  • Flask 代码
python 复制代码
from flask import Flask, request

app = Flask(__name__)

@app.route('/upload', methods=['POST'])
def upload_file():
    file = request.files.get('file')
    return {'name': file.filename}
  • FastAPI 代码
python 复制代码
from fastapi import FastAPI, UploadFile, File

app = FastAPI()

@app.post('/upload')
def upload_file(file: UploadFile = File(...)):
    return {'name': file.filename}

使用Postman模拟请求如下:

shell 复制代码
$ curl --location 'localhost:8000/upload' \
--header 'Content-Type: multipart/form-data' \
--form 'file=@"/Users/admin/Documents/test.pdf"'
{"name": "test.pdf"}

九、表单提交

我们希望从表单中获取text类型的变量,并返回它的值,如下:

  • Flask 代码
python 复制代码
from flask import Flask, request

app = Flask(__name__)

@app.route('/submit', methods=['POST'])
def echo():
    city = request.form.get('city')
    return {'city': city}
  • FastAPI 代码
python 复制代码
from fastapi import FastAPI, Form

app = FastAPI()

@app.post('/submit')
def echo(city: str = Form(...)):
    return {'city': city}

使用curl命令模拟请求如下:

shell 复制代码
$ curl --location 'localhost:8000/submit' \
--form 'city="shanghai"'
{"city":"shanghai"}

十、Cookies

我们希望从请求的cookie中获取name字段的值。

  • Flask 代码
python 复制代码
from flask import Flask, request

app = Flask(__name__)

@app.route('/profile')
def profile():
    name = request.cookies.get('name')
    return {'name': name}
  • FastAPI 代码
python 复制代码
from fastapi import FastAPI, Cookie

app = FastAPI()

@app.get('/profile')
def profile(name=Cookie(None)):
    return {'name': name}

十一、模块化视图

我们希望将单个的app.py文件分解成视图(多个独立的文件),如下:

shell 复制代码
- app.py
- views
  - user.py
  • Flask 代码

在Flask中,我们可以使用蓝图(Blueprint)来管理,代码如下:

python 复制代码
from flask import Blueprint

user_blueprint = Blueprint('user', __name__)

@user_blueprint.route('/users')
def list_users():
    return {'users': ['a', 'b', 'c']}
python 复制代码
from flask import Flask

from views.user import user_blueprint

app = Flask(__name__)
app.register_blueprint(user_blueprint)
  • FastAPI 代码

在FastAPI中,与蓝图等价的实现形式为router,首先需创建一个user router如下:

python 复制代码
from fastapi import APIRouter

router = APIRouter()

@router.get('/users')
def list_users():
    return {'users': ['a', 'b', 'c']}
python 复制代码
# app.py
from fastapi import FastAPI
from routers import user

app = FastAPI()
app.include_router(user.router)

十二、数据校验

Flask本身并没有提供数据校验功能,可使用marshmalllow或pydantic模块来辅助实现。

而FastAPI在其框架中已包装pydantic模块,可轻松实现数据校验。示例代码如下:

python 复制代码
import uvicorn
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class User(BaseModel):
    name: str
    age: int


@app.post('/users')
def save_user(user: User):
    return {'name': user.name,
            'age': user.age}


if __name__ == '__main__':
    uvicorn.run(app)

关于pydantic的schema与JSON格式对应关系,在此给出三个例子:

  • 例子1 键值对(key-value pairs)
json 复制代码
{
  "name": "Isaac",
  "age": 60
}
python 复制代码
from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int
  • 例子2 列表
json 复制代码
{
  "series": ["GOT", "Dark", "Mr. Robot"]
}
python 复制代码
from pydantic import BaseModel
from typing import List

class Metadata(BaseModel):
    series: List[str]
  • 例子3 嵌套对象
json 复制代码
{
  "users": [
    {
      "name": "xyz",
      "age": 25
    },
    {
      "name": "abc",
      "age": 30
    }
  ],
  "group": "Group A"
}
python 复制代码
from pydantic import BaseModel
from typing import List

class User(BaseModel):
    name: str
    age: int

class UserGroup(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模块辅助实现,代码如下:
python 复制代码
from flask import Flask
from flask_cors import CORS

app_ = Flask(__name__)
CORS(app_)
  • FastAPI提供了内置的中间件来处理CORS,示例代码如下:
python 复制代码
# app.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=['*'],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
相关推荐
u0103055273 小时前
Java实用类应用精讲
人工智能·1024程序员节
aGdF8E3gQ7 小时前
【Application Insights】采样率对Function App日志收集的影响和解决方法
python·flask·wpf
李昊哲小课8 小时前
fastapi sse websocket 智能家居实时控制台
python·websocket·智能家居·fastapi·sse
赵广陆10 小时前
SQLAlchemy ORM 超全教程
python·fastapi
u01030552712 小时前
Java I/O核心操作实战
人工智能·1024程序员节
为啥全要学12 小时前
fastapi websocket全双工通信
websocket·网络协议·fastapi
编码者卢布12 小时前
【Azure APIM】通过 API Management 公开API为 MCP Server 的试验 (二)
microsoft·flask·azure
这就是佬们吗12 小时前
企业Agent落地为什么需要RAG?
人工智能·python·fastapi
编码者卢布1 天前
【Azure APIM】通过 API Management 公开现有 MCP Server 的试验 (一)
microsoft·flask·azure
鲨鱼辣钊1 天前
【FastAPI 筑基 - Day2】彩色日志封装 + Python 装饰器精讲
fastapi