Skip to content

Commit e679e02

Browse files
committed
Added CLI to construct an OpenAPI schema of either the instrument server or backend server and save it as either a JSON or YAML file
1 parent 9f0c46a commit e679e02

File tree

1 file changed

+116
-0
lines changed

1 file changed

+116
-0
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import contextlib
2+
import io
3+
import json
4+
from argparse import ArgumentParser
5+
from pathlib import Path
6+
7+
import yaml
8+
from fastapi.openapi.utils import get_openapi
9+
10+
import murfey
11+
from murfey.cli import LineWrapHelpFormatter, PrettierDumper
12+
13+
14+
def run():
15+
# Set up argument parser
16+
parser = ArgumentParser(
17+
description=(
18+
"Generates an OpenAPI schema of the chosen FastAPI server "
19+
"and outputs it as either a JSON or YAML file"
20+
),
21+
formatter_class=LineWrapHelpFormatter,
22+
)
23+
parser.add_argument(
24+
"--target",
25+
"-t",
26+
default="server",
27+
help=(
28+
"The target FastAPI server to construct the OpenAPI schema for. \n"
29+
"OPTIONS: instrument-server | server \n"
30+
"DEFAULT: server"
31+
),
32+
)
33+
parser.add_argument(
34+
"--output",
35+
"-o",
36+
default="yaml",
37+
help=(
38+
"Set the output format of the OpenAPI schema. \n"
39+
"OPTIONS: json | yaml \n"
40+
"DEFAULT: yaml"
41+
),
42+
)
43+
parser.add_argument(
44+
"--to-file",
45+
"-f",
46+
default="",
47+
help=(
48+
"Alternative file path and file name to save the schema as. "
49+
"Can be a relative or absolute path"
50+
),
51+
)
52+
parser.add_argument(
53+
"--debug",
54+
action="store_true",
55+
default=False,
56+
help="Shows additional steps when setting ",
57+
)
58+
args = parser.parse_args()
59+
60+
# Load the relevant FastAPI app
61+
target = str(args.target).lower()
62+
if args.debug:
63+
print(f"Constructing OpenAPI schema for {target}")
64+
65+
# Silence output during import; only return genuine errors
66+
buffer = io.StringIO()
67+
with contextlib.redirect_stdout(buffer), contextlib.redirect_stderr(buffer):
68+
if target == "server":
69+
from murfey.server.main import app
70+
elif target == "instrument-server":
71+
from murfey.instrument_server.main import app
72+
else:
73+
raise ValueError(
74+
"Unexpected value for target server. It must be one of "
75+
"'instrument-server' or 'server'"
76+
)
77+
78+
output = str(args.output).lower()
79+
if not app.openapi_schema:
80+
schema = get_openapi(
81+
title=app.title,
82+
version=app.version,
83+
openapi_version=app.openapi_version,
84+
description=app.description,
85+
routes=app.routes,
86+
)
87+
else:
88+
schema = app.openapi_schema
89+
90+
murfey_dir = Path(murfey.__path__[0])
91+
save_path = (
92+
murfey_dir / "util" / f"openapi.{output}"
93+
if not args.to_file
94+
else Path(args.to_file)
95+
)
96+
with open(save_path, "w") as f:
97+
if output == "json":
98+
json.dump(schema, f, indent=2)
99+
elif output == "yaml":
100+
yaml.dump(
101+
schema,
102+
f,
103+
Dumper=PrettierDumper,
104+
default_flow_style=False,
105+
sort_keys=False,
106+
indent=2,
107+
)
108+
else:
109+
raise ValueError(
110+
"Invalid file format select. Output must be either 'json' or 'yaml'"
111+
)
112+
print(f"OpenAPI schema save to {save_path}")
113+
114+
115+
if __name__ == "__main__":
116+
run()

0 commit comments

Comments
 (0)