FastAPI -- 第三弹(自定义响应、中间件、代理、WebSockets)

路径操作的高级配置

OpenAPI 的 operationId

python 复制代码
from fastapi import FastAPI

app = FastAPI()


# 通过 operation_id 参数设置
@app.get("/items/", operation_id="some_specific_id_you_define")
async def read_items():
    return [{"item_id": "Foo"}]

使用 路径操作函数 的函数名作为 operationId

python 复制代码
from fastapi import FastAPI
from fastapi.routing import APIRoute

app = FastAPI()


@app.get("/items/")
async def read_items():
    return [{"item_id": "Foo"}]


def use_route_names_as_operation_ids(app: FastAPI) -> None:
    """
    Simplify operation IDs so that generated API clients have simpler function
    names.

    Should be called only after all routes have been added.
    """
    for route in app.routes:
        if isinstance(route, APIRoute):
        	# 个人觉得这种操作挺不错,可以在一个地方统一处理,更有利于建立规范 且方便管理
            route.operation_id = route.name  # in this case, 'read_items'


use_route_names_as_operation_ids(app)

从 OpenAPI 中排除

python 复制代码
from fastapi import FastAPI

app = FastAPI()


# 使用 include_in_schema 参数并将其设置为 False,
# openapi 文档中就看不到这个接口的信息
# 
# 个人认为,可以作为是否完成的开关使用,默认设置 False,当接口完成开发后设置为 True
@app.get("/items/", include_in_schema=False)
async def read_items():
    return [{"item_id": "Foo"}]

docstring 的高级描述

python 复制代码
from typing import Set, Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None
    tags: Set[str] = set()


@app.post("/items/", response_model=Item, summary="Create an item")
async def create_item(item: Item):
    """
    Create an item with all the information:

    - **name**: each item must have a name
    - **description**: a long description
    - **price**: required
    - **tax**: if the item doesn't have tax, you can omit this
    - **tags**: a set of unique tag strings for this item
    
    > \\f : 换页 的转义字符 1 <br/>
    > 比较有意思的是,这里可以按照 Markdown 的语法写文档注释
    > Swagger UI 只支持一些简单的 Markdown 语法
    > 比如现在的 `>` Swagger UI就不支持,但是 ReDoc 支持
    > 但是比较遗憾的是 这两者对 Markdown 的语法支持的不够完善
    
    但是比较遗憾的是 这两者都不支持换行
    但是比较遗憾的是 这两者都不支持换行
    但是比较遗憾的是 这两者都不支持换行
    `\n` 和 `<br/>` 两者的换行还不一样
    对于 `>` 中的换行 要使用 `<br/>`, 不然会作为两段 引用,
    只能说对于 Markdown语法的支持两者都有提升空间啊
    
    \f
    \\f : 换页 的转义字符 2
    换页的内容,不会再 上面提到的两者中 进行展示
    比较有意思的是,这里可以按照 Markdown 的语法写文档注释
    然后在文档中就会按照 Markdown 的样式进行展示
    
    :param item: User input.
    """
    return item

自定义响应

使用 ORJSONResponse

如果你需要压榨性能,你可以安装并使用 orjson 并将响应设置为 ORJSONResponse

python 复制代码
from fastapi import FastAPI
from fastapi.responses import ORJSONResponse

app = FastAPI()


# 使用 ORJSONResponse 代替 JSONResponse
@app.get("/items/", response_class=ORJSONResponse)
async def read_items():
    return ORJSONResponse([{"item_id": "Foo"}])

StreamingResponse

如果您有类似文件的对象(例如,由 open() 返回的对象),则可以在 StreamingResponse 中将其返回

python 复制代码
from fastapi import FastAPI
from fastapi.responses import StreamingResponse

some_file_path = "large-video-file.mp4"
app = FastAPI()


@app.get("/")
def main():
    def iterfile():  # (1)
        with open(some_file_path, mode="rb") as file_like:  # (2)
            yield from file_like  # (3)

	# 使用 StreamingResponse 返回数据
    return StreamingResponse(iterfile(), media_type="video/mp4")

FileResponse

异步传输文件作为响应。

python 复制代码
from fastapi import FastAPI
from fastapi.responses import FileResponse

some_file_path = "large-video-file.mp4"
app = FastAPI()


@app.get("/")
async def main():
    return FileResponse(some_file_path)

响应 Cookies

使用 Response 参数

pythonfrom 复制代码
app = FastAPI()


@app.post("/cookie-and-object/")
def create_cookie(response: Response):
	
	# 定义一个 response: Response 的参数
	# 调用 set_cookie
    response.set_cookie(key="fakesession", value="fake-cookie-session-value")
    return {"message": "Come to the dark side, we have cookies"}

直接响应 Response

python 复制代码
from fastapi import FastAPI
from fastapi.responses import JSONResponse

app = FastAPI()


@app.post("/cookie/")
def create_cookie():
    content = {"message": "Come to the dark side, we have cookies"}

	# 创建一个 Response 或其子类 对象
    response = JSONResponse(content=content)

	# 调用 set_cookie
    response.set_cookie(key="fakesession", value="fake-cookie-session-value")
    return response

响应头

和 响应Cookies 类似也有两种方式

使用 Response 参数

python 复制代码
from fastapi import FastAPI, Response

app = FastAPI()


@app.get("/headers-and-object/")
def get_headers(response: Response):
	
	# 声明一个 Response 类的形参
	# 像字典添加 键值对 一样,往 headers中添加键值对
    response.headers["X-Cat-Dog"] = "alone in the world"
    return {"message": "Hello World"}

直接返回 Response

python 复制代码
from fastapi import FastAPI
from fastapi.responses import JSONResponse

app = FastAPI()


@app.get("/headers/")
def get_headers():
    content = {"message": "Hello World"}

	# 将要返回的响应头信息先存到字典中 header_dict 
    header_dict = {"X-Cat-Dog": "alone in the world", "Content-Language": "en-US"}

	# 通过 kv 形式设置 headers, headers=header_dict 
    return JSONResponse(content=content, headers=header_dict )

直接使用请求

python 复制代码
from fastapi import FastAPI, Request

app = FastAPI()


@app.get("/items/{item_id}")
def read_root(item_id: str, request: Request):

	# 声明一个形参 request: Request
	# 可以从 request 中得到请求信息
    client_host = request.client.host
    return {"client_host": client_host, "item_id": item_id}

添加 ASGI 中间件

python 复制代码
from fastapi import FastAPI
from unicorn import UnicornMiddleware

app = FastAPI()

# 通过 FastAPI 的实例 app 调用 add_middleware 方法添加中间件 
app.add_middleware(UnicornMiddleware, some_config="rainbow")

使用代理

在 FastAPI 应用里设置 root_path

python 复制代码
from fastapi import FastAPI, Request

# 将 "/api/v1" 赋值给 root_path
app = FastAPI(root_path="/api/v1")


@app.get("/app")
def read_main(request: Request):
    return {"message": "Hello World", "root_path": request.scope.get("root_path")}

附加的服务器(多环境部署时)

python 复制代码
from fastapi import FastAPI, Request

# 可以通过 servers,将多个环境的地址以列表的形式赋值给 servers
app = FastAPI(
    servers=[
        {"url": "https://stag.example.com", "description": "Staging environment"},
        {"url": "https://prod.example.com", "description": "Production environment"},
    ],
    root_path="/api/v1",
    
    # 将 root_path 从 servers 剔除,root_path_in_servers=False
    # 默认 servers 会包含 root_path, root_path_in_servers=True
    # root_path_in_servers=False,
)


@app.get("/app")
def read_main(request: Request):
    return {"message": "Hello World", "root_path": request.scope.get("root_path")}

WebSockets

安装 WebSockets

pip install websockets

创建 websocket

python 复制代码
from fastapi import FastAPI, WebSocket
from fastapi.responses import HTMLResponse

app = FastAPI()

html = """
<!DOCTYPE html>
<html>
    <head>
        <title>Chat</title>
    </head>
    <body>
        <h1>WebSocket Chat</h1>
        <form action="" οnsubmit="sendMessage(event)">
            <input type="text" id="messageText" autocomplete="off"/>
            <button>Send</button>
        </form>
        <ul id='messages'>
        </ul>
        <script>
            var ws = new WebSocket("ws://localhost:8000/ws");
            ws.onmessage = function(event) {
                var messages = document.getElementById('messages')
                var message = document.createElement('li')
                var content = document.createTextNode(event.data)
                message.appendChild(content)
                messages.appendChild(message)
            };
            function sendMessage(event) {
                var input = document.getElementById("messageText")
                ws.send(input.value)
                input.value = ''
                event.preventDefault()
            }
        </script>
    </body>
</html>
"""


@app.get("/")
async def get():
    return HTMLResponse(html)


# 通过 app.websocket 创建一个 websocket 
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):

	# 接收消息
    await websocket.accept()
    while True:
        data = await websocket.receive_text()
		
		# 发送消息
        await websocket.send_text(f"Message text was: {data}")

事件:启动 - 关闭

startup 事件

python 复制代码
from fastapi import FastAPI

app = FastAPI()

items = {}


# 通过 app.on_event("startup") "声明"一个函数为启动函数
# 可以做一些预处理工作,比如 往数据库中写入一些初始数据
@app.on_event("startup")
async def startup_event():
    items["foo"] = {"name": "Fighters"}
    items["bar"] = {"name": "Tenders"}


@app.get("/items/{item_id}")
async def read_items(item_id: str):
    return items[item_id]

shutdown 事件

python 复制代码
from fastapi import FastAPI

app = FastAPI()



# 通过 app.on_event("shutdown") "声明"一个函数为关闭函数
@app.on_event("shutdown")
def shutdown_event():
    with open("log.txt", mode="a") as log:
        log.write("Application shutdown")


@app.get("/items/")
async def read_items():
    return [{"name": "Foo"}]

到此结  DragonFangQy 2024.07.18

相关推荐
苹果酱056711 小时前
windows安装redis, 修改自启动的redis服务的密码
java·开发语言·spring boot·mysql·中间件
陈健平15 小时前
2024最新YT-DLP使用demo网页端渲染
python·fastapi·jinja2·yt-dlp·yt_dlp
苹果酱056719 小时前
4-SpringCloud整合服务间的调用即负载均衡
java·开发语言·spring boot·mysql·中间件
永乐春秋1 天前
WEB攻防-通用漏洞&文件上传&中间件解析漏洞&编辑器安全
安全·中间件
hxj..1 天前
【中间件】Redis
数据库·redis·缓存·中间件
九河云1 天前
分布式数据库中间件可以用在哪些场景呢
数据库·分布式·中间件·华为云
股票GPT分析1 天前
《Python 股票交易分析:开启智能投资新时代》(二)
大数据·服务器·python·c#·fastapi
股票GPT分析2 天前
《Python 股票交易分析:开启智能投资新时代》(一)
服务器·开发语言·python·fastapi
Clown952 天前
go-zero(八) 中间件的使用
开发语言·中间件·golang
苹果酱05672 天前
springcloud-网关路由gateway
java·开发语言·spring boot·mysql·中间件