Python web框架FastAPI入门——一个比Flask和Tornada更高性能的API 框架

用官方的话来说,FastAPI 是一种现代,快速(高性能)的 Web 框架,基于标准Python 类型提示使用 Python 3.6+ 构建 API

FastAPI 站在巨人的肩膀上?

很大程度上来说,这个巨人就是指 Flask 框架。

FastAPI 从语法上和 Flask 非常的相似,有异曲同工之妙。

技术背景:Py3.6+,Starlette,Pydantic

其实不仅仅是 FastAPI ,就连 Sanic 也是基于 Flask 快速开发的 Web API 框架。

废话少说,代码总是能给人带来愉悦感 (抱头),直接开怼。

安装

pip install fastapi 
pip install uvicorn

创建一个 main.py 文件

from fastapi import FastAPIapp = FastAPI() # 创建 api 对象
@app.get("/") # 根路由def root():   
 return {"武汉": "加油!!!"}
@app.get("/say/{data}")def say(data: str,q: int):    
return {"data": data, "item": q}

上面搭建了一个最简单的 FastAPI 应用,看起来和 Flask 完全一样,莫名的喜感。

使用以下命令来启动服务器:

uvicorn main:app --reload

FastAPI 推荐使用 uvicorn 来运行服务,Uvicorn 是基于uvloop 和 httptools 构建的闪电般快速的 ASGI 服务器。

uvicorn main:app 指的是:

main:文件main.py

app:  创建的启用对象

--reload:  热启动,方便代码的开发

启动界面如下:

INFO 信息告诉我们已经监听了本地的 8000 端口,访问 http://127.0.0.1:8000 得到结果

传入参数

再来看看 FastAPI 的异步代码

from fastapi import FastAPIapp = FastAPI() # 创建 api 对象
@app.get("/") # 根路由async def root():    
return {"武汉": "加油!!!"}
@app.get("/say/{data}")async def say(data: str,q: int = None):   
 return {"data": data, "q": q}

开启服务后访问结果是一样的。

在上面的路由方法中,我们传入了一个 q 参数并且初始为 None,如果不给默认值,并且不传参,代码将直接报错。

来看看 FastAPI 是如何处理错误的:


可以看到,即使是报错,也是优美的输入一个带有错误字段的 JSON,这就非常的友好了,这也是体现了 FastAPI 减少更多的人为错误的特性,返回也更加的简洁直观。

在命令行输出:

再来看看 FastAPI 的交互文档

根据官方文档,打开 http://127.0.0.1:8000/docs

看到:

支持动态传入数据:


结果:

从交互体验上也是无比的友好,让代码在生产中更加健壮。

现在我们算是快速的体验了一波 FastAPI 骚操作,从代码上和 Flask 及其的类似,体验性更好。

那么再来看看最新的 Python web框架的性能响应排行版

从并发性上来说是完全碾压了 Flask (实际上也领先了同为异步框架的tornado 不少),看来 FastAPI 也真不是盖的,名副其实的高性能 API 框架呀!

查询参数

先来看看官方小 demo

from fastapi import FastAPI
app = FastAPI()fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
@app.get("/items/")
async def read_item(skip: int = 0, limit: int = 10):    
return fake_items_db[skip : skip + limit]

该查询是 ? URL中位于关键字之后的一组键值对,以&字符分隔。

在 url 中进行查询

http://127.0.0.1:8000/items/?skip=0&limit=10

skip:查询的起始参数

limit:查询的结束参数

成功返回查询列表。

查询参数类型转换

FastAPI 非常聪明,足以辨别 路径参数 和 查询参数。

来看看具体的例子:

from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id: str, q: str = None, short: bool = False):    
item = {"item_id": item_id}   
 if q:        
item.update({"q": q})    
if not short:        
item.update(           
 {"description": "This is an amazing item that has a long description"}        
)    
return item

看看其访问路径,执行以下的任何一种 url 访问方式

http://127.0.0.1:8000/items/武汉加油?short=1

http://127.0.0.1:8000/items/武汉加油?short=True

http://127.0.0.1:8000/items/武汉加油?short=true

http://127.0.0.1:8000/items/武汉加油?short=on

http://127.0.0.1:8000/items/武汉加油?short=yes

可以发现任何大小写的字母等都会被转换成 bool 值的参数 True,这就是所谓模糊验证参数,对于开发者来说这是个好消息。

要知道的是,如果 short 参数没有默认值,则必须传参,否则 FastAPI 将会返回类似以下的错误信息。

{    
    "detail": [        
    {            
    "loc": [                
    "query",                
    "needy"            
],           
     "msg": "field required",            
    "type": "value_error.missing"       
     }    
]}

创建数据模型

前面说到 FastAPI 依赖 Pydantic 模块,所以首先,你需要导入 Pydantic 的 BaseModel 类。

from fastapi import FastAPI
from pydantic import BaseModel
# 请求主体类
class Item(BaseModel):    
name: str = "武汉加油 !!"    
description: str = None    
price: float = 233   
tax: float = Noneapp = FastAPI()
@app.post("/items/")
async def create_item(item: Item):    
return item

发送 post 请求来提交一个 Item(请求主体) 并返回,来看看提交过程。


成功提交并返回 200 状态码

请求主体+路径+查询参数,在请求主体的基础上加入 url 动态路径参数 和 查询参数

from fastapi import FastAPI
from pydantic import BaseModelclass 

Item(BaseModel):    
name: str    
description: str = None   
 price: float   
 tax: float = Noneapp = FastAPI()
@app.put("/items/{item_id}")
async def create_item(item_id: int, item: Item, q: str = None):    
result = {"item_id": item_id, **item.dict()}   
 if q:       
 result.update({"q": q})   
 return result

put 方法用于更新,传入参数后成功返回一个字典。

关于模板引擎

FastAPI 不像 Flask 那样自带 模板引擎(Jinja2),也就是说没有默认的模板引擎,从另一个角度上说,FastAPI 在模板引擎的选择上变得更加灵活,极度舒适。

以 Jinja2 模板为例

安装依赖

pip install jinja2
pip install aiofiles # 用于 fastapi 的异步静态文件

具体的用法

# -*- coding:utf-8 -*-
from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
import uvicorn
app = FastAPI()app.mount("/static", StaticFiles(directory="static"), name="static") # 挂载静态文件,指定目录templates = Jinja2Templates(directory="templates") # 模板目录@app.get("/data/{data}")
async def read_data(request: Request, data: str):   
 return templates.TemplateResponse("index.html", {"request": request, "data": data})

if __name__ == '__main__':    
uvicorn.run(app, host="127.0.0.1", port=8000)

html 文件渲染

<html>
<head>    
<title>武汉加油</title>
</head>
<body>   
 <h1>高呼: {{ data }}</h1>
</body>
</html>

在浏览器键入 http://127.0.0.1:8000/data/武汉加油

值得注意的是,在返回的 TemplateRespone 响应时,必须带上 request 的上下文对象,传入参数放在同一字典。

这样一来,又可以像 Flask 一样的使用熟悉的 Jinja2 了,哈哈。

做个小总结的话就是 FastAPI 在用法上也是及其简单,速度更快,性能更好,容错率更高,整体上更牛逼。但是我在设想如此之快的框架,毕竟发布的时间不长,缺少像 Flask 框架的第三方库和各种插件,所以要想真正意义上替代还是需要一定的时间。

FastAPI 的官方文档有详细的介绍和实例,入门篇到此结束。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,718评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,683评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,207评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,755评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,862评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,050评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,136评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,882评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,330评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,651评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,789评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,477评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,135评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,864评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,099评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,598评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,697评论 2 351

推荐阅读更多精彩内容