Created
March 2, 2023 22:33
-
-
Save vskrachkov/53b9d31172f58bd1991a2752c2ec187b to your computer and use it in GitHub Desktop.
Generate OpenAPI Schema based on dictionary structure
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
import re | |
from typing import Tuple | |
def dict_to_openapi(d: dict) -> dict: | |
result = {} | |
for k, v in d.items(): | |
if isinstance(v, dict): | |
result[k] = dict(type="object", properties=dict_to_openapi(v)) | |
if isinstance(v, list): | |
if re.match(r"^[a-zA-Z]+\w+$", k) and v and isinstance(v[0], dict): | |
result[k] = dict( | |
type="array", | |
items=dict(type="object", properties=dict_to_openapi(v[0])), | |
) | |
else: | |
result[k] = dict(type="array", example=v) | |
if isinstance(v, str): | |
result[k] = dict(type="string") | |
if isinstance(v, int): | |
result[k] = dict(type="integer") | |
if isinstance(v, float): | |
result[k] = dict(type="number") | |
if isinstance(v, bool): | |
result[k] = dict(type="boolean") | |
return result | |
def setup_ref(d: dict) -> dict: | |
result = {} | |
result.update(d) | |
for k, v in d.items(): | |
if isinstance(v, dict) and v.get("type") == "object" and (properties := v.get("properties")): | |
parse_properties(result, k, properties) | |
return result | |
def parse_properties(result, k, properties): | |
for pk, pv in properties.items(): | |
if pv.get("type") == "object" and re.match(r"^[a-zA-Z]+\w+$", pk): # real object | |
ref_key, ref_val = ref(pk) | |
result[k]["properties"][pk] = {"$ref": ref_val} | |
result[ref_key] = pv | |
elif pv.get("type") == "object": # dictionary | |
ref_key, ref_val = ref(f"{k}_item") | |
result[k]["additionalProperties"] = {"$ref": ref_val} | |
if result[k].get("properties"): | |
del result[k]["properties"] | |
result[ref_key] = pv | |
def ref(name: str) -> Tuple[str, str]: | |
return name, f"#/components/schemas/{name}" | |
def process_schema(d: dict, depth: int = 10) -> dict: | |
result = {} | |
result.update(d) | |
previous_dict_items_count = 0 | |
current_dict_items_count = len(result.items()) | |
while previous_dict_items_count != current_dict_items_count: | |
previous_dict_items_count = len(result.items()) | |
result = setup_ref(result) | |
current_dict_items_count = len(result.items()) | |
return result | |
sample_dict = {} | |
def main(): | |
result = dict_to_openapi(sample_dict) | |
result = process_schema(result) | |
print(json.dumps(result)) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment