sanic-openapi
sanic-openapi copied to clipboard
[Bug] Doubly defined objects in the output specification
When we have:
@component
@dataclasses.dataclass
class Location:
x: int
y: int
@component
@dataclasses.dataclass
class UserProfile:
name: str
age: int
email: str
location: Location #Path
Location is define twice in the output schema. Once in components, once again within UserProfile.
This is deeply problematic for code generators which depend on generating a single class for both. ( openapi-generator-cli, for example, produces two Location classes and one cannot be used where the other is used).
UserProfile should have a ref to Location and Location should be added as a component whether or not it has the @component
decorator:
{
"$ref": f"#/components/schemas/{Location.__name__}"
}
import os
import dataclasses
from sanic import Sanic, text, Request
from sanic_ext.extensions.openapi import openapi
from sanic_ext.extensions.openapi.definitions import Response, RequestBody
from sanic_ext.extensions.openapi.openapi import component
# from typing import List
app = Sanic("app")
@component
@dataclasses.dataclass
class MyBody:
email: str
# @property
# def something(self) -> int:
# print("Oh no you didn't!")
# return "OK2"
@component
@dataclasses.dataclass
class Location:
x: int
y: int
@component
@dataclasses.dataclass
class UserProfile:
name: str
age: int
email: str
# locations: List[Location] #Path
location: Location #Path
@property
def something(self) -> int:
print("Oh no you didn't!")
return "OK"
@app.post("/")
@openapi.definition(
body=RequestBody({"application/json": {
"$ref": f"#/components/schemas/{MyBody.__name__}"
}}, required=True), # if body else None,
# body=RequestBody(Body, required=True),
# summary="User profile update",
# tag="one",
# description=openapi.description(textwrap.dedent(func.__doc__)) if func.__doc__ else None,
response=[ # Success,
Response({
"application/json": {
"schema": {
"$ref": f"#/components/schemas/{UserProfile.__name__}"
}
}
}, status=200)
# Response(Failure, status=400)
],
)
def root(req: Request, *args, **kw): # body:UserProfile):
"""
Short description
Long Description
"""
return text("Hello")