Open TauPan opened 1 week ago
That garbled swagger output is also very weird.
Looking at the output, it seems as if swagger is trying to construct examples from the string format + regex.
Still that example is wrong since the full list of names (all of INFO_NAMES
prefixed by sis.
) would always be present in the response.
Even if I correct the schema to be an array with prefixItems
, each with its own example, redoc still displays it as a list of list.
I swagger-ui the example becomes null
.
(This is the changed code. It's somewhat convoluted since I didn't want to rewrite the whole schema and examples and I wouldn't keep it that way. Just to illustrate:
INFO_ARRAY_SCHEMA = dict(
type='array',
prefixItems=[
dict(
type='object',
properties=OrderedDict({
'name': dict(
type='string',
enum=(f'sis.{n}',),
description='Name des Checks (beginnt immer mit `"sis."`)'
),
'value': STATUS_INFO_VALUE_SCHEMA,
'type': STATUS_INFO_TYPE_SCHEMA,
'description': STATUS_INFO_DESCRIPTION_SCHEMA,
'nagios': dict(
type='string',
pattern=(
f'({n})'
f' ({" | ".join(STATUS_INFO_TYPE_SCHEMA["enum"])})'
f' ({" | ".join(STATUS_INFO_VALUE_SCHEMA["enum"])})'
r' - .+'),
description='Vollständige Ausgabe des Nagios/Icinga-Checks'
)
}),
example=[e for e in INFO_EXAMPLE if e['name'] == f'sis.{n}'][0]
) for n in INFO_NAMES
]
)
class InfoViewSet(viewsets.ViewSet):
"""[Allgemeine Info über den SIS-Server](/doc/#tag/info)
Erlaubt zu Debugging-Zwecken eine Untermenge der
Statusinformationen ohne Autorisierung.
"""
resource = "info"
permission_classes = [permissions.IsAuthenticated]
@extend_schema(
responses={200: INFO_ARRAY_SCHEMA})
def list(self, request):
"""List SIS Information
[/api/info/](/api/info/)
Liefert einen Status von einigen Selbsttest aus.
"""
return Response([c.as_dict() for c in check.info()])
The result in INFO_ARRAY_SCHEMA
dumped to json is:
{
"type": "array",
"prefixItems": [
{
"type": "object",
"properties": {
"name": {
"type": "string",
"enum": [
"sis.info"
],
"description": "Name des Checks (beginnt immer mit `\"sis.\"`)"
},
"value": {
"type": "string",
"enum": [
"ok",
"warning",
"error",
"critical"
],
"description": "Wert oder Schwere (\"Severity\") des Status."
},
"type": {
"type": "string",
"enum": [
"direct"
],
"description": "Nagios/Icinga Typ (immer `\"direct\"`)"
},
"description": {
"type": "string",
"description": "Menschenlesbare Beschreibung des Resultats"
},
"nagios": {
"type": "string",
"pattern": "(info) (direct) (ok | warning | error | critical) - .+",
"description": "Vollst\u00e4ndige Ausgabe des Nagios/Icinga-Checks"
}
},
"example": {
"name": "sis.info",
"value": "ok",
"type": "direct",
"description": "SIS version devel",
"nagios": "sis.info direct ok - SIS version devel"
}
},
{
"type": "object",
"properties": {
"name": {
"type": "string",
"enum": [
"sis.configuration"
],
"description": "Name des Checks (beginnt immer mit `\"sis.\"`)"
},
"value": {
"type": "string",
"enum": [
"ok",
"warning",
"error",
"critical"
],
"description": "Wert oder Schwere (\"Severity\") des Status."
},
"type": {
"type": "string",
"enum": [
"direct"
],
"description": "Nagios/Icinga Typ (immer `\"direct\"`)"
},
"description": {
"type": "string",
"description": "Menschenlesbare Beschreibung des Resultats"
},
"nagios": {
"type": "string",
"pattern": "(configuration) (direct) (ok | warning | error | critical) - .+",
"description": "Vollst\u00e4ndige Ausgabe des Nagios/Icinga-Checks"
}
},
"example": {
"name": "sis.configuration",
"value": "critical",
"type": "direct",
"description": "Config option 'errors-to' missing",
"nagios": "sis.configuration direct critical - Config option 'errors-to' missing"
}
},
{
"type": "object",
"properties": {
"name": {
"type": "string",
"enum": [
"sis.database"
],
"description": "Name des Checks (beginnt immer mit `\"sis.\"`)"
},
"value": {
"type": "string",
"enum": [
"ok",
"warning",
"error",
"critical"
],
"description": "Wert oder Schwere (\"Severity\") des Status."
},
"type": {
"type": "string",
"enum": [
"direct"
],
"description": "Nagios/Icinga Typ (immer `\"direct\"`)"
},
"description": {
"type": "string",
"description": "Menschenlesbare Beschreibung des Resultats"
},
"nagios": {
"type": "string",
"pattern": "(database) (direct) (ok | warning | error | critical) - .+",
"description": "Vollst\u00e4ndige Ausgabe des Nagios/Icinga-Checks"
}
},
"example": {
"name": "sis.database",
"value": "ok",
"type": "direct",
"description": "Database readable",
"nagios": "sis.database direct ok - Database readable"
}
},
{
"type": "object",
"properties": {
"name": {
"type": "string",
"enum": [
"sis.fingerprints"
],
"description": "Name des Checks (beginnt immer mit `\"sis.\"`)"
},
"value": {
"type": "string",
"enum": [
"ok",
"warning",
"error",
"critical"
],
"description": "Wert oder Schwere (\"Severity\") des Status."
},
"type": {
"type": "string",
"enum": [
"direct"
],
"description": "Nagios/Icinga Typ (immer `\"direct\"`)"
},
"description": {
"type": "string",
"description": "Menschenlesbare Beschreibung des Resultats"
},
"nagios": {
"type": "string",
"pattern": "(fingerprints) (direct) (ok | warning | error | critical) - .+",
"description": "Vollst\u00e4ndige Ausgabe des Nagios/Icinga-Checks"
}
},
"example": {
"name": "sis.fingerprints",
"value": "ok",
"type": "direct",
"description": "No duplicate fingerprints",
"nagios": "sis.fingerprints direct ok - No duplicate fingerprints"
}
},
{
"type": "object",
"properties": {
"name": {
"type": "string",
"enum": [
"sis.mail_host"
],
"description": "Name des Checks (beginnt immer mit `\"sis.\"`)"
},
"value": {
"type": "string",
"enum": [
"ok",
"warning",
"error",
"critical"
],
"description": "Wert oder Schwere (\"Severity\") des Status."
},
"type": {
"type": "string",
"enum": [
"direct"
],
"description": "Nagios/Icinga Typ (immer `\"direct\"`)"
},
"description": {
"type": "string",
"description": "Menschenlesbare Beschreibung des Resultats"
},
"nagios": {
"type": "string",
"pattern": "(mail_host) (direct) (ok | warning | error | critical) - .+",
"description": "Vollst\u00e4ndige Ausgabe des Nagios/Icinga-Checks"
}
},
"example": {
"name": "sis.mail_host",
"value": "ok",
"type": "direct",
"description": "SMTP server reachable",
"nagios": "sis.mail_host direct ok - SMTP server reachable"
}
},
{
"type": "object",
"properties": {
"name": {
"type": "string",
"enum": [
"sis.django_compatibility"
],
"description": "Name des Checks (beginnt immer mit `\"sis.\"`)"
},
"value": {
"type": "string",
"enum": [
"ok",
"warning",
"error",
"critical"
],
"description": "Wert oder Schwere (\"Severity\") des Status."
},
"type": {
"type": "string",
"enum": [
"direct"
],
"description": "Nagios/Icinga Typ (immer `\"direct\"`)"
},
"description": {
"type": "string",
"description": "Menschenlesbare Beschreibung des Resultats"
},
"nagios": {
"type": "string",
"pattern": "(django_compatibility) (direct) (ok | warning | error | critical) - .+",
"description": "Vollst\u00e4ndige Ausgabe des Nagios/Icinga-Checks"
}
},
"example": {
"name": "sis.django_compatibility",
"value": "ok",
"type": "direct",
"description": "SIS is compatible with the current version of Django",
"nagios": "sis.django_compatibility direct ok - SIS is compatible with the current version of Django"
}
},
{
"type": "object",
"properties": {
"name": {
"type": "string",
"enum": [
"sis.request_stats"
],
"description": "Name des Checks (beginnt immer mit `\"sis.\"`)"
},
"value": {
"type": "string",
"enum": [
"ok",
"warning",
"error",
"critical"
],
"description": "Wert oder Schwere (\"Severity\") des Status."
},
"type": {
"type": "string",
"enum": [
"direct"
],
"description": "Nagios/Icinga Typ (immer `\"direct\"`)"
},
"description": {
"type": "string",
"description": "Menschenlesbare Beschreibung des Resultats"
},
"nagios": {
"type": "string",
"pattern": "(request_stats) (direct) (ok | warning | error | critical) - .+",
"description": "Vollst\u00e4ndige Ausgabe des Nagios/Icinga-Checks"
}
},
"example": {
"name": "sis.request_stats",
"value": "ok",
"type": "direct",
"description": "No request durations over 100 seconds in the last 5 days",
"nagios": "sis.request_stats direct ok - No request durations over 100 seconds in the last 5 days"
}
}
]
}
)
(The schema displays correctly in redoc, as well as in swagger, although without indentation and somewhat unhelpful in the latter and I will eventually go with that schema, but it doesn't help with the broken example.)
Describe the bug When I specify a list as an example (in a raw schema) in redoc only the first item in the given list is displayed as the only item in the example. If I wrap the example list into a list, the example is displayed as a list of list.
In swagger I always get a single element list with garbled data.
To Reproduce Note that this endpoint returns a list of (subset of) icinga (nagios) check items which are converted into the format expected by icinga checks. The data is provided by code that runs these checks and returns the appropriate status code and description.
So this is my application code (I elided some earlier definitions, but you get the idea, I think):
In this form, the example data will be given in redoc as a list of list.
In swagger, the example looks garbled and only has the first item:
If I change the raw schema to
The example in redoc changes to:
i.e. just the first item. And swagger displays:
Expected behavior I expect to be able to give a full list as an example to a list response and see exactly that list as an example.
I've seen https://drf-spectacular.readthedocs.io/en/stable/faq.html#my-viewset-list-does-not-return-a-list-but-a-single-object as well as https://github.com/tfranzel/drf-spectacular/issues/990 and I've tried to come up with a way to apply the hints in https://drf-spectacular.readthedocs.io/en/stable/faq.html#how-do-i-wrap-my-responses-my-endpoints-are-wrapped-in-a-generic-envelope to an on-the-fly serializer via https://drf-spectacular.readthedocs.io/en/stable/drf_spectacular.html#drf_spectacular.utils.inline_serializer but it seems easier to write a serializer for the data returned by
check.info()
.That seems wasteful since it already does return an array and I feel it should not be that hard.
Also why does something (redoc?) apparently wrap the first element of a list into a list if it's not a list AND keep a nested list as is? That garbled swagger output is also very weird.