1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
from pathlib import Path
import msgspec
from click import Path as ClickPath
from click import group, option
from yaml import dump as dump_yaml
from litestar import Litestar
from litestar._openapi.typescript_converter.converter import (
convert_openapi_to_typescript,
)
from litestar.cli._utils import JSBEAUTIFIER_INSTALLED, LitestarCLIException, LitestarGroup
from litestar.serialization import encode_json, get_serializer
__all__ = ("generate_openapi_schema", "generate_typescript_specs", "schema_group")
@group(cls=LitestarGroup, name="schema")
def schema_group() -> None:
"""Manage server-side OpenAPI schemas."""
def _generate_openapi_schema(app: Litestar, output: Path) -> None:
"""Generate an OpenAPI Schema."""
serializer = get_serializer(app.type_encoders)
if output.suffix in (".yml", ".yaml"):
content = dump_yaml(
msgspec.to_builtins(app.openapi_schema.to_schema(), enc_hook=serializer),
default_flow_style=False,
encoding="utf-8",
)
else:
content = msgspec.json.format(
encode_json(app.openapi_schema.to_schema(), serializer=serializer),
indent=4,
)
try:
output.write_bytes(content)
except OSError as e: # pragma: no cover
raise LitestarCLIException(f"failed to write schema to path {output}") from e
@schema_group.command("openapi") # type: ignore[misc]
@option(
"--output",
help="output file path",
type=ClickPath(dir_okay=False, path_type=Path),
default=Path("openapi_schema.json"),
show_default=True,
)
def generate_openapi_schema(app: Litestar, output: Path) -> None:
"""Generate an OpenAPI Schema."""
_generate_openapi_schema(app, output)
@schema_group.command("typescript") # type: ignore[misc]
@option(
"--output",
help="output file path",
type=ClickPath(dir_okay=False, path_type=Path),
default=Path("api-specs.ts"),
show_default=True,
)
@option("--namespace", help="namespace to use for the typescript specs", type=str, default="API")
def generate_typescript_specs(app: Litestar, output: Path, namespace: str) -> None:
"""Generate TypeScript specs from the OpenAPI schema."""
if JSBEAUTIFIER_INSTALLED: # pragma: no cover
from jsbeautifier import Beautifier
beautifier = Beautifier()
else:
beautifier = None
try:
specs = convert_openapi_to_typescript(app.openapi_schema, namespace)
# beautifier will be defined if JSBEAUTIFIER_INSTALLED is True
specs_output = (
beautifier.beautify(specs.write()) if JSBEAUTIFIER_INSTALLED and beautifier else specs.write() # pyright: ignore
)
output.write_text(specs_output)
except OSError as e: # pragma: no cover
raise LitestarCLIException(f"failed to write schema to path {output}") from e
|