1

When making an app that uses dependency injection with a list field, the parameter automatically goes to the request body in SwaggerUI:

from fastapi import FastAPI, Query, Depends
import uvicorn
from pydantic import BaseModel, Field
from typing import List


class QueryParams(BaseModel):
    name: str = Field(...)
    ages: List[int] = Field([])


app = FastAPI()


@app.get("/test")
def test(query: QueryParams = Depends()):
    return "hi"

uvicorn.run(app)

SwaggerUI

Which means I cant test it in swagger UI. Even if I change field to query, it still doesn't work:

from fastapi import FastAPI, Query, Depends
import uvicorn
from pydantic import BaseModel, Field
from typing import List


class QueryParams(BaseModel):
    name: str = Field(...)
    ages: List[int] = Query([])  # <-- Query


app = FastAPI()


@app.get("/test")
def test(query: QueryParams = Depends()):
    return "hi"

uvicorn.run(app)

If I put it in the route function, it works:

from fastapi import FastAPI, Query, Depends
import uvicorn
from pydantic import BaseModel, Field
from typing import List


class QueryParams(BaseModel):
    name: str = Field(...)


app = FastAPI()


@app.get("/test")
def test(query: QueryParams = Depends(), ages: List[int] = Query([])):
    return "hi"

uvicorn.run(app)

Working UI

How can I get swagger UI to recognize a list query field in a basemodel with dependency injection?

0

2 Answers 2

1

As described in this answer, one can't use a List field inside a Pydantic model and expect it to be a query parameter. The way to do this is to implement your query parameter-parsing in a separate dependency class, as shown below:

class QueryParams:
    def __init__(
        self,
        name: str,
        ages: List[int] = Query(...)
    ):
        self.name = name
        self.ages = ages
        
@app.get("/test")
def test(query: QueryParams = Depends()):
    return "hi"

The above can be re-written using the @dataclass decorator, as shown below:

from dataclasses import dataclass

@dataclass
class QueryParams:
    name: str
    ages: List[int] = Query(...)

@app.get("/test")
def test(query: QueryParams = Depends()):
    return "hi"

Update

One could wrap the Query() in a Field() that would allow them to define a List field as query parameter inside the Pydantic model. Complete working examples can be found in this answer and this answer.

from fastapi import Query
from pydantic import BaseModel, Field
from typing import List

class QueryParams(BaseModel):
    name: str
    ages: List[int] = Field(Query(...))
Sign up to request clarification or add additional context in comments.

2 Comments

Do you know why we cant use a query parameter in a base model for a list field? Is it a design decision?
Could be. There is an extensive discussion here, if you would like to have a look.
1

I'm gonna just drop this here, maybe it will help someone.

I achieved the desired result using:

  • List from typing
  • Field from pydantic
  • Query from fastapi
    class User(BaseModel):
      name: Optional[str] = None
      favorite_colors: List[str] = Field(Query(default=[]))

The default=[] is needed to indicate that´s an optional parameter.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.