mirror of https://github.com/zulip/zulip.git
api docs: Display data type of responses in API Documentation.
Previously, the data type of responses wasn't displayed in the API Documentation, even though that OpenAPI data is carefully validated against the implementation. Here we add a recursive function to render the data types visibly in API Documentation. Fixes part of #15967.
This commit is contained in:
parent
38dc1131b9
commit
26a81ab3aa
|
@ -1726,6 +1726,10 @@ label.label-title {
|
|||
}
|
||||
}
|
||||
|
||||
.api-response-datatype {
|
||||
color: hsl(176, 46.4%, 41%);
|
||||
}
|
||||
|
||||
.desktop-redirect-box {
|
||||
text-align: center;
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ from markdown.preprocessors import Preprocessor
|
|||
|
||||
from zerver.openapi.openapi import get_openapi_return_values, likely_deprecated_parameter
|
||||
|
||||
from .api_arguments_table_generator import generate_data_type
|
||||
|
||||
REGEXP = re.compile(r'\{generate_return_values_table\|\s*(.+?)\s*\|\s*(.+)\s*\}')
|
||||
|
||||
class MarkdownReturnValuesTableGenerator(Extension):
|
||||
|
@ -59,11 +61,27 @@ class APIReturnValuesTablePreprocessor(Preprocessor):
|
|||
done = True
|
||||
return lines
|
||||
|
||||
def render_desc(self, description: str, spacing: int, return_value: Optional[str]=None) -> str:
|
||||
def render_desc(self, description: str, spacing: int, data_type: str,
|
||||
return_value: Optional[str]=None) -> str:
|
||||
description = description.replace('\n', '\n' + ((spacing + 4) * ' '))
|
||||
if return_value is None:
|
||||
return (spacing * " ") + "* " + description
|
||||
return (spacing * " ") + "* `" + return_value + "`: " + description
|
||||
# HACK: It's not clear how to use OpenAPI data to identify
|
||||
# the `key` fields for objects where e.g. the keys are
|
||||
# user/stream IDs being mapped to data associated with
|
||||
# those IDs. We hackily describe those fields by
|
||||
# requiring that the descriptions be written as `key_name:
|
||||
# key_description` and parsing for that pattern; we need
|
||||
# to be careful to skip cases where we'd have `Note: ...`
|
||||
# on a later line.
|
||||
#
|
||||
# More correctly, we should be doing something that looks at the types;
|
||||
# print statements and test_api_doc_endpoint is useful for testing.
|
||||
arr = description.split(": ", 1)
|
||||
if data_type != "object" or len(arr) == 1 or '\n' in arr[0]:
|
||||
return (spacing * " ") + "* " + description
|
||||
(key_name, key_description) = arr
|
||||
return (spacing * " ") + "* " + key_name + ": " + '<span class="api-response-datatype">' + data_type + "</span> " + key_description
|
||||
return (spacing * " ") + "* `" + return_value + "`: " + '<span class="api-response-datatype">' + data_type + "</span> " + description
|
||||
|
||||
def render_table(self, return_values: Dict[str, Any], spacing: int) -> List[str]:
|
||||
IGNORE = ["result", "msg"]
|
||||
|
@ -77,28 +95,32 @@ class APIReturnValuesTablePreprocessor(Preprocessor):
|
|||
# description of the endpoint. Then for each element of oneOf there is a
|
||||
# specialized description for that particular case. The description used
|
||||
# right below is the main description.
|
||||
data_type = generate_data_type(return_values[return_value])
|
||||
ans.append(self.render_desc(return_values[return_value]['description'],
|
||||
spacing, return_value))
|
||||
spacing, data_type, return_value))
|
||||
for element in return_values[return_value]['oneOf']:
|
||||
if 'description' not in element:
|
||||
continue
|
||||
# Add the specialized description of the oneOf element.
|
||||
ans.append(self.render_desc(element['description'], spacing + 4))
|
||||
data_type = generate_data_type(element)
|
||||
ans.append(self.render_desc(element['description'], spacing + 4, data_type))
|
||||
# If the oneOf element is an object schema then render the documentation
|
||||
# of its keys.
|
||||
if 'properties' in element:
|
||||
ans += self.render_table(element['properties'], spacing + 8)
|
||||
continue
|
||||
description = return_values[return_value]['description']
|
||||
data_type = generate_data_type(return_values[return_value])
|
||||
# Test to make sure deprecated keys are marked appropriately.
|
||||
if likely_deprecated_parameter(description):
|
||||
assert(return_values[return_value]['deprecated'])
|
||||
ans.append(self.render_desc(description, spacing, return_value))
|
||||
ans.append(self.render_desc(description, spacing, data_type, return_value))
|
||||
if 'properties' in return_values[return_value]:
|
||||
ans += self.render_table(return_values[return_value]['properties'], spacing + 4)
|
||||
if return_values[return_value].get('additionalProperties', False):
|
||||
data_type = generate_data_type(return_values[return_value]['additionalProperties'])
|
||||
ans.append(self.render_desc(return_values[return_value]['additionalProperties']
|
||||
['description'], spacing + 4))
|
||||
['description'], spacing + 4, data_type))
|
||||
if 'properties' in return_values[return_value]['additionalProperties']:
|
||||
ans += self.render_table(return_values[return_value]['additionalProperties']
|
||||
['properties'], spacing + 8)
|
||||
|
|
Loading…
Reference in New Issue