{"detail":[{"type":"int_parsing","loc":["path","item_id"],"msg":"Input should be a valid integer, unable to parse string as an integer","input":"foo","url":"https://errors.pydantic.dev/2.1/v/int_parsing"}]}
because the path parameter item_id had a value of "foo", which is not an int.
When creating path operations, you can find situations where you have a fixed path.
Like /users/me, let's say that it's to get data about the current user.
And then you can also have a path /users/{user_id} to get data about a specific user by some user ID.
Because path operations are evaluated in order, you need to make sure that the path for /users/me is declared before the one for /users/{user_id}:
fromfastapiimportFastAPIapp=FastAPI()@app.get("/users/me")asyncdefread_user_me():return{"user_id":"the current user"}@app.get("/users/{user_id}")asyncdefread_user(user_id:str):return{"user_id":user_id}
Otherwise, the path for /users/{user_id} would match also for /users/me, "thinking" that it's receiving a parameter user_id with a value of "me".
If you have a path operation that receives a path parameter, but you want the possible valid path parameter values to be predefined, you can use a standard Python Enum.
Import Enum and create a sub-class that inherits from str and from Enum.
By inheriting from str the API docs will be able to know that the values must be of type string and will be able to render correctly.
Then create class attributes with fixed values, which will be the available valid values:
fromenumimportEnumfromfastapiimportFastAPIclassModelName(str,Enum):alexnet="alexnet"resnet="resnet"lenet="lenet"app=FastAPI()@app.get("/models/{model_name}")asyncdefget_model(model_name:ModelName):ifmodel_nameisModelName.alexnet:return{"model_name":model_name,"message":"Deep Learning FTW!"}ifmodel_name.value=="lenet":return{"model_name":model_name,"message":"LeCNN all the images"}return{"model_name":model_name,"message":"Have some residuals"}
Then create a path parameter with a type annotation using the enum class you created (ModelName):
fromenumimportEnumfromfastapiimportFastAPIclassModelName(str,Enum):alexnet="alexnet"resnet="resnet"lenet="lenet"app=FastAPI()@app.get("/models/{model_name}")asyncdefget_model(model_name:ModelName):ifmodel_nameisModelName.alexnet:return{"model_name":model_name,"message":"Deep Learning FTW!"}ifmodel_name.value=="lenet":return{"model_name":model_name,"message":"LeCNN all the images"}return{"model_name":model_name,"message":"Have some residuals"}
You can compare it with the enumeration member in your created enum ModelName:
fromenumimportEnumfromfastapiimportFastAPIclassModelName(str,Enum):alexnet="alexnet"resnet="resnet"lenet="lenet"app=FastAPI()@app.get("/models/{model_name}")asyncdefget_model(model_name:ModelName):ifmodel_nameisModelName.alexnet:return{"model_name":model_name,"message":"Deep Learning FTW!"}ifmodel_name.value=="lenet":return{"model_name":model_name,"message":"LeCNN all the images"}return{"model_name":model_name,"message":"Have some residuals"}
You can get the actual value (a str in this case) using model_name.value, or in general, your_enum_member.value:
fromenumimportEnumfromfastapiimportFastAPIclassModelName(str,Enum):alexnet="alexnet"resnet="resnet"lenet="lenet"app=FastAPI()@app.get("/models/{model_name}")asyncdefget_model(model_name:ModelName):ifmodel_nameisModelName.alexnet:return{"model_name":model_name,"message":"Deep Learning FTW!"}ifmodel_name.value=="lenet":return{"model_name":model_name,"message":"LeCNN all the images"}return{"model_name":model_name,"message":"Have some residuals"}
Tip
You could also access the value "lenet" with ModelName.lenet.value.
You can return enum members from your path operation, even nested in a JSON body (e.g. a dict).
They will be converted to their corresponding values (strings in this case) before returning them to the client:
fromenumimportEnumfromfastapiimportFastAPIclassModelName(str,Enum):alexnet="alexnet"resnet="resnet"lenet="lenet"app=FastAPI()@app.get("/models/{model_name}")asyncdefget_model(model_name:ModelName):ifmodel_nameisModelName.alexnet:return{"model_name":model_name,"message":"Deep Learning FTW!"}ifmodel_name.value=="lenet":return{"model_name":model_name,"message":"LeCNN all the images"}return{"model_name":model_name,"message":"Have some residuals"}
OpenAPI doesn't support a way to declare a path parameter to contain a path inside, as that could lead to scenarios that are difficult to test and define.
Nevertheless, you can still do it in FastAPI, using one of the internal tools from Starlette.
And the docs would still work, although not adding any documentation telling that the parameter should contain a path.