如何使用FastAPI合并多个独立服务的Swagger文档?
问题描述
我有两个运行在不同端口的FastAPI服务:
第一个服务代码(端口8000)
from fastapi import FastAPI app = FastAPI() @app.get("/test") async def root(): return {"message": "Hello World"} @app.get("/test/hello/{name}") async def say_hello(name: str): return {"message": f"Hello {name}"}
第二个服务代码(端口9000)
from fastapi import FastAPI app = FastAPI() @app.get("/") async def root(): return {"message": "Hello World"} @app.get("/hello/{name}") async def say_hello(name: str): return {"message": f"Hello {name}"}
Docker Compose配置
version: '3.9' services: first: build: context: ./first dockerfile: Dockerfile ports: - "8000:8000" second: build: context: ./second dockerfile: Dockerfile ports: - "9000:9000"
我需要一个可选择所需服务文档的端点(效果如下图所示):
请问如何将这些服务的Swagger文档合并到一个端点?FastAPI官方文档提到可自定义文档,但我不知如何实现合并。
解决方案
你可以通过创建一个网关服务实现需求,这个服务会提供自定义的Swagger UI页面,支持切换查看不同后端服务的API文档,具体步骤如下:
1. 创建网关服务
新建FastAPI项目作为统一文档入口,核心逻辑是自定义Swagger页面添加服务选择控件,动态加载对应服务的OpenAPI规范。
网关服务核心代码
from fastapi import FastAPI, Request from fastapi.openapi.docs import get_swagger_ui_html import httpx app = FastAPI(docs_url=None, redoc_url=None) # 定义后端服务列表 SERVICES = { "First Service (8000)": "http://first:8000/openapi.json", "Second Service (9000)": "http://second:9000/openapi.json" } @app.get("/docs", include_in_schema=False) async def custom_swagger_ui_html(request: Request): # 生成基础Swagger UI页面 swagger_ui_html = get_swagger_ui_html( openapi_url="/openapi.json", title="API Gateway - Swagger UI", swagger_js_url="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js", swagger_css_url="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css", ) # 插入服务切换的前端逻辑 custom_js = """ <script> window.onload = function() { // 在顶部栏添加服务选择下拉框 const header = document.querySelector('.swagger-ui .topbar'); const selectContainer = document.createElement('div'); selectContainer.style.margin = '0 10px'; const select = document.createElement('select'); select.style.padding = '8px'; select.innerHTML = ` <option value="">选择服务</option> <option value="http://first:8000/openapi.json">First Service (8000)</option> <option value="http://second:9000/openapi.json">Second Service (9000)</option> `; select.onchange = function() { if (this.value) { window.ui.updateSpecUrl(this.value); } }; selectContainer.appendChild(select); header.appendChild(selectContainer); }; </script> """ # 将自定义代码插入页面末尾 return swagger_ui_html.replace('</body>', custom_js + '</body>') @app.get("/openapi.json", include_in_schema=False) async def get_openapi(request: Request): # 默认返回第一个服务的OpenAPI规范 async with httpx.AsyncClient() as client: response = await client.get(SERVICES["First Service (8000)"]) return response.json()
2. 更新Docker Compose配置
将网关服务加入配置,确保它能通过Docker内部网络访问两个后端服务:
version: '3.9' services: first: build: context: ./first dockerfile: Dockerfile ports: - "8000:8000" second: build: context: ./second dockerfile: Dockerfile ports: - "9000:9000" gateway: build: context: ./gateway dockerfile: Dockerfile ports: - "8080:8000" depends_on: - first - second
3. 网关服务的Dockerfile示例
FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
网关服务的requirements.txt:
fastapi>=0.100.0 uvicorn>=0.23.2 httpx>=0.24.1
4. 使用说明
启动所有服务后,访问http://localhost:8080/docs即可看到带有服务选择下拉框的Swagger UI页面。选择不同服务后,页面会自动加载对应服务的API文档,和你提供的示例图效果一致。
内容的提问来源于stack exchange,提问作者Vladislav
相关产品推荐
相关产品推荐

