You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
161 lines
4.9 KiB
161 lines
4.9 KiB
# -*- coding: utf-8 -*-
|
|
import urllib
|
|
from typing import Any, List
|
|
|
|
VERBS = [
|
|
"add",
|
|
"create",
|
|
"delete",
|
|
"get",
|
|
"attach",
|
|
"detach",
|
|
"update",
|
|
"push",
|
|
"extendedcreate",
|
|
"activate",
|
|
]
|
|
|
|
|
|
# generate a name for the endpoint from the path template
|
|
# POST /api/v1/things/{id}/create -> POST create thing by id
|
|
def path_template_to_endpoint_name(method, path_template):
|
|
path_template = path_template.strip("/")
|
|
segments = path_template.split("/")
|
|
# remove params to a separate array
|
|
params = []
|
|
for idx, segment in enumerate(segments):
|
|
if segment.startswith("{") and segment.endswith("}"):
|
|
params.append(segment)
|
|
segments[idx] = "{}"
|
|
# remove them from the segments
|
|
segments = [segment for segment in segments if segment != "{}"]
|
|
# reverse the segments
|
|
segments.reverse()
|
|
name_parts = []
|
|
for segment in segments:
|
|
if segment in VERBS:
|
|
# prepend to the name_parts
|
|
name_parts.insert(0, segment.lower())
|
|
else:
|
|
name_parts.insert(0, segment.lower())
|
|
break
|
|
for param in params:
|
|
name_parts.append("by " + param.replace("{", "").replace("}", ""))
|
|
break
|
|
return method.upper() + " " + " ".join(name_parts)
|
|
|
|
|
|
# when given an url and its path template, generates the parameters section of the request
|
|
def url_to_params(url, path_template):
|
|
path_template = path_template.strip("/")
|
|
segments = path_template.split("/")
|
|
url_segments = url.split("?")[0].strip("/").split("/")
|
|
params = []
|
|
for idx, segment in enumerate(segments):
|
|
if segment.startswith("{") and segment.endswith("}"):
|
|
params.append(
|
|
{
|
|
"name": segment.replace("{", "").replace("}", ""),
|
|
"in": "path",
|
|
"required": True,
|
|
"schema": {
|
|
"type": "number" if url_segments[idx].isdigit() else "string"
|
|
},
|
|
}
|
|
)
|
|
query_string = urllib.parse.urlparse(url).query
|
|
if query_string:
|
|
query_params = urllib.parse.parse_qs(query_string)
|
|
for key in query_params:
|
|
params.append(
|
|
{
|
|
"name": key,
|
|
"in": "query",
|
|
"required": False,
|
|
"schema": {
|
|
"type": "number" if query_params[key][0].isdigit() else "string"
|
|
},
|
|
}
|
|
)
|
|
return params
|
|
|
|
|
|
def request_to_headers(headers: dict[str, List[Any]], add_example: bool = False):
|
|
"""When given an url and its path template, generates the parameters
|
|
section of the request."""
|
|
params = []
|
|
if headers:
|
|
for key in headers:
|
|
h = {
|
|
"name": key,
|
|
"in": "header",
|
|
"required": False,
|
|
"schema": {"type": "number" if headers[key][0].isdigit() else "string"},
|
|
}
|
|
if add_example:
|
|
h["example"] = headers[key][0]
|
|
params.append(h)
|
|
return params
|
|
|
|
|
|
def response_to_headers(headers):
|
|
header = {}
|
|
if headers:
|
|
for key in headers:
|
|
header[key] = {
|
|
"description": headers[key][0],
|
|
"schema": {"type": "number" if headers[key][0].isdigit() else "string"},
|
|
}
|
|
return header
|
|
|
|
|
|
def value_to_schema(value):
|
|
# check if value is a number
|
|
if type(value) == int or type(value) == float:
|
|
return {"type": "number"}
|
|
# check if value is a boolean
|
|
elif type(value) == bool:
|
|
return {"type": "boolean"}
|
|
# check if value is a string
|
|
elif type(value) == str:
|
|
return {"type": "string"}
|
|
# check if value is a list
|
|
elif type(value) == list:
|
|
if len(value) == 0:
|
|
return {"type": "array", "items": {}}
|
|
|
|
return {"type": "array", "items": value_to_schema(value[0])}
|
|
# check if value is a dict
|
|
elif type(value) == dict:
|
|
return {
|
|
"type": "object",
|
|
"properties": {key: value_to_schema(value[key]) for key in value},
|
|
}
|
|
# if it is none, return null
|
|
elif value is None:
|
|
return {"type": "object"}
|
|
|
|
|
|
MAX_EXAMPLE_ARRAY_ELEMENTS = 10
|
|
MAX_EXAMPLE_OBJECT_PROPERTIES = 150
|
|
|
|
|
|
# recursively scan an example value and limit the number of elements and properties
|
|
def limit_example_size(example):
|
|
if type(example) == list:
|
|
new_list = []
|
|
for element in example:
|
|
if len(new_list) >= MAX_EXAMPLE_ARRAY_ELEMENTS:
|
|
break
|
|
new_list.append(limit_example_size(element))
|
|
return new_list
|
|
elif type(example) == dict:
|
|
new_dict = {}
|
|
for key in example:
|
|
if len(new_dict) >= MAX_EXAMPLE_OBJECT_PROPERTIES:
|
|
break
|
|
new_dict[key] = limit_example_size(example[key])
|
|
return new_dict
|
|
else:
|
|
return example
|