Fastapi: Not able to handle URL-encoded GET parameters - Response code 422 - Expected?

Created on 2 Sep 2020  路  10Comments  路  Source: tiangolo/fastapi

Is it expected that FastAPI cannot handle URL-encoded GET parameters? I searched the docs and via google but couldn't find any hints why this is or how to change the behaviour.

See the example below. I'm trying to pass float numbers as GET parameters with the . being URL-encoded. I'm getting the response that the number isn't a valid float.

Example

from pydantic import BaseModel
from fastapi import FastAPI

app = FastAPI()

class LongitudinalDiameterAndQuantity(BaseModel):
    diameter: float
    quantity_a: float
    quantity_b: float

@app.get("/column/longitudinal/diameter_quantity", response_model=LongitudinalDiameterAndQuantity)
def read_root(As: float, a: float, b: float):
    # TODO: Feed parameters into ML model and get results
    return LongitudinalDiameterAndQuantity(diameter=As, quantity_a=a, quantity_b=b)

Description

Non-URL-Encoded - working

URL: http://localhost:8000/column/longitudinal/diameter_quantity?As=1.2&a=1.2&b=1.2
As expected: Response code 200, content: {"diameter":1.2,"quantity_a":1.2,"quantity_b":1.2}

URL-Encoded - not working

URL: http://localhost:8000/column/longitudinal/diameter_quantity?As=1%2C2&a=1%2C2&b=1%2C2
Not expected: Response code 422, content:

{
   "detail":[
      {
         "loc":[
            "query",
            "As"
         ],
         "msg":"value is not a valid float",
         "type":"type_error.float"
      },
      {
         "loc":[
            "query",
            "a"
         ],
         "msg":"value is not a valid float",
         "type":"type_error.float"
      },
      {
         "loc":[
            "query",
            "b"
         ],
         "msg":"value is not a valid float",
         "type":"type_error.float"
      }
   ]
}

Environment

  • OS: Windows 10 64 bit
  • Python: 3.8.3
  • FastAPI: 0.61.1
question

Most helpful comment

Ooooooooooooh. I missunderstood the whole question

Haha, no problem 馃槃

Thanks for the hint regarding xxd 馃憤

All 10 comments

If there is not a special reason, declare and return your models like this

from pydantic import BaseModel
from fastapi import FastAPI

app = FastAPI()

class LongitudinalDiameterAndQuantity(BaseModel):
    diameter: float
    quantity_a: float
    quantity_b: float

@app.get("/column/longitudinal/diameter_quantity", response_model=LongitudinalDiameterAndQuantity)
def read_root(model: LongitudinalDiameterAndQuantity):
    return model

Thanks ycd. The reason is, that the code is not complete. Actually later the input parameters will not be directly used as output parameters. What I could have done is have a separate model for the input data maybe.

@MarcelKr you can still use the parameters with model.diameter etc.

Just tried the modifications you propose. The problem is, that FastAPI is interpreting def read_root(model: LongitudinalDiameterAndQuantity): as needing a request body. However a request body for GET isn't allowed.

So to circumvent the problem I might switch to a POST with JSON body for now. However this is not a clean solution I think :/

@MarcelKr try this

from fastapi import Depends

def read_root(model: LongitudinalDiameterAndQuantity = Depends())

Thanks again @ycd, but I feel that we're avoiding the actual problem or question I'm having.

However I think I found the answer: It seems that the Library I'm using - or rather the C# code generated from swagger - is using , instead of . as decimal separator when generating the GET parameters. URL-encoding , results in %2C (I initially thought that %2C is .). Obviously FastAPI or Python is expecting floats with a . instead of a ,. So that's why it generates the error message value is not a valid float.

To test this I created an endpoint like this:

@app.get("/test")
def read_test(test: str):
    return test

Using the built-in /docs/ to test it. Putting in . is never encoded, but , for instance is encoded as %2C (or ? -> %3F) and it's correctly returned. So it seems that FastAPI is handling the encoding correctly and the root cause was simply using , instead of . for decimal separation by my swagger-generated client API.

So I'll double check the swagger-codegen why they generate , instead of . which is quite qeird I think.

Ooooooooooooh. I missunderstood the whole question, :disappointed: i think If you use %2E it 'd be fine.

Also you can check a character's hexadecimal equivalent with

echo -n . | xxd -p

2e

Ooooooooooooh. I missunderstood the whole question

Haha, no problem 馃槃

Thanks for the hint regarding xxd 馃憤

The problem (using , instead of . in the query string) seems to be originating from the RestSharp library which is used by the C# code generated from Swagger. When generating the URLs the current locale is taken into account. On my system (german locale), the decimal separator is a ,. When I set the locale to invariant it's using . as expected. Who would have thought that? 馃う

Thanks for the help here @ycd ! :clap: :bow:

Thanks for reporting back and closing the issue @MarcelKr :+1:

Was this page helpful?
0 / 5 - 0 ratings