mirror of
https://github.com/langgenius/dify.git
synced 2026-05-10 14:14:17 +08:00
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: WH-2099 <wh2099@pm.me>
96 lines
2.6 KiB
Python
96 lines
2.6 KiB
Python
"""Generate FastOpenAPI OpenAPI 3.0 specs without booting the full backend."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import logging
|
|
import sys
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
|
|
API_ROOT = Path(__file__).resolve().parents[1]
|
|
if str(API_ROOT) not in sys.path:
|
|
sys.path.insert(0, str(API_ROOT))
|
|
|
|
from dev.generate_swagger_specs import apply_runtime_defaults, drop_null_values, sort_openapi_arrays
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class FastOpenApiSpecTarget:
|
|
route: str
|
|
filename: str
|
|
|
|
|
|
FASTOPENAPI_SPEC_TARGETS: tuple[FastOpenApiSpecTarget, ...] = (
|
|
FastOpenApiSpecTarget(route="/fastopenapi/openapi.json", filename="fastopenapi-console-openapi.json"),
|
|
)
|
|
|
|
|
|
def create_fastopenapi_spec_app():
|
|
"""Build a minimal Flask app that only mounts FastOpenAPI docs routes."""
|
|
|
|
apply_runtime_defaults()
|
|
|
|
from app_factory import create_flask_app_with_configs
|
|
from extensions import ext_fastopenapi
|
|
|
|
app = create_flask_app_with_configs()
|
|
ext_fastopenapi.init_app(app)
|
|
return app
|
|
|
|
|
|
def generate_fastopenapi_specs(output_dir: Path) -> list[Path]:
|
|
"""Write FastOpenAPI specs to `output_dir` and return the written paths."""
|
|
|
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
app = create_fastopenapi_spec_app()
|
|
client = app.test_client()
|
|
|
|
written_paths: list[Path] = []
|
|
for target in FASTOPENAPI_SPEC_TARGETS:
|
|
response = client.get(target.route)
|
|
if response.status_code != 200:
|
|
raise RuntimeError(f"failed to fetch {target.route}: {response.status_code}")
|
|
|
|
payload = response.get_json()
|
|
if not isinstance(payload, dict):
|
|
raise RuntimeError(f"unexpected response payload for {target.route}")
|
|
payload = drop_null_values(payload)
|
|
payload = sort_openapi_arrays(payload)
|
|
|
|
output_path = output_dir / target.filename
|
|
output_path.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
|
written_paths.append(output_path)
|
|
|
|
return written_paths
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument(
|
|
"-o",
|
|
"--output-dir",
|
|
type=Path,
|
|
default=Path("openapi"),
|
|
help="Directory where the OpenAPI JSON files will be written.",
|
|
)
|
|
return parser.parse_args()
|
|
|
|
|
|
def main() -> int:
|
|
args = parse_args()
|
|
written_paths = generate_fastopenapi_specs(args.output_dir)
|
|
|
|
for path in written_paths:
|
|
logger.debug(path)
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|