fastapi icon indicating copy to clipboard operation
fastapi copied to clipboard

Unavailability to set `default` response for OpenAPI doc at `0.79.0`

Open matiuszka opened this issue 3 years ago • 7 comments

First Check

  • [X] I added a very descriptive title to this issue.
  • [X] I used the GitHub search to find a similar issue and didn't find it.
  • [X] I searched the FastAPI documentation, with the integrated search.
  • [X] I already searched in Google "How to X in FastAPI" and didn't find any information.
  • [X] I already read and followed all the tutorial in the docs and didn't find an answer.
  • [X] I already checked if it is not related to FastAPI but to Pydantic.
  • [X] I already checked if it is not related to FastAPI but to Swagger UI.
  • [X] I already checked if it is not related to FastAPI but to ReDoc.

Commit to Help

  • [X] I commit to help with one of those options 👆

Example Code

from fastapi import FastAPI
from fastapi.responses import JSONResponse
from pydantic import BaseModel


class Item(BaseModel):
    id: str
    value: str


class Message(BaseModel):
    message: str


app = FastAPI()


@app.get("/items/{item_id}", response_model=Item, responses={"default": {"model": Message}})
async def read_item(item_id: str):
    if item_id == "foo":
        return {"id": "foo", "value": "there goes my hero"}
    else:
        return JSONResponse(status_code=404, content={"message": "Item not found"})

Description

Prior to 0.79.0 I was able to specify the default response for the path. According to the OpenAPI Spec, it should be somehow possible: https://swagger.io/specification/#path-item-object

At 0.79.0 I am receiving this exception:

Traceback (most recent call last):
  File "<stdin>", line 19, in <module>
  File "/Users/matnowak/.pyenv/versions/3.9.11/envs/radkit3.9/lib/python3.9/site-packages/fastapi/routing.py", line 622, in decorator
    self.add_api_route(
  File "/Users/matnowak/.pyenv/versions/3.9.11/envs/radkit3.9/lib/python3.9/site-packages/fastapi/routing.py", line 561, in add_api_route
    route = route_class(
  File "/Users/matnowak/.pyenv/versions/3.9.11/envs/radkit3.9/lib/python3.9/site-packages/fastapi/routing.py", line 418, in __init__
    assert is_body_allowed_for_status_code(
  File "/Users/matnowak/.pyenv/versions/3.9.11/envs/radkit3.9/lib/python3.9/site-packages/fastapi/utils.py", line 24, in is_body_allowed_for_status_code
    current_status_code = int(status_code)
ValueError: invalid literal for int() with base 10: 'default'

invalid literal for int() with base 10: 'default'

How to set the default response in OpenAPI?

Operating System

Linux, Windows, macOS

Operating System Details

No response

FastAPI Version

0.79.0

Python Version

3.9.11

Additional Context

No response

matiuszka avatar Jul 18 '22 07:07 matiuszka

default response_code is 200, you need to specify status code instead of default keyword

kalmastenitin avatar Jul 18 '22 12:07 kalmastenitin

@kalmastenitin As you can see in the spec example: https://swagger.io/specification/#path-item-object besides 200 there is the option to specify the default.

If I will rephrase the question here, it will be: how to recreate the same structure as presented in OpenAPI examples from fastapi point of view?

matiuszka avatar Jul 18 '22 12:07 matiuszka

"default" response is a specifier for any status code that doesn't have an entry. It usually is for specifying the schema of error responses

tapple avatar Jul 18 '22 13:07 tapple

Hi! We are also seeing this issue. We are initializing FastAPI with a default response for unexpected error responses for OpenAPI spec:

FastAPI(..., responses={"default": {"model": UnexpectedErrorResponse}})

After updating to 0.79.0 this breaks with similar exception as above.

See OpenAPI specification for "default" responses: https://swagger.io/docs/specification/describing-responses/#default previously this was possible to define it in FastAPI but it is now broken.

This PR seems the one that broke the OpenAPI default-response definitions: https://github.com/tiangolo/fastapi/pull/5145 cc @tiangolo

MarkusSintonen avatar Jul 22 '22 07:07 MarkusSintonen

@MarkusSintonen Thanks for the answer. I am glad that someone else is also seeing this as a potential bug. I will try to propose a fix for this.

matiuszka avatar Jul 22 '22 08:07 matiuszka

Hi!

We are also facing this issue. We are using default as status code for error responses too.

Also things like 5XX (see Swagger Docs) should be valid values.

Changing the function is_body_allowed_for_status_code could fix this issue. Maybe something like this:

def is_body_allowed_for_status_code(status_code: Union[int, str, None]) -> bool:
    if status_code is None:
        return True
    if isinstance(status_code, str) and not status_code.isdigit():
        # return 'True' as we cannot know if this response is allowed to have a body
        return True
    current_status_code = int(status_code)
    return not (current_status_code < 200 or current_status_code in {204, 304})

gruberlu avatar Jul 22 '22 11:07 gruberlu

I guess that could work. I would opt for a more specific check though, just to be compliant with the OpenAPI spec. Something in the line of:

def is_body_allowed_for_status_code(status_code: Union[int, str, None]) -> bool:
    if status_code is None or status_code=="default":
        return True
    current_status_code = int(status_code)
    return not (current_status_code < 200 or current_status_code in {204, 304})

JarroVGIT avatar Jul 23 '22 12:07 JarroVGIT

@JarroVGIT the OpenAPI spec also allows specifiers of 4XX etc, which your code would still raise the same ValueError on. It's not very nice but at least the default use cases are client/server errors and as such we won't see 2XX 3XX often/at all

Kyle-sandeman-mrdfood avatar Aug 18 '22 11:08 Kyle-sandeman-mrdfood

My pull request does account for that, it checks various values including the xXX values

JarroVGIT avatar Aug 18 '22 12:08 JarroVGIT