Skip to content
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

Bug: failure to reflect constraints in autogenerated OpenAPI spec #3999

Open
1 of 4 tasks
umarbutler opened this issue Feb 14, 2025 · 5 comments
Open
1 of 4 tasks

Bug: failure to reflect constraints in autogenerated OpenAPI spec #3999

umarbutler opened this issue Feb 14, 2025 · 5 comments
Labels
Bug 🐛 This is something that is not working as expected

Comments

@umarbutler
Copy link

Description

Adding a gt constraint to an int with either msgpec.Meta or litestar.params.Body() fails to have that greater than constraint reflected in the autogenerated OpenAPI spec.

Here is the MRE:

from typing import Annotated

import msgspec

from litestar import get, Request, Litestar
from litestar.params import Body


class Resp(msgspec.Struct):
    foo: Annotated[int, msgspec.Meta(gt=0), Body(gt=0)]

Resp = Annotated[Resp, Body(description="A response object.")]

@get("/")
async def home() -> Resp:
    return Resp(1)

@get(path=["/openapi.json"], include_in_schema=False, sync_to_thread=True)
def get_openapi(request: Request) -> dict:
    schema = request.app.openapi_schema

    return schema.to_schema()

app = Litestar(
    [home, get_openapi],
)

if __name__ == "__main__":
    import uvicorn

    try:
        uvicorn.run(
            app = "_mre:app",
            host = "localhost",
            port = 2020,
            reload = True,
        )
    
    except Exception:
        uvicorn.run(
            app = app,
            host = "localhost",
            port = 2020,
        )

Here is the autogenerated OpenAPI spec:

{
  "info": {
    "title": "Litestar API",
    "version": "1.0.0"
  },
  "openapi": "3.1.0",
  "servers": [
    {
      "url": "/"
    }
  ],
  "paths": {
    "/": {
      "get": {
        "summary": "Home",
        "operationId": "Home",
        "responses": {
          "200": {
            "description": "Request fulfilled, document follows",
            "headers": {

            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Resp"
                }
              }
            }
          }
        },
        "deprecated": false
      }
    }
  },
  "components": {
    "schemas": {
      "Resp": {
        "properties": {
          "foo": {
            "type": "integer"
          }
        },
        "type": "object",
        "required": [
          "foo"
        ],
        "title": "Resp",
        "description": "A response object."
      }
    }
  }
}

It only works if you specify float instead of int.

URL to code causing the issue

No response

MCVE

# Your MCVE code here

Steps to reproduce

1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

Screenshots

"![SCREENSHOT_DESCRIPTION](SCREENSHOT_LINK.png)"

Logs

Litestar Version

2.13.0 final

Platform

  • Linux
  • Mac
  • Windows
  • Other (Please specify in the description above)
@umarbutler umarbutler added the Bug 🐛 This is something that is not working as expected label Feb 14, 2025
@umarbutler
Copy link
Author

This persists on 2.14.0.

@umarbutler
Copy link
Author

Turns out, this only happens if we're dealing with an int AND the constraint is 0. Super weird.

Temporary solution: gt = 0 -> ge = 1.

But having to do ge = 0 -> gt = -1 for my custom NonNegativeInt type is a bit annoying.

@provinzkraut
Copy link
Member

Turns out, this only happens if we're dealing with an int AND the constraint is 0. Super weird.

Mmh. Sounds like the bug could be a not gt check where it should be a gt is not None somewhere.

@umarbutler
Copy link
Author

Yes there is a check like that but changing that code didn't fix it either. I suspect there's two layers of checks like that which are making it even trickier.

@umarbutler
Copy link
Author

@provinzkraut it also looks like even if I get ge=1 in Meta but I don't also duplicate that in Body() then it won't show up in the spec... for only certain structs?? and for some structs it will show up. Again, only for ints.

Workaround: make sure you define your constraints twice in Meta and Body(). And never let a constraint be 0 if its an int.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug 🐛 This is something that is not working as expected
Projects
None yet
Development

No branches or pull requests

2 participants