3

I have a simple application below:

from typing import Annotated

import uvicorn
from fastapi import FastAPI, Query, Depends
from pydantic import BaseModel

app = FastAPI()


class Input(BaseModel):
    a: Annotated[str, Query(..., alias="your_name")]


@app.get("/")
def test(inp: Annotated[Input, Depends()]):
    return f"Hello {inp.a}"


def main():
    uvicorn.run("run:app", host="0.0.0.0", reload=True, port=8001)


if __name__ == "__main__":
    main()

curl "http://127.0.0.1:8001/?your_name=amin" returns "Hello amin"


I now change the alias from your_name to your-name.

from typing import Annotated

import uvicorn
from fastapi import FastAPI, Query, Depends
from pydantic import BaseModel

app = FastAPI()


class Input(BaseModel):
    a: Annotated[str, Query(..., alias="your-name")]


@app.get("/")
def test(inp: Annotated[Input, Depends()]):
    return f"Hello {inp.a}"


def main():
    uvicorn.run("run:app", host="0.0.0.0", reload=True, port=8001)


if __name__ == "__main__":
    main()

Then curl "http://127.0.0.1:8001/?your-name=amin" returns:

{"detail":[{"loc":["query","extra_data"],"msg":"field required","type":"value_error.missing"}]}

However, hyphened alias in a simpler application is allowed.

from typing import Annotated

import uvicorn
from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/")
def test(a: Annotated[str, Query(..., alias="your-name")]):
    return f"Hello {a}"


def main():
    uvicorn.run("run:app", host="0.0.0.0", reload=True, port=8001)


if __name__ == "__main__":
    main()

curl "http://127.0.0.1:8001/?your-name=amin" returns "Hello Amin"



Is this a bug? what is the problem here?

2
  • Does curl "http://127.0.0.1:8001/?your%2Dname=amin" work? Commented Apr 29, 2023 at 15:04
  • no. the same error response Commented Apr 29, 2023 at 15:23

1 Answer 1

6

Problem Overview

As explained here by @JarroVGIT, this is a behaviour coming from Pydantic, not FastAPI. If you looked closely at the error you posted:

{"detail":[{"loc":["query","extra_data"],"msg":"field required","type":"value_error.missing"}]}

it talks about a missing value for a query parameter named extra_data—however, there is no such a parameter defined in your BaseModel. If, in fact, you used the Swagger UI autodocs at /docs, you would see that your endpoint is expecting a required parameter named extra_data. As noted by @JarroVGIT in the linked discussion above:

Whenever you give a 'non-pythonic' alias (like with dashes/hyphens), the signature that inspect.signature() will get from that BaseModel subclass will be grouped in the kwargs extra_data.

Hence the error about the missing value for extra_data query parameter.

Solution 1

You could wrap the Query() in a Field(), as demonstrated in this answer. Example:

from fastapi import Query, Depends
from pydantic import BaseModel, Field

class Input(BaseModel):
    a: str = Field(Query(..., alias="your-name"))


@app.get("/")
def main(i: Input = Depends()):
    pass

Solution 2

As shown in this answer and this answer, you could use a separate dependency class, instead of a BaseModel. Example:

from fastapi import Query, Depends
from dataclasses import dataclass

@dataclass
class Input:
    a: str = Query(..., alias="your-name")


@app.get("/")
def main(i: Input = Depends()):
    pass

Solution 3

Declare the query parameter directly in the endpoint, instead of using a Pydantic BaseModel. Example:

from fastapi import Query

@app.get("/")
def main(a: str = Query(..., alias="your-name")):
    pass
Sign up to request clarification or add additional context in comments.

6 Comments

In your first solution, could you write it with Annotated?
the question is can I have Annotated and Field and Query in the same line?
a: Annotated[str, Field(Query(..., alias= in fastapi version 0.95.1
The question is about how to use hyphens in query parameters, when these are defined within a Pydantic model. "Python itself doesn't do anything with this Annotated", and there is nothing preventing one from using = instead (regardless of the FastAPI version one might be using) - it serves the same purpose. In fact, there are cases, just like in Solution 1, where one needs to use = instead, as there stiil seem to be issues with Annotated.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.