Fastapi: Union between Valid type should be Valid

Created on 8 Nov 2020  路  2Comments  路  Source: tiangolo/fastapi

First check

  • [x] I added a very descriptive title to this issue.
  • [x] I used the GitHub search to find a similar issue and didn't find it.
  • [x] I searched the FastAPI documentation, with the integrated search.
  • [x] I already searched in Google "How to X in FastAPI" and didn't find any information.
  • [x] I already read and followed all the tutorial in the docs and didn't find an answer.
  • [x] I already checked if it is not related to FastAPI but to Pydantic.
  • [x] I already checked if it is not related to FastAPI but to Swagger UI.
  • [x] I already checked if it is not related to FastAPI but to ReDoc.
  • [x] After submitting this, I commit to one of:

    • Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there.

    • I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future.

    • Implement a Pull Request for a confirmed bug.

Example

from fastapi import FastAPI, Query
from enum import Enum
from typing import List, Union

app = FastAPI()


class Tag(str, Enum):
    a = 'a'
    b = 'b'
    c = 'c'


@app.get("/")
async def read_file(tag_or_list: Union[Tag, List[str]] = Query(...)):
    return tag_or_list

Description

I got the following error for running uvicorn test:app:

  File "/usr/local/lib/python3.8/site-packages/fastapi/dependencies/utils.py", line 333, in get_dependant
    assert isinstance(
AssertionError: Param: tag_or_list can only be a request body, using Body(...)

a List[str] is valid and Enum instace for Query is valid why Union between theme is not valid?

Environment

  • OS: Linux
  • FastAPI Version : 0.61.2
  • Python version: 3.8.6

Additional context

question

Most helpful comment

In the example, tag_or_list is just a one query parameter, but since you are giving more than one Models to it with Union, it understands the situation and assumes it is a Body that's why it expects a Body

You can send an array as a query parameter like this /products?color=blue,green,red but you have one query parameter in this case. So you can not serialize two different things in one query parameter in any way.

So there are two options for you.

You can create a new model.

from fastapi import FastAPI, Depends
from enum import Enum
from pydantic import BaseModel
from typing import List

app = FastAPI()


class Tag(str, Enum):
    a = "a"
    b = "b"
    c = "c"


class NewModel(BaseModel):
    tag: Tag
    my_list: List[str]


@app.post("/")
async def read_file(tag_or_list: NewModel = Depends()):
    return tag_or_list

Or you can create two different query parameters.

from fastapi import FastAPI, Query
from enum import Enum
from pydantic import BaseModel
from typing import List

app = FastAPI()


class Tag(str, Enum):
    a = "a"
    b = "b"
    c = "c"


@app.post("/")
async def read_file(tag: Tag, my_list: List[str] = Query(...)):
    return tag_or_list

There is no way to merge two different things in one Query parameter, if you need one result, you need to use a Request Body.

All 2 comments

In the example, tag_or_list is just a one query parameter, but since you are giving more than one Models to it with Union, it understands the situation and assumes it is a Body that's why it expects a Body

You can send an array as a query parameter like this /products?color=blue,green,red but you have one query parameter in this case. So you can not serialize two different things in one query parameter in any way.

So there are two options for you.

You can create a new model.

from fastapi import FastAPI, Depends
from enum import Enum
from pydantic import BaseModel
from typing import List

app = FastAPI()


class Tag(str, Enum):
    a = "a"
    b = "b"
    c = "c"


class NewModel(BaseModel):
    tag: Tag
    my_list: List[str]


@app.post("/")
async def read_file(tag_or_list: NewModel = Depends()):
    return tag_or_list

Or you can create two different query parameters.

from fastapi import FastAPI, Query
from enum import Enum
from pydantic import BaseModel
from typing import List

app = FastAPI()


class Tag(str, Enum):
    a = "a"
    b = "b"
    c = "c"


@app.post("/")
async def read_file(tag: Tag, my_list: List[str] = Query(...)):
    return tag_or_list

There is no way to merge two different things in one Query parameter, if you need one result, you need to use a Request Body.

Is your issue is resolved @ihakh ?

Was this page helpful?
0 / 5 - 0 ratings