74 lines
2.3 KiB
Python
74 lines
2.3 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import json
|
||
|
|
from collections import defaultdict
|
||
|
|
from datetime import UTC, datetime
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
from app.main import create_app
|
||
|
|
|
||
|
|
SERVER_DIR = Path(__file__).resolve().parents[1]
|
||
|
|
ROOT_DIR = SERVER_DIR.parent
|
||
|
|
OUTPUT_DIR = ROOT_DIR / "document" / "development" / "backend_api"
|
||
|
|
OPENAPI_PATH = OUTPUT_DIR / "openapi.json"
|
||
|
|
INVENTORY_PATH = OUTPUT_DIR / "interface_inventory.md"
|
||
|
|
|
||
|
|
|
||
|
|
def build_inventory(schema: dict[str, object]) -> str:
|
||
|
|
paths = schema.get("paths", {})
|
||
|
|
tag_groups: dict[str, list[tuple[str, str, str]]] = defaultdict(list)
|
||
|
|
|
||
|
|
for path, operations in sorted(paths.items()):
|
||
|
|
if not isinstance(operations, dict):
|
||
|
|
continue
|
||
|
|
for method, operation in sorted(operations.items()):
|
||
|
|
if not isinstance(operation, dict):
|
||
|
|
continue
|
||
|
|
summary = str(operation.get("summary") or operation.get("operationId") or "-")
|
||
|
|
tags = operation.get("tags") or ["untagged"]
|
||
|
|
primary_tag = str(tags[0])
|
||
|
|
tag_groups[primary_tag].append((method.upper(), str(path), summary))
|
||
|
|
|
||
|
|
generated_at = datetime.now(UTC).strftime("%Y-%m-%d %H:%M:%S UTC")
|
||
|
|
lines = [
|
||
|
|
"# Backend API Interface Inventory",
|
||
|
|
"",
|
||
|
|
f"- Generated at: `{generated_at}`",
|
||
|
|
f"- API title: `{schema['info']['title']}`",
|
||
|
|
f"- API version: `{schema['info']['version']}`",
|
||
|
|
f"- Total paths: `{len(paths)}`",
|
||
|
|
"",
|
||
|
|
"## Tag Overview",
|
||
|
|
"",
|
||
|
|
]
|
||
|
|
|
||
|
|
for tag_name in sorted(tag_groups):
|
||
|
|
lines.append(f"### {tag_name}")
|
||
|
|
lines.append("")
|
||
|
|
lines.append("| Method | Path | Summary |")
|
||
|
|
lines.append("| --- | --- | --- |")
|
||
|
|
for method, path, summary in tag_groups[tag_name]:
|
||
|
|
lines.append(f"| `{method}` | `{path}` | {summary} |")
|
||
|
|
lines.append("")
|
||
|
|
|
||
|
|
return "\n".join(lines).strip() + "\n"
|
||
|
|
|
||
|
|
|
||
|
|
def main() -> None:
|
||
|
|
app = create_app()
|
||
|
|
schema = app.openapi()
|
||
|
|
|
||
|
|
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||
|
|
OPENAPI_PATH.write_text(
|
||
|
|
json.dumps(schema, ensure_ascii=False, indent=2),
|
||
|
|
encoding="utf-8",
|
||
|
|
)
|
||
|
|
INVENTORY_PATH.write_text(build_inventory(schema), encoding="utf-8")
|
||
|
|
|
||
|
|
print(f"OpenAPI exported to: {OPENAPI_PATH}")
|
||
|
|
print(f"Interface inventory exported to: {INVENTORY_PATH}")
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|