1import json
2import sys
3
4import click
5import requests
6
7from plain.cli import register_cli
8from plain.runtime import settings
9from plain.utils.module_loading import import_string
10
11from .openapi.generator import OpenAPISchemaGenerator
12
13
14@register_cli("api")
15@click.group()
16def cli() -> None:
17 """API commands"""
18
19
20@cli.command()
21@click.option("--validate", is_flag=True, help="Validate the OpenAPI schema.")
22@click.option("--indent", default=2, help="Indentation level for JSON and YAML output.")
23@click.option(
24 "--format",
25 default="json",
26 help="Output format (json or yaml).",
27 type=click.Choice(["json", "yaml"]),
28)
29def generate_openapi(validate: bool, indent: int, format: str) -> None:
30 if not settings.API_OPENAPI_ROUTER:
31 click.secho("No OpenAPI URL router configured.", fg="red", err=True)
32 sys.exit(1)
33
34 url_router_class = import_string(settings.API_OPENAPI_ROUTER)
35
36 schema = OpenAPISchemaGenerator(url_router_class)
37
38 if format == "json":
39 print(schema.as_json(indent=indent))
40 elif format == "yaml":
41 print(schema.as_yaml(indent=indent))
42
43 if validate:
44 click.secho("\nOpenAPI schema validation: ", err=True, nl=False)
45 response = requests.post(
46 "https://validator.swagger.io/validator/debug",
47 headers={"Content-Type": "application/json"},
48 json=schema.schema,
49 )
50 response.raise_for_status()
51 failed = response.json().get(
52 "schemaValidationMessages", []
53 ) or response.json().get("messages", [])
54 if failed:
55 click.secho("Failed", fg="red", err=True)
56 click.secho(
57 json.dumps(response.json(), indent=2, sort_keys=True),
58 fg="yellow",
59 err=True,
60 )
61 sys.exit(1)
62 else:
63 click.secho("Success", fg="green", err=True)