1+1=10

记记笔记,放松一下...

Python FastAPI入门笔记(一)

接前面Python的Web框架梳理ASGI入门笔记,继续了解一下FastAPI。

FastAPI 是一个用于构建API的现代化的web框架,首次发布于2018年。它建立在Starlette和Pydantic基础之上。

  • Starlette:在Python下创建异步web服务的一个轻量的ASGI框架、工具集。
  • Pydantic:基于Python类型提示来定义数据验证、序列化的库。

内容小记:

  • 安装与启动ASGI服务端: uvicorn
  • 返回除json之外的其他响应格式
  • 路径操作函数async defdef
  • 路径操作装饰符

准备

安装fastapi

1
pip install fastapi

安装uvicorn

1
pip install "uvicorn[standard]"
  • 注意方括号内内容,这会安装uvicorn和它依赖的基于Cython的模块和其他模块。不然只会安装纯python的依赖。

入门例子

从简单的例子开始

例子1

文件 myapi.py

1
2
3
4
5
6
7
8
from fastapi import FastAPI

app = FastAPI()


@app.get("/")
async def home():
    return {"message": "Hello World"}

运行它

1
uvicorn myapi:app --reload
  • --reload:自动加载,调试有用
  • --ssl-keyfile:ssl 私钥文件
  • --ssl-certfile:ssl证书文件

而后通过浏览器访问:127.0.0.1:8000

注:浏览器端看到了是一个JSON对象

除了命令行,也可以直接通过代码运行uvicorn服务:

1
2
3
if __name__ == '__main__':
    from uvicorn import run
    run(app)

doc

这个程序中,FastAPI除了注册路由之外,还自动生成了文档:

  • Wsagger UI风格文档:127.0.0.1:8000/docs
  • ReDoc风格文档:127.0.0.1:8000/redoc

如果不想要,可以关闭

1
app = FastAPI(docs_rul=None, redoc_url=None)

另外,FastAPI框架内部还实现了OpenAPI 规范,通过 127.0.0.1:8000/openapi.json 访问

例子2

在前面的例子中,浏览器端看到了是一个JSON对象。因为FastAPI将路径函数的返回值使用jsonable_encoder转成了JSONResponse。默认是json。

即使写成下面这样,返回的也是json:

1
2
3
4
5
6
7
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return "Hello World"

要返回其他内容,需要使用Response:

1
2
3
4
5
6
7
from fastapi import FastAPI, Response

app = FastAPI()

@app.get("/")
async def root():
    return Response(content="Hello World", media_type="text/plain")

或者

1
2
3
4
5
6
7
from fastapi import FastAPI, responses

app = FastAPI()

@app.get("/")
async def root():
    return responses.PlainTextResponse("Hello World")

注:这儿的 fastapi.responses 其实就是 starlette.reponses

例子3

响应类型可以通过response_class来指定,这样似乎更简单一些,比如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from fastapi import FastAPI
from fastapi.responses import HTMLResponse

app = FastAPI()

@app.get("/", response_class=HTMLResponse)
async def root():
    return """
    <html>
        <body>
            <h1>Hello 1+1=10!</h1>
        </body>
    </html>
    """

路径操作函数

async def还是def?

编写路径操作函数时,fastapi对这两种写法都能接受,如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from fastapi import FastAPI

app = FastAPI()

@app.get("/async-def")
async def p1():
    return {"message": "Hello World from async def"}

@app.get("/def")
def p2():
    return {"message": "Hello World from def"}
  • 前者在协程中执行
  • 后者使用多线程方式执行

如果里面有阻塞或耗时操作,比如time.sleep(),需要使用普通的def进行定义。不然会阻塞其他路径操作:

1
2
3
4
@app.get("/def")
def p2():
    time.sleep(5)
    return {"message": "Hello World from def"}

其他场景下应该用应该用async def。特别是内部需要用await的,只能用async def

路径操作装饰符

路径操作装饰符,对应HTTP中的methods:

常用:

  • @app.get()
  • @app.post()
  • @app.put()
  • @app.delete()

以及

  • @app.options()
  • @app.head()
  • @app.patch()
  • @app.trace()

构建API时,通常使用特定的HTTP method执行特定的动作:

  • POST:创建数据
  • GET:读取数据
  • PUT:更新数据
  • DELETE:删除数据

参考

  • https://fastapi.tiangolo.com
  • https://asgi.readthedocs.io/en/latest/introduction.html
  • https://www.starlette.io
  • https://docs.pydantic.dev/latest/

Python web