Skip to content

🐛 Fix wrong OpenApi scheme generation for custom models with computed fields in additional responses#12119

Closed
DavideGalilei wants to merge 3 commits intofastapi:masterfrom
DavideGalilei:fix-responses-model-computed-fields
Closed

🐛 Fix wrong OpenApi scheme generation for custom models with computed fields in additional responses#12119
DavideGalilei wants to merge 3 commits intofastapi:masterfrom
DavideGalilei:fix-responses-model-computed-fields

Conversation

@DavideGalilei
Copy link
Copy Markdown

Previously discussed here: @computed_field not showing in OpenAPI Json #9856

📕 Description

  • When using computed fields in a custom Pydantic model, FastAPI incorrectly uses mode="validation" for the additional responses model schema.

  • This causes an issue where the response model is interpreted as an -Input model, thus excluding read-only computed fields from the documentation (note: the fields are correctly returned in the answer even if they are not shown in the documentation).

👀 Example code

from fastapi import FastAPI
from pydantic import BaseModel
from pydantic.fields import computed_field

app = FastAPI()

class Rectangle(BaseModel):
    width: int
    height: int

    @computed_field
    def area(self) -> int:
        return self.width * self.height

@app.get(
    "/rectangle/",
    responses={200: {"model": Rectangle}},
)
async def rectangle() -> Rectangle:
    return Rectangle(width=10, height=5)

❌ Wrong (current) schema

Click to expand

image

{
  "openapi": "3.1.0",
  "info": {
    "title": "FastAPI",
    "version": "0.1.0"
  },
  "paths": {
    "/rectangle/": {
      "get": {
        "summary": "Rectangle",
        "operationId": "rectangle_rectangle__get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Rectangle-Input"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Rectangle-Input": {
        "properties": {
          "width": {
            "type": "integer",
            "title": "Width"
          },
          "height": {
            "type": "integer",
            "title": "Height"
          }
        },
        "type": "object",
        "required": [
          "width",
          "height"
        ],
        "title": "Rectangle"
      },
      "Rectangle-Output": {
        "properties": {
          "width": {
            "type": "integer",
            "title": "Width"
          },
          "height": {
            "type": "integer",
            "title": "Height"
          },
          "area": {
            "type": "integer",
            "title": "Area",
            "readOnly": true
          }
        },
        "type": "object",
        "required": [
          "width",
          "height",
          "area"
        ],
        "title": "Rectangle"
      }
    }
  }
}

✅ Correct (fixed) schema:

Click to expand

image

{
  "openapi": "3.1.0",
  "info": {
    "title": "FastAPI",
    "version": "0.1.0"
  },
  "paths": {
    "/rectangle/": {
      "get": {
        "summary": "Rectangle",
        "operationId": "rectangle_rectangle__get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Rectangle"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Rectangle": {
        "properties": {
          "width": {
            "type": "integer",
            "title": "Width"
          },
          "height": {
            "type": "integer",
            "title": "Height"
          },
          "area": {
            "type": "integer",
            "title": "Area",
            "readOnly": true
          }
        },
        "type": "object",
        "required": [
          "width",
          "height",
          "area"
        ],
        "title": "Rectangle"
      }
    }
  }
}

OpenApi schema diff (wrong ➡️ correct)

18c18
<                   "$ref": "#/components/schemas/Rectangle-Input"
---
>                   "$ref": "#/components/schemas/Rectangle"
29,47c29
<       "Rectangle-Input": {
<         "properties": {
<           "width": {
<             "type": "integer",
<             "title": "Width"
<           },
<           "height": {
<             "type": "integer",
<             "title": "Height"
<           }
<         },
<         "type": "object",
<         "required": [
<           "width",
<           "height"
<         ],
<         "title": "Rectangle"
<       },
<       "Rectangle-Output": {
---
>       "Rectangle": {

💊 Fix

Use mode="serialization" for create_model_field for additional responses model.

🧪 Added tests!

  • All tests pass and the code has been formatted
  • tests/test_additional_responses_custom_model_with_computed_fields.py

@DavideGalilei
Copy link
Copy Markdown
Author

DavideGalilei commented Sep 2, 2024

Edit: I just noticed that this PR might be a duplicate PR of #11517

@alejsdev alejsdev added the bug Something isn't working label Sep 3, 2024
@alejsdev
Copy link
Copy Markdown
Member

alejsdev commented Sep 3, 2024

Hi @DavideGalilei, thank you for your interest in contributing to the project! Yes, this is a duplicate. We'll review both PRs in detail later. We currently have a high volume of PRs, we appreciate your patience as we manage the queue. 🙇‍♀️

@flxdot
Copy link
Copy Markdown
Contributor

flxdot commented Sep 5, 2024

Hi @DavideGalilei, thank you for your interest in contributing to the project! Yes, this is a duplicate. We'll review both PRs in detail later. We currently have a high volume of PRs, we appreciate your patience as we manage the queue. 🙇‍♀️

And the PR is a duplicate of #10895 :)

@svlandeg svlandeg self-assigned this Sep 18, 2024
Copy link
Copy Markdown
Member

@svlandeg svlandeg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @DavideGalilei, thanks for the contribution!

Your fix is correct, but the PR is indeed a duplicate of #11517 and #10895. My suggestion is to merge the earliest PR #10895 and close this one, but I'll leave the final review for Tiangolo.

Thanks again though! 🙏

@tiangolo
Copy link
Copy Markdown
Member

Thanks for the interest @DavideGalilei! As @svlandeg was saying, this was handled in #10895. That is now available in FastAPI 0.115.1. So I'll now pass on this one, but thanks for the effort! ☕

@tiangolo tiangolo closed this Oct 12, 2024
@svlandeg svlandeg removed their assignment Feb 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants