Python 如何在单独的文件中为端点/路由使用FastAPI?

Python 如何在单独的文件中为端点/路由使用FastAPI?,python,dependency-injection,websocket,web-frameworks,fastapi,Python,Dependency Injection,Websocket,Web Frameworks,Fastapi,我在单独的文件中定义了一个Websocket端点,如: 从starlette.endpoints导入WebSocketEndpoint 从连接\服务导入连接服务 WSEndpoint类(WebSocketEndpoint): “”“处理Websocket连接”“” _connect上的异步定义(自, websocket:websocket, connectionService:connectionService=Dependes(connectionService)): “”“处理新连接”“”

我在单独的文件中定义了一个Websocket端点,如:

从starlette.endpoints导入WebSocketEndpoint
从连接\服务导入连接服务
WSEndpoint类(WebSocketEndpoint):
“”“处理Websocket连接”“”
_connect上的异步定义(自,
websocket:websocket,
connectionService:connectionService=Dependes(connectionService)):
“”“处理新连接”“”
self.connectionService=connectionService
...
main.py
中,我将端点注册为:

从fastapi导入fastapi
从starlette.routing导入WebSocketRoute
从ws_端点导入WSEndpoint
app=FastAPI(routes=[WebSocketRoute(“/ws”,WSEndpoint)])
但是,
依赖于
,因为我的端点永远不会被解析。有没有办法让它发挥作用

另外,FastAPI中这种机制的目的是什么?我们不能只使用局部/全局变量吗?

TL;博士 这些文档似乎暗示您只能对请求函数使用
dependens

解释 我在FastAPI repo中发现了一个相关的问题,似乎
依赖(…)
只适用于请求,而不适用于其他任何东西

我通过,

from fastapi import Depends, FastAPI

app = FastAPI()


async def foo_func():
    return "This is from foo"


async def test_depends(foo: str = Depends(foo_func)):
    return foo


@app.get("/")
async def read_items():
    depends_result = await test_depends()
    return depends_result
在这种情况下,依赖关系没有得到解决


在你的案例中,你可以像这样解决依赖关系

from starlette.endpoints import WebSocketEndpoint
from connection_service import ConnectionService


class WSEndpoint(WebSocketEndpoint):
    async def on_connect(
            self,
            websocket: WebSocket,
            connectionService=None
    ):
        if connectionService is None:
            connectionService = ConnectionService()  # calling the depend function

        self.connectionService = connectionService
从starlette.endpoints导入WebSocketEndpoint
从连接\服务导入连接服务
WSEndpoint类(WebSocketEndpoint):
_connect上的异步定义(
自己
websocket:websocket,
connectionService=None
):
如果connectionService为无:
connectionService=connectionService()#调用depend函数

self.connectionService=connectionService
经过数小时的学习,在FastAPI中使用依赖注入和路由/端点,我发现了以下内容

路由与端点 首先,我想指出,
Endpoint
是一个存在于Starlette中的概念,而FastAPI中没有。在我的问题中,我展示了使用
WebSocketEndpoint
类的代码,依赖注入在FastAPI中不起作用。进一步阅读以了解原因

依赖注入(DI) FastAPI中的DI并不是我们所知道的经典模式,它并不能神奇地解决所有地方的依赖关系

dependens
仅针对FastAPI路由进行解析,这意味着使用方法:
add\u-api\u-route
add\u-api\u-websocket\u-route
,或者它们的装饰器类似物:
api\u-route
websocket
,它们只是前两个的包装

然后,当请求通过FastAPI到达路由时,依赖关系将得到解决。这对于理解FastAPI是在解析依赖项而不是Starlette是很重要的。FastAPI构建在Starlette之上,您可能还想使用一些“原始”Starlette功能,例如:
add\u route
add\u websocket\u route
,但是您将没有这些功能的
分辨率

另外,FastAPI中的DI可以用于解析类的实例,但这不是它的主要用途,而且在Python中没有任何意义,因为您只需使用闭包。当您需要某种类型的请求验证时(Django使用decorators完成的工作),就会出现
依赖的情况。在这种用法中,
dependens
非常有用,因为它可以解析
route
依赖项和那些子依赖项。查看下面的我的代码,我使用
auth\u Check

代码示例 作为奖励,我希望将websocket路由作为一个类放在单独的文件中,并使用用于连接、断开连接和接收的单独方法。另外,我希望在单独的文件中进行身份验证检查,以便能够轻松地将其交换

#main.py
从fastapi导入fastapi
从ws_路由导入WSRoute
app=FastAPI()
app.add_api_websocket_route(“/ws”,WSRoute)
#auth.py
从fastapi导入WebSocket
def身份验证检查(websocket:websocket):
#`websocket`实例将自动解析
#还有其他“视情况而定”。它们是所谓的子依赖项。
#在此处实现您的身份验证逻辑:
#解析标题或查询参数(这通常是WebSocket的一种方式)
#并进行验证
返回真值
#ws_route.py
导入键入
将starlette.status导入为status
从fastapi导入WebSocket,WebSocketDisconnect,取决于
从身份验证导入身份验证检查
等级WSRoute:
定义初始化(自我,
websocket:websocket,
是否经过身份验证:bool=Depends(身份验证检查)):
self.\u websocket=websocket
定义等待(自我)->键入。生成器:
返回self.dispatch()
异步def调度(自)->无:
#Websocket生命周期
等待自我。_on_connect()
关闭代码:int=status.WS\u 1000\u正常\u关闭
尝试:
尽管如此:
数据=等待自我。\u websocket.receive\u text()
等待自我。接收(数据)
除WebSocketDisconnect外:
#在这里处理客户端正常断开连接
通过
除作为exc的例外情况外:
#在这里处理其他类型的错误
关闭\u代码=status.WS\u 1011\u内部\u错误
将exc从零提高到零
最后:
等待自我。断开连接(关闭代码)
异步定义连接(自):
#在这里处理您的新连接
等待自我。_websocket.accept()
通过
异步定义打开断开(自身、关闭代码:int):
#在这里处理客户端断开连接
通过
接收时异步定义(self,msg:typing.Any):
#在这里处理客户端消息
通过

我也面临同样的问题。依赖项/查询不起作用。我停止使用网络
# @app.websocket("/ws/hello/token")
async def websocket_hello_endpoint_with_token(websocket: WebSocket, client_id: str = Query(..., alias="token")):
    #on_connect
    await websocket.accept()
    try:
        while True:
            data = await websocket.receive_text()
             #on_receive
            await websocket.send_text(f"Token: {client_id}  & Message text was: {data}")
    except WebSocketDisconnect:
        #on_disconnect
        pass
app = FastAPI()
app.add_api_websocket_route("/ws/hello/token", socket.websocket_hello_endpoint_with_token)
<!DOCTYPE html>
<html>
    <head>
        <title>Chat</title>
    </head>
    <body>
        <h1>WebSocket Chat</h1>
        <form action="" onsubmit="sendMessage(event)">
            <label>Token: <input type="text" id="token" autocomplete="off" value="some-key-token"/></label>
            <button onclick="connect(event)">Connect</button>
            <hr>
            <label>Message: <input type="text" id="messageText" autocomplete="off"/></label>
            <button>Send</button>
        </form>
        <ul id='messages'>
        </ul>
        <script>
        var ws = null;
            function connect(event) {
                var token = document.getElementById("token")
                ws = new WebSocket("ws://localhost:6003/ws/hello/token?token=" + token.value);
                
                ws.onopen = function () {
                  console.log('socket opened'); 
                };
                ws.onmessage = function(event) {
                    var messages = document.getElementById('messages')
                    var message = document.createElement('li')
                    var content = document.createTextNode(event.data)
                    <!-- var data = document.createTextNode(event.data) -->
                    <!-- var content = "message:" + data.message -->
                    message.appendChild(content)
                    messages.appendChild(message)
                };
                
                ws.onclose = function(e) {  
                  console.log('socket closed from server'); 
                }

                ws.onerror = function(err) {
                  console.error(err)
                };
                
                event.preventDefault()
            }
            function sendMessage(event) {
                var input = document.getElementById("messageText")
                ws.send(input.value)
                input.value = ''
                event.preventDefault()
            }
        </script>
    </body>
</html>