Skip to content

Commit 676b924

Browse files
Add FastAPIModule routes_url and openapi_url parameters (#148)
1 parent 6af3c0c commit 676b924

File tree

2 files changed

+83
-1
lines changed

2 files changed

+83
-1
lines changed

src/fps/web/fastapi.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from __future__ import annotations
22

33
from fastapi import FastAPI
4+
from fastapi.routing import APIRoute, APIWebSocketRoute
5+
from starlette import routing
46

57
from fps import Module
68

@@ -12,10 +14,38 @@ def __init__(
1214
*,
1315
app: FastAPI | None = None,
1416
debug: bool | None = None,
17+
routes_url: str | None = None,
18+
openapi_url: str | None = "/openapi.json",
1519
) -> None:
1620
super().__init__(name)
1721
debug = debug if debug is not None else __debug__
18-
self.app = app if app is not None else FastAPI(debug=debug)
22+
self.app = (
23+
app if app is not None else FastAPI(debug=debug, openapi_url=openapi_url)
24+
)
25+
self.routes_url = routes_url
1926

2027
async def prepare(self) -> None:
2128
self.put(self.app)
29+
30+
async def start(self) -> None:
31+
if self.routes_url is not None:
32+
routes = []
33+
name: str | None
34+
for route in self.app.routes:
35+
if isinstance(route, APIWebSocketRoute):
36+
path = route.path
37+
name = route.name
38+
methods = ["WEBSOCKET"]
39+
elif isinstance(route, routing.Mount):
40+
path = route.path
41+
name = route.name
42+
methods = ["MOUNT"]
43+
elif isinstance(route, APIRoute):
44+
path = route.path
45+
name = route.name
46+
methods = list(route.methods)
47+
routes.append({"path": path, "name": name, "methods": methods})
48+
49+
@self.app.get(self.routes_url)
50+
async def get_routes():
51+
return routes

tests/test_web.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import httpx
44
from fastapi import FastAPI
5+
from fastapi.staticfiles import StaticFiles
56

67
from fps import Module
78
from fps.web.fastapi import FastAPIModule
@@ -31,3 +32,54 @@ def __init__(self, name):
3132
response = await client.get(f"http://127.0.0.1:{unused_tcp_port}")
3233

3334
assert response.json() == {"Hello": "World"}
35+
36+
37+
async def test_routes(unused_tcp_port):
38+
class Submodule0(Module):
39+
async def prepare(self):
40+
app = await self.get(FastAPI)
41+
42+
@app.get("/get")
43+
def get(): ...
44+
45+
@app.websocket("/websocket")
46+
def websocket(): ...
47+
48+
app.mount("/static", StaticFiles(directory="."), name="static")
49+
50+
class Module0(Module):
51+
def __init__(self, name):
52+
super().__init__(name)
53+
self.add_module(
54+
FastAPIModule, "fastapi_module", openapi_url=None, routes_url="/routes"
55+
)
56+
self.add_module(ServerModule, "server_module", port=unused_tcp_port)
57+
self.add_module(Submodule0, "submodule0")
58+
59+
async with Module0("module0"):
60+
async with httpx.AsyncClient() as client:
61+
response = await client.get(f"http://127.0.0.1:{unused_tcp_port}/routes")
62+
63+
assert response.json() == [
64+
{
65+
"methods": [
66+
"GET",
67+
],
68+
"name": "get",
69+
"path": "/get",
70+
},
71+
{
72+
"methods": [
73+
"WEBSOCKET",
74+
],
75+
"name": "websocket",
76+
"path": "/websocket",
77+
},
78+
{
79+
"methods": [
80+
"MOUNT",
81+
],
82+
"name": "static",
83+
"path": "/static",
84+
},
85+
]

0 commit comments

Comments
 (0)