Reputation: 88619
Suppose I have a FastAPI project that contains 100+ API endpoints. How can I list all APIs/paths?
Upvotes: 19
Views: 27693
Reputation: 1
Following the answer from @olegsv, this would be a solution:
import requests
url = 'http://127.0.0.1:8000/' # local
response = requests.get(url+'openapi.json')
loaded_endpoints = list(response.json()['paths'].keys())
Upvotes: 0
Reputation: 1462
You can open /docs
URI to get all URLs documented in OpenAPI (swagger) format.
Parsing URLs should be trivial.
On localhost: http://localhost:8000/docs
Upvotes: 0
Reputation: 507
The accepted answer works great when you have just one app, but unfortunately, in our project we have a number of submounted ones which makes things a bit trickier in terms of traversal.
app.mount("/admin", admin_app)
...
We also have a lot of routes and their unqualified names can be the same even within one app, let alone different ones. So I wanted to get an overview of all the routes and their matching functions.
That's how I approached it, hope it will be helpful to others. :)
Great framework, but really miss django-extensions which had that covered, too bad there's nothing of the sort in fastapi land. Please correct me if I'm wrong!
from __future__ import annotations
from typing import Iterable
from app.main import app
from fastapi import FastAPI
from starlette.routing import Mount
def gen_routes(app: FastAPI | Mount) -> Iterable[tuple[str, str]]:
for route in app.routes:
if isinstance(route, Mount):
yield from (
(f"{route.path}{path}", name) for path, name in gen_routes(route)
)
else:
yield (
route.path,
"{}.{}".format(route.endpoint.__module__, route.endpoint.__qualname__),
)
def list_routes(app: FastAPI) -> None:
import tabulate
routes = sorted(set(gen_routes(app))) # also readable enough
print(tabulate.tabulate(routes, headers=["path", "full name"]))
if __name__ == "__main__":
list_routes(app)
Upvotes: 1
Reputation: 88619
To get all possible URL patterns, we need to get access to the defined URL routes which is an attribute of running app instance.
We can do that in at least two ways,
FastAPI
app: This is handy when you have access to the FastAPi instanceRequest
instance: This is handy when you have access to the incoming requests, but not to the FastAPI instance.from fastapi import FastAPI, Request
app = FastAPI()
@app.get(path="/", name="API Foo")
def foo():
return {"message": "this is API Foo"}
@app.post(path="/bar", name="API Bar")
def bar():
return {"message": "this is API Bar"}
# Using FastAPI instance
@app.get("/url-list")
def get_all_urls():
url_list = [{"path": route.path, "name": route.name} for route in app.routes]
return url_list
# Using Request instance
@app.get("/url-list-from-request")
def get_all_urls_from_request(request: Request):
url_list = [
{"path": route.path, "name": route.name} for route in request.app.routes
]
return url_list
Upvotes: 36
Reputation: 361
I tried to provide an edit the original answer but wouldn't let me.
Another use case: Suppose you are not in the main app file and don't have access to app
in the namespace. In that case Starlette documentation says that we also have access to the app instance from the request as request.app
. For example if in the main file you only have the app instance and don't want to have any endpoints in the main file but all of them to be in separate routers.
from fastapi import FastAPI
# then let's import all the various routers we have
# please note that api is the name of our package
from api.routers import router_1, router_2, router_3, utils
app = FastAPI()
app.include_router(router_1)
app.include_router(router_2)
app.include_router(router_3)
app.include_router(utils)
I have my list_endpoints endpoint in the utils router. To be able to list all of the app routes, I would do the following:
utils.pyfrom fastapi import APIRouter, Request
router = APIRouter(
prefix="/utils",
tags=["utilities"]
)
@router.get('/list_endpoints/')
def list_endpoints(request: Request):
url_list = [
{'path': route.path, 'name': route.name}
for route in request.app.routes
]
return url_list
Note that rather than using app.routes
I used request.app.routes
and I have access to all of them. If you now access /utils/list_endpoints
you will get all your routes.
Upvotes: 10