{"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"}]}
porque el parámetro de path item_id tenía un valor de "foo", que no es un int.
Y cuando abras tu navegador en http://127.0.0.1:8000/docs, verás una documentación de API automática e interactiva como:
Revisa
Nuevamente, solo con esa misma declaración de tipo de Python, FastAPI te ofrece documentación automática e interactiva (integrando Swagger UI).
Nota que el parámetro de path está declarado como un entero.
Beneficios basados en estándares, documentación alternativa¶
Y porque el esquema generado es del estándar OpenAPI, hay muchas herramientas compatibles.
Debido a esto, el propio FastAPI proporciona una documentación de API alternativa (usando ReDoc), a la cual puedes acceder en http://127.0.0.1:8000/redoc:
De la misma manera, hay muchas herramientas compatibles. Incluyendo herramientas de generación de código para muchos lenguajes.
Al crear path operations, puedes encontrarte en situaciones donde tienes un path fijo.
Como /users/me, imaginemos que es para obtener datos sobre el usuario actual.
Y luego también puedes tener un path /users/{user_id} para obtener datos sobre un usuario específico por algún ID de usuario.
Debido a que las path operations se evalúan en orden, necesitas asegurarte de que el path para /users/me se declara antes que el 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, el path para /users/{user_id} también coincidiría para /users/me, "pensando" que está recibiendo un parámetro user_id con un valor de "me".
De manera similar, no puedes redefinir una path operation:
Si tienes una path operation que recibe un path parameter, pero quieres que los valores posibles válidos del path parameter 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á representarlos 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"}
Luego crea un path parameter 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 creada 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 actual (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 path operation, incluso anidados en un cuerpo JSON (por ejemplo, un dict).
Serán convertidos 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 manera de declarar un path parameter para que contenga un path dentro, ya que eso podría llevar a escenarios que son difíciles de probar y definir.
Sin embargo, todavía puedes hacerlo en FastAPI, usando una de las herramientas internas de Starlette.
Y la documentación seguiría funcionando, aunque no agregue ninguna documentación indicando que el parámetro debe contener un path.