Search code examples
pythonswagger-uiopenapifastapi

FastAPI swaggerUI shows nested routes twice


I have a configuration like this in the routes/__init__.py

## api/routes/__init__.py
router = APIRouter()
router.include_router(models_router, prefix="/models", tags=["models"])
...

And here is the main.py that includes them.

## main.py
from api.routes import router as api_router
def get_app():
    app = FastAPI()
    app.include_router(api_router, prefix = "/api")
    ...

app = get_app() 

Now inside the models router I have two more nested routes like this:

## api/routes/models.py
router.include_router(
    fields_router, 
    prefix="/{model_id}/fields", 
    tags=["fields"],
    dependencies=[Depends(pre_model_validation)]
)
router.include_router(
    model_data_router, 
    prefix="/{model_id}/data", 
    tags=["model_data"],
    dependencies=[Depends(pre_model_validation)]
)

While this works, when I open the localhost and use the generated SwaggerUI docs, it shows something like this

swagger ui docs:

The nested endpoints are also appearing from inside the /models API as well as from their separate /fields and /model_data APIs. How do I isolate the nested routes in a way that they appear as separate API in swagger docs but stay defined inside the /models API?


Solution

  • If I understand correctly you want all endpoints to be under the root path /api/models/ but want the Swagger docs to just show them only once, under the respective 'fields' or 'model_data' tags, while keeping the following under the 'models' tag:

    • Get Models For Site
    • Create Models
    • Update Content Type

    If the above is correct, instead of nesting the imports, you might want to split them using the same root path as needed, as follows:

    # api/routes/__init__.py
    router = APIRouter()
    
    router.include_router(
        models_router, 
        prefix="/models", 
        tags=["models"]
    )
    
    router.include_router(
        fields_router, 
        prefix="/models/{model_id}/fields", 
        tags=["fields"]
    )
    
    router.include_router(
        models_router, 
        prefix="/models/{model_id}/data", 
        tags=["model_data"]
    )