Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Union doesn't document properly on swagger #1083

Closed
teamhide opened this issue Mar 5, 2020 · 13 comments
Closed

Union doesn't document properly on swagger #1083

teamhide opened this issue Mar 5, 2020 · 13 comments

Comments

@teamhide
Copy link

teamhide commented Mar 5, 2020

Describe the bug

When using Union on response_model, it doesn't doucment properly on swagger.

To Reproduce

  1. Create two models
from pydantic import BaseModel

class VerifyTokenResponseSchema(BaseModel):
    status: bool

class ExceptionResponseSchema(BaseModel):
    error: str
  1. Add it on response_model
from typing import Union
from fastapi import APIRouter

oauth_router = APIRouter()

@oauth_router.post('/verify', response_model=Union[VerifyTokenResponseSchema, ExceptionResponseSchema])
async def verify_token(token: str):
    status = await VerifyTokenUsecase().execute(token=token)
    return status.dict()
  1. Check it on /docs

Expected behavior

스크린샷 2020-03-05 오후 7 59 47

Example value tab throw no example available.

스크린샷 2020-03-05 오후 7 59 57

But it can show on Schema tab

Additional context

I want to check both response schema on Example value tab.

Is there anything wrong with my code?

(I know that I can use responses but using Union is described on document(https://fastapi.tiangolo.com/tutorial/extra-models/#union-or-anyof)

@teamhide teamhide added the bug Something isn't working label Mar 5, 2020
@Dustyposa
Copy link
Contributor

What do you want to display in example value like Union type

@sm-Fifteen
Copy link
Contributor

sm-Fifteen commented Mar 5, 2020

FastAPI does not generate body examples, that's just something SwaggerUI does, and Swagger apparently doesn't create an example value for type unions (probably because there's no single valid schema anymore). The union is technically properly documented (the schema tab is still correct, and that's the one that actually matters).

I don't know if it's currently possible to specify a custom example structure using FastAPI, though.

@Dustyposa
Copy link
Contributor

I'm not familiar with swagger, but I think it's necessary to obey the swagger rules by default.
Sure, you can define a custom structure, but how to display it that's not easy, two and more example value?

@sm-Fifteen
Copy link
Contributor

Swagger is just the documentation renderer FastAPI exposes at localhost:8000/docs. FastAPI also embeds another documentation renderer, ReDoc, which is accessible at localhost:8000/redoc and might support type unions better than Swagger, but I'm not entirely sure.

Normally, if Swagger can't figure out an example for your schema, your OpenAPI schema can specify one, and Pydantic supports it for individual BaseModel classes, but unions are trickier because they're not actually classes...

@tiangolo
Copy link
Owner

Thanks for the help here @Dustyposa and @sm-Fifteen ! 👏 🍰

Yep, indeed that's not a bug in FastAPI, but a feature request for Swagger UI.

Nevertheless, you can add a custom example that is shown in Swagger UI, check the docs: https://fastapi.tiangolo.com/tutorial/schema-extra-example/

@github-actions
Copy link
Contributor

Assuming the original issue was solved, it will be automatically closed now. But feel free to add more comments or create new issues.

@mcauto
Copy link

mcauto commented May 15, 2020

@Dustyposa 와 @ sm-Fifteen 의 도움에 감사드립니다 !👏 🍰

실제로 FastAPI의 버그는 아니지만 Swagger UI에 대한 기능 요청입니다.

그럼에도 불구하고 Swagger UI에 표시되는 사용자 정의 예제를 추가하고 문서를 확인하십시오. https://fastapi.tiangolo.com/tutorial/schema-extra-example/

class Human(BaseModel):
    age: int
    name: str


class Man(Human):


class Woman(Human):


HumanCreateRequest = Union[Man, Woman]

# POST /human

I want to set default schema Woman class in swagger.

but swagger example is empty.

@phy25
Copy link

phy25 commented May 17, 2020

@mcauto Please see comments above. It's not supported by Swagger UI so you have to add a custom example. Also -

What do you want to display in example value like Union type?

from fastapi import FastAPI, Body
from typing import Union
from pydantic import BaseModel


class User(BaseModel):
    name: str


class Item(BaseModel):
    size: int
    price: float


app = FastAPI()

process_things_body_example = {"name": "1", "size": 2, "price": 3} # whatever makes sense to you

@app.post("/multi/")
def process_things(body: Union[User, Item] = Body(..., example=process_things_body_example)):
    return body

Please create an issue at https://github.com/swagger-api/swagger-ui if you want this behavior to be improved.

@mcauto
Copy link

mcauto commented May 17, 2020

@mcauto Please see comments above. It's not supported by Swagger UI so you have to add a custom example. Also -

What do you want to display in example value like Union type?

from fastapi import FastAPI, Body
from typing import Union
from pydantic import BaseModel


class User(BaseModel):
    name: str


class Item(BaseModel):
    size: int
    price: float


app = FastAPI()

process_things_body_example = {"name": "1", "size": 2, "price": 3} # whatever makes sense to you

@app.post("/multi/")
def process_things(body: Union[User, Item] = Body(..., example=process_things_body_example)):
    return body

Please create an issue at https://github.com/swagger-api/swagger-ui if you want this behavior to be improved.

Thank you for your attension. 👍👍

I solved it!

class Human(BaseModel):
    age: int
    name: str


class Man(Human):

class Woman(Human):

class HumanCreateRequest(BaseModel):
    target: Union[Woman, Man]
    class Config:
        schema_extra = {
            "example": {
                "target": Man(age=29, name="deo").dict()
            }
        }

app = FastAPI()

@app.post("/human")
def add_human(create_request: HumanCreateRequest):
    pass
# POST /human

@mcauto
Copy link

mcauto commented May 21, 2020

Hi! @phy25

Have you ever been like this?

from typing import Union

from fastapi.applications import FastAPI
from pydantic import BaseModel


class Human(BaseModel):
    age: int
    name: str


class Man(Human):
    """ man """

    something: str


class Woman(Human):
    """ woman """


class ManCreateRequest(Man):
    class Config:
        schema_extra = {
            "example": {
                "target": Man(age=29, name="deo", something="something").dict()
            }
        }


class HumanCreateRequest(BaseModel):
    target: Union[Woman, Man]

    class Config:
        schema_extra = Man.Config.schema_extra # default Schema Man


app = FastAPI()


@app.post("/human")
def add_human(create_request: HumanCreateRequest) -> None:
    instance_type = create_request.target # always Woman
    return

Pydantic will always return the first one...

image

I want to get real type of HumanCreateRequest.

@phy25
Copy link

phy25 commented May 21, 2020

@mcauto
Copy link

mcauto commented May 22, 2020

@tiangolo tiangolo added question Question or problem answered reviewed and removed bug Something isn't working labels Feb 22, 2023
@tiangolo tiangolo changed the title [BUG] Union doesn't document properly on swagger Union doesn't document properly on swagger Feb 24, 2023
@tiangolo tiangolo reopened this Feb 28, 2023
@github-actions
Copy link
Contributor

Assuming the original need was handled, this will be automatically closed now. But feel free to add more comments or create new issues or PRs.

@tiangolo tiangolo reopened this Feb 28, 2023
Repository owner locked and limited conversation to collaborators Feb 28, 2023
@tiangolo tiangolo converted this issue into discussion #7633 Feb 28, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Projects
None yet
Development

No branches or pull requests

6 participants