Movatterモバイル変換


[0]ホーム

URL:


Saltar a contenido
Join theFastAPI Cloud waiting list 🚀
Follow@fastapi onX (Twitter) to stay updated
FollowFastAPI onLinkedIn to stay updated
Subscribe to theFastAPI and friends newsletter 🎉
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor

Manejo de Errores

🌐 Traducción por IA y humanos

Esta traducción fue hecha por IA guiada por humanos. 🤝

Podría tener errores al interpretar el significado original, o sonar poco natural, etc. 🤖

Puedes mejorar esta traducciónayudándonos a guiar mejor al LLM de IA.

Versión en inglés

Existen muchas situaciones en las que necesitas notificar un error a un cliente que está usando tu API.

Este cliente podría ser un navegador con un frontend, un código de otra persona, un dispositivo IoT, etc.

Podrías necesitar decirle al cliente que:

  • El cliente no tiene suficientes privilegios para esa operación.
  • El cliente no tiene acceso a ese recurso.
  • El ítem al que el cliente intentaba acceder no existe.
  • etc.

En estos casos, normalmente devolverías uncódigo de estado HTTP en el rango de400 (de 400 a 499).

Esto es similar a los códigos de estado HTTP 200 (de 200 a 299). Esos códigos de estado "200" significan que de alguna manera hubo un "éxito" en el request.

Los códigos de estado en el rango de 400 significan que hubo un error por parte del cliente.

¿Recuerdas todos esos errores de"404 Not Found" (y chistes)?

UsaHTTPException

Para devolver responses HTTP con errores al cliente, usaHTTPException.

ImportaHTTPException

fromfastapiimportFastAPI,HTTPExceptionapp=FastAPI()items={"foo":"The Foo Wrestlers"}@app.get("/items/{item_id}")asyncdefread_item(item_id:str):ifitem_idnotinitems:raiseHTTPException(status_code=404,detail="Item not found")return{"item":items[item_id]}

Lanza unHTTPException en tu código

HTTPException es una excepción de Python normal con datos adicionales relevantes para APIs.

Debido a que es una excepción de Python, no lareturn, sino que laraise.

Esto también significa que si estás dentro de una función de utilidad que estás llamando dentro de tupath operation function, y lanzas elHTTPException desde dentro de esa función de utilidad, no se ejecutará el resto del código en lapath operation function, terminará ese request de inmediato y enviará el error HTTP delHTTPException al cliente.

El beneficio de lanzar una excepción en lugar dereturnar un valor será más evidente en la sección sobre Dependencias y Seguridad.

En este ejemplo, cuando el cliente solicita un ítem por un ID que no existe, lanza una excepción con un código de estado de404:

fromfastapiimportFastAPI,HTTPExceptionapp=FastAPI()items={"foo":"The Foo Wrestlers"}@app.get("/items/{item_id}")asyncdefread_item(item_id:str):ifitem_idnotinitems:raiseHTTPException(status_code=404,detail="Item not found")return{"item":items[item_id]}

El response resultante

Si el cliente solicitahttp://example.com/items/foo (unitem_id"foo"), ese cliente recibirá un código de estado HTTP de 200, y un response JSON de:

{"item":"The Foo Wrestlers"}

Pero si el cliente solicitahttp://example.com/items/bar (unitem_id inexistente"bar"), ese cliente recibirá un código de estado HTTP de 404 (el error "no encontrado"), y un response JSON de:

{"detail":"Item not found"}

Consejo

Cuando lanzas unHTTPException, puedes pasar cualquier valor que pueda convertirse a JSON como el parámetrodetail, no solostr.

Podrías pasar undict, unlist, etc.

Son manejados automáticamente porFastAPI y convertidos a JSON.

Agrega headers personalizados

Existen algunas situaciones en las que es útil poder agregar headers personalizados al error HTTP. Por ejemplo, para algunos tipos de seguridad.

Probablemente no necesitarás usarlos directamente en tu código.

Pero en caso de que los necesites para un escenario avanzado, puedes agregar headers personalizados:

fromfastapiimportFastAPI,HTTPExceptionapp=FastAPI()items={"foo":"The Foo Wrestlers"}@app.get("/items-header/{item_id}")asyncdefread_item_header(item_id:str):ifitem_idnotinitems:raiseHTTPException(status_code=404,detail="Item not found",headers={"X-Error":"There goes my error"},)return{"item":items[item_id]}

Instalar manejadores de excepciones personalizados

Puedes agregar manejadores de excepciones personalizados conlas mismas utilidades de excepciones de Starlette.

Supongamos que tienes una excepción personalizadaUnicornException que tú (o un paquete que usas) podrías lanzar.

Y quieres manejar esta excepción globalmente con FastAPI.

Podrías agregar un manejador de excepciones personalizado con@app.exception_handler():

fromfastapiimportFastAPI,Requestfromfastapi.responsesimportJSONResponseclassUnicornException(Exception):def__init__(self,name:str):self.name=nameapp=FastAPI()@app.exception_handler(UnicornException)asyncdefunicorn_exception_handler(request:Request,exc:UnicornException):returnJSONResponse(status_code=418,content={"message":f"Oops!{exc.name} did something. There goes a rainbow..."},)@app.get("/unicorns/{name}")asyncdefread_unicorn(name:str):ifname=="yolo":raiseUnicornException(name=name)return{"unicorn_name":name}

Aquí, si solicitas/unicorns/yolo, lapath operation lanzará unUnicornException.

Pero será manejado por elunicorn_exception_handler.

Así que recibirás un error limpio, con un código de estado HTTP de418 y un contenido JSON de:

{"message":"Oops! yolo did something. There goes a rainbow..."}

Nota Técnica

También podrías usarfrom starlette.requests import Request yfrom starlette.responses import JSONResponse.

FastAPI ofrece las mismasstarlette.responses comofastapi.responses solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles vienen directamente de Starlette. Lo mismo conRequest.

Sobrescribir los manejadores de excepciones predeterminados

FastAPI tiene algunos manejadores de excepciones predeterminados.

Estos manejadores se encargan de devolver los responses JSON predeterminadas cuando lanzas unHTTPException y cuando el request tiene datos inválidos.

Puedes sobrescribir estos manejadores de excepciones con los tuyos propios.

Sobrescribir excepciones de validación de request

Cuando un request contiene datos inválidos,FastAPI lanza internamente unRequestValidationError.

Y también incluye un manejador de excepciones predeterminado para ello.

Para sobrescribirlo, importa elRequestValidationError y úsalo con@app.exception_handler(RequestValidationError) para decorar el manejador de excepciones.

El manejador de excepciones recibirá unRequest y la excepción.

fromfastapiimportFastAPI,HTTPExceptionfromfastapi.exceptionsimportRequestValidationErrorfromfastapi.responsesimportPlainTextResponsefromstarlette.exceptionsimportHTTPExceptionasStarletteHTTPExceptionapp=FastAPI()@app.exception_handler(StarletteHTTPException)asyncdefhttp_exception_handler(request,exc):returnPlainTextResponse(str(exc.detail),status_code=exc.status_code)@app.exception_handler(RequestValidationError)asyncdefvalidation_exception_handler(request,exc:RequestValidationError):message="Validation errors:"forerrorinexc.errors():message+=f"\nField:{error['loc']}, Error:{error['msg']}"returnPlainTextResponse(message,status_code=400)@app.get("/items/{item_id}")asyncdefread_item(item_id:int):ifitem_id==3:raiseHTTPException(status_code=418,detail="Nope! I don't like 3.")return{"item_id":item_id}

Ahora, si vas a/items/foo, en lugar de obtener el error JSON por defecto con:

{"detail":[{"loc":["path","item_id"],"msg":"value is not a valid integer","type":"type_error.integer"}]}

obtendrás una versión en texto, con:

Validation errors:Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to parse string as an integer

Sobrescribir el manejador de errores deHTTPException

De la misma manera, puedes sobrescribir el manejador deHTTPException.

Por ejemplo, podrías querer devolver un response de texto plano en lugar de JSON para estos errores:

fromfastapiimportFastAPI,HTTPExceptionfromfastapi.exceptionsimportRequestValidationErrorfromfastapi.responsesimportPlainTextResponsefromstarlette.exceptionsimportHTTPExceptionasStarletteHTTPExceptionapp=FastAPI()@app.exception_handler(StarletteHTTPException)asyncdefhttp_exception_handler(request,exc):returnPlainTextResponse(str(exc.detail),status_code=exc.status_code)@app.exception_handler(RequestValidationError)asyncdefvalidation_exception_handler(request,exc:RequestValidationError):message="Validation errors:"forerrorinexc.errors():message+=f"\nField:{error['loc']}, Error:{error['msg']}"returnPlainTextResponse(message,status_code=400)@app.get("/items/{item_id}")asyncdefread_item(item_id:int):ifitem_id==3:raiseHTTPException(status_code=418,detail="Nope! I don't like 3.")return{"item_id":item_id}

Nota Técnica

También podrías usarfrom starlette.responses import PlainTextResponse.

FastAPI ofrece las mismasstarlette.responses comofastapi.responses solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles vienen directamente de Starlette.

Advertencia

Ten en cuenta queRequestValidationError contiene la información del nombre de archivo y la línea donde ocurre el error de validación, para que puedas mostrarla en tus logs con la información relevante si quieres.

Pero eso significa que si simplemente lo conviertes a un string y devuelves esa información directamente, podrías estar filtrando un poquito de información sobre tu sistema, por eso aquí el código extrae y muestra cada error de forma independiente.

Usar el body deRequestValidationError

ElRequestValidationError contiene elbody que recibió con datos inválidos.

Podrías usarlo mientras desarrollas tu aplicación para registrar el body y depurarlo, devolverlo al usuario, etc.

fromfastapiimportFastAPI,Requestfromfastapi.encodersimportjsonable_encoderfromfastapi.exceptionsimportRequestValidationErrorfromfastapi.responsesimportJSONResponsefrompydanticimportBaseModelapp=FastAPI()@app.exception_handler(RequestValidationError)asyncdefvalidation_exception_handler(request:Request,exc:RequestValidationError):returnJSONResponse(status_code=422,content=jsonable_encoder({"detail":exc.errors(),"body":exc.body}),)classItem(BaseModel):title:strsize:int@app.post("/items/")asyncdefcreate_item(item:Item):returnitem

Ahora intenta enviar un ítem inválido como:

{"title":"towel","size":"XL"}

Recibirás un response que te dirá que los datos son inválidos conteniendo el body recibido:

{"detail":[{"loc":["body","size"],"msg":"value is not a valid integer","type":"type_error.integer"}],"body":{"title":"towel","size":"XL"}}

HTTPException de FastAPI vsHTTPException de Starlette

FastAPI tiene su propioHTTPException.

Y la clase de errorHTTPException deFastAPI hereda de la clase de errorHTTPException de Starlette.

La única diferencia es que elHTTPException deFastAPI acepta cualquier dato JSON-able para el campodetail, mientras que elHTTPException de Starlette solo acepta strings para ello.

Así que puedes seguir lanzando unHTTPException deFastAPI como de costumbre en tu código.

Pero cuando registras un manejador de excepciones, deberías registrarlo para elHTTPException de Starlette.

De esta manera, si alguna parte del código interno de Starlette, o una extensión o plug-in de Starlette, lanza unHTTPException de Starlette, tu manejador podrá capturarlo y manejarlo.

En este ejemplo, para poder tener ambosHTTPException en el mismo código, las excepciones de Starlette son renombradas aStarletteHTTPException:

fromstarlette.exceptionsimportHTTPExceptionasStarletteHTTPException

Reutilizar los manejadores de excepciones deFastAPI

Si quieres usar la excepción junto con los mismos manejadores de excepciones predeterminados deFastAPI, puedes importar y reutilizar los manejadores de excepciones predeterminados defastapi.exception_handlers:

fromfastapiimportFastAPI,HTTPExceptionfromfastapi.exception_handlersimport(http_exception_handler,request_validation_exception_handler,)fromfastapi.exceptionsimportRequestValidationErrorfromstarlette.exceptionsimportHTTPExceptionasStarletteHTTPExceptionapp=FastAPI()@app.exception_handler(StarletteHTTPException)asyncdefcustom_http_exception_handler(request,exc):print(f"OMG! An HTTP error!:{repr(exc)}")returnawaithttp_exception_handler(request,exc)@app.exception_handler(RequestValidationError)asyncdefvalidation_exception_handler(request,exc):print(f"OMG! The client sent invalid data!:{exc}")returnawaitrequest_validation_exception_handler(request,exc)@app.get("/items/{item_id}")asyncdefread_item(item_id:int):ifitem_id==3:raiseHTTPException(status_code=418,detail="Nope! I don't like 3.")return{"item_id":item_id}

En este ejemplo solo estásprinteando el error con un mensaje muy expresivo, pero te haces una idea. Puedes usar la excepción y luego simplemente reutilizar los manejadores de excepciones predeterminados.


[8]ページ先頭

©2009-2026 Movatter.jp