{"detail":[{"type":"int_parsing","loc":["path","item_id"],"msg":"Input should be a valid integer, unable to parse string as an integer","input":"foo"}]}
porque el parámetro de ruta item_id tenía un valor de "foo", que no es un int.
Al crear operaciones de ruta, puedes encontrarte con situaciones donde tienes una ruta fija.
Como /users/me, digamos que es para obtener datos sobre el usuario actual.
Y luego también puedes tener una ruta /users/{user_id} para obtener datos sobre un usuario específico por algún ID de usuario.
Como las operaciones de ruta se evalúan en orden, necesitas asegurarte de que la ruta para /users/me se declare antes que la de /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}
De lo contrario, la ruta para /users/{user_id} también coincidiría con /users/me, "pensando" que está recibiendo un parámetro user_id con un valor de "me".
De manera similar, no puedes redefinir una operación de ruta:
Si tienes una operación de ruta que recibe un parámetro de ruta, pero quieres que los posibles valores válidos del parámetro de ruta estén predefinidos, puedes usar un Enum estándar de Python.
Importa Enum y crea una subclase que herede de str y de Enum.
Al heredar de str la documentación de la API podrá saber que los valores deben ser de tipo string y podrá renderizarse correctamente.
Luego crea atributos de clase con valores fijos, que serán los valores válidos disponibles:
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"}
Consejo
Si te lo preguntas, "AlexNet", "ResNet", y "LeNet" son solo nombres de modelos de Machine Learning.
Luego crea un parámetro de ruta con una anotación de tipo usando la clase enum que creaste (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"}
Puedes compararlo con el miembro de enumeración en tu enum creado 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"}
Puedes obtener el valor real (un str en este caso) usando model_name.value, o en 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"}
Consejo
También podrías acceder al valor "lenet" con ModelName.lenet.value.
Puedes devolver miembros de enum desde tu operación de ruta, incluso anidados en un cuerpo JSON (por ejemplo, un dict).
Se convertirán a sus valores correspondientes (cadenas en este caso) antes de devolverlos al cliente:
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 no soporta una forma de declarar un parámetro de ruta que contenga una ruta dentro, ya que eso podría llevar a escenarios difíciles de probar y definir.
Sin embargo, aún puedes hacerlo en FastAPI, usando una de las herramientas internas de Starlette.
Y la documentación seguiría funcionando, aunque sin añadir ninguna documentación que indique que el parámetro debe contener una ruta.