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

Pydantic Types (Optional, Tuple, List) not validating on export as OpenAPI #1367

Open
QBH3 opened this issue Jan 15, 2025 · 0 comments
Open

Comments

@QBH3
Copy link

QBH3 commented Jan 15, 2025

Describe the bug

I write an app in django using the django rest framework and pydantic classes as well as spectacular extended_schema annotations.

when exporting views that take types having optional fields the export does not validate:

class RequestBSchema(BaseModel):
    "Pydantic class request string to be send to service"
    string: str
    toggle: Optional[bool] = True

neither do classes of type

class RequestASchema(BaseModel):
    "Pydantic class request string to be send to service"
    string_pairs: List[Tuple[str, str]]

To Reproduce

models/service.py

from typing import Any
from typing import Dict
from typing import Optional

from pydantic import BaseModel
from pydantic import Field

class RequestSchema(BaseModel):
    "Pydantic class request string to be send to service"
    text: str = Field(..., min_length=1)
    toggle: Optional[bool] = True

class ResponseSchema(BaseModel):
    "Pydantic class defining result to be received from service"
    result: Dict[str, Any]

class ErrorResponseSchema(BaseModel):
    detail: str  # A human-readable error message
    code: str # An error code (e.g., VALIDATION_ERROR)

services/service.py

from ..models import RequestSchema
from ..models import ResponseSchema

class Service:
 
    def service(self, query: RequestSchema) -> ResponseSchema:
        """do stuff."""

        result = query.text,
        return ResponseSchema(result=result)

views/service.py

from typing import Any

from drf_spectacular.utils import OpenApiResponse
from drf_spectacular.utils import extend_schema
from pydantic import ValidationError
from rest_framework import status
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import APIView

from .models.service import RequestSchema
from .models.service import ResponseSchema
from .models.service import ErrorResponseSchema

from .services.service import Service

# Instantiate the service
service = Service()

class View(APIView):
    "Implements the DRF view to connect the Service to an API"

    @extend_schema(
        summary="Service",
        description="Services the submitted text",
        request=RequestSchema,
        responses={
            200: ResponseSchema,
            400: OpenApiResponse(ErrorResponseSchema,
                description="Invalid Request - message format is incorrect",
            ),
        },
    )
    def post(self, request: Request, *args: Any, **kwargs: Any) -> Response:
        """Serves the submitted text."""
        try:
            # Validate the input using Pydantic
            validated_data = RequestSchema(**request.data)
            result = service.service(validated_data)
        except ValidationError as e:
            result = ErrorResponseSchema(detail=str(e), code="VALIDATION_ERROR")
            return Response(result.dict(), status=status.HTTP_400_BAD_REQUEST)

        return Response(result.dict(), status=status.HTTP_200_OK)

urls.py:

from django.urls import path

from .views.service import View

urlpatterns = [
    path("service", View.as_view(), name="do stuff"),
]

python manage.py spectacular --file openapi-schema.yaml

class RequestBSchema(BaseModel):
    "Pydantic class request string to be send to service"
    text: str
    toggle: Optional[bool] = True

exports as:

components:
  schemas:
    RequestBSchema:
      description: Pydantic class request string to be send to service
      properties:
        text:
          minLength: 1
          title: Text
          type: string
        toggle:
          anyOf:
          - type: boolean
          - type: 'null'
          default: true
          title: Return Dense
      required:
      - text
      title: RequestBSchema
      type: object
class RequestASchema(BaseModel):
    "Pydantic class request string to be send to service"
    string_pairs: List[Tuple[str, str]]

exports as:

    RequestASchema:
      description: Pydantic class request string to be send to service
      properties:
        sentence_pairs:
          items:
            maxItems: 2
            minItems: 2
            prefixItems:
            - type: string
            - type: string
            type: array
          title: Sentence Pairs
          type: array
      required:
      - sentence_pairs
      title: RequestASchema
      type: object

both don't validate

Expected behavior

Exporting valid Pydantic types leads to valid OpenAPI specs.

python manage.py spectacular --file openapi-schema.yaml --validate works

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant