Skip to content

Instantly share code, notes, and snippets.

@vskrachkov
Created March 2, 2023 22:33
Show Gist options
  • Save vskrachkov/53b9d31172f58bd1991a2752c2ec187b to your computer and use it in GitHub Desktop.
Save vskrachkov/53b9d31172f58bd1991a2752c2ec187b to your computer and use it in GitHub Desktop.
Generate OpenAPI Schema based on dictionary structure
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