swagger-ui icon indicating copy to clipboard operation
swagger-ui copied to clipboard

having problems with dict used in get requests

Open HamzaYslmn opened this issue 8 months ago • 4 comments

Q&A (please complete the following information)

  • OS: Windows 11
  • Browser: Chrome
  • Version: 134.0.6998.179
  • Method of installation: pip with fastapi
  • Swagger-UI version: 3.10.0
  • Swagger/OpenAPI version: OAS 3.1

Describe the bug you're encountering

having problems with dicts used in get requests

To reproduce...

Steps to reproduce the behavior: write pydantic + fastapi code

import json
from typing import Optional, List
from fastapi import FastAPI, APIRouter, Query, Request, Response
from fastapi.responses import JSONResponse
from pydantic import BaseModel, Field
from pydantic import ConfigDict, field_validator

app = FastAPI()

class AdBase(BaseModel):
    id: str
    title: str
    owner: Optional[str] = None
    doc_id: Optional[List[str]] = None

class AdGetRequest(AdBase):
    page: int = Field(0, gt=-1)
    filters: Optional[dict] = Field(
        default=None,
        example={"location": ["Ankara", "İstanbul"], "position_title": "Yazılım"}
    )
    owner: Optional[str] = Field(None)
    doc_id: Optional[List[str]] = Field(None)
    
    model_config = ConfigDict(extra="ignore")
    
    @field_validator("filters", mode="before")
    def parse_filters(cls, value):
        if value is None:
            return value
        if isinstance(value, str):
            try:
                return json.loads(value)
            except json.JSONDecodeError:
                raise ValueError("filters must be a valid JSON string representing a dictionary")
        return value

@app.get("/management")
async def get_ads(request: Request, ad: AdGetRequest = Query(...)):
    print(f"Received Filters: {ad.filters}")
    
    return JSONResponse(content={"message": "Filters received","filters": ad.filters})

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

Expected behavior

url should be: localhost:8002/DB/ad/management?page=0&filters={"location": ["Ankara", "İstanbul"], "position_title": "Yazılım"}

not: localhost:8002/DB/ad/management?page=0&location=["Ankara","İstanbul"]&position_title=Yazılım

filters missing.

Screenshots

Image

Image

The request is wrong, it's not usable.

HamzaYslmn avatar Apr 07 '25 12:04 HamzaYslmn

Hi @HamzaYslmn,

We don't really know what API Description pydantic + fastapi code generates. If you could provide an actual generated API Description in JSON or YAML format, we would be able to determine if SwaggerUI is doing something problematic.

Thanks!

char0n avatar Apr 17 '25 10:04 char0n

actual generated API Description in JSON

HERE:

{
  "openapi": "3.1.0",
  "info": {
    "title": "FastAPI",
    "version": "0.1.0"
  },
  "paths": {
    "/management": {
      "get": {
        "summary": "Get Ads",
        "operationId": "get_ads_management_get",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Id"
            }
          },
          {
            "name": "title",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Title"
            }
          },
          {
            "name": "owner",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Owner"
            }
          },
          {
            "name": "doc_id",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                {
                  "type": "null"
                }
              ],
              "title": "Doc Id"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": -1,
              "default": 0,
              "title": "Page"
            }
          },
          {
            "name": "filters",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "object",
                  "additionalProperties": true
                },
                {
                  "type": "null"
                }
              ],
              "example": {
                "location": [
                  "Ankara",
                  "İstanbul"
                ],
                "position_title": "Yazılım"
              },
              "title": "Filters"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {

                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
          }
        },
        "type": "object",
        "title": "HTTPValidationError"
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      }
    }
  }
}

http://localhost:8000/openapi.json

HamzaYslmn avatar Apr 17 '25 11:04 HamzaYslmn

YAML

openapi: 3.1.0
info:
  title: FastAPI
  version: 0.1.0
paths:
  /management:
    get:
      summary: Get Ads
      operationId: get_ads_management_get
      parameters:
      - name: id
        in: query
        required: true
        schema:
          type: string
          title: Id
      - name: title
        in: query
        required: true
        schema:
          type: string
          title: Title
      - name: owner
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Owner
      - name: doc_id
        in: query
        required: false
        schema:
          anyOf:
          - type: array
            items:
              type: string
          - type: 'null'
          title: Doc Id
      - name: page
        in: query
        required: false
        schema:
          type: integer
          exclusiveMinimum: -1
          default: 0
          title: Page
      - name: filters
        in: query
        required: false
        schema:
          anyOf:
          - type: object
            additionalProperties: true
          - type: 'null'
          example:
            location:
            - Ankara
            - "\u0130stanbul"
            position_title: "Yaz\u0131l\u0131m"
          title: Filters
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
components:
  schemas:
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
            - type: string
            - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
      type: object
      required:
      - loc
      - msg
      - type
      title: ValidationError

HamzaYslmn avatar Apr 17 '25 11:04 HamzaYslmn