728x90
반응형

API을 사용하는 클라이언트에 오류를 알려야 하는 상황이 많이 있습니다.

 

이 클라이언트는 프론트엔드인 브라우저는 물론 IoT 기기, 기타 등등 다른 곳의 코드가 될 수도 있습니다.

 

클라이언트에 아래와 같은 내용을 알려줘야 합니다:

 

  • 클라이언트는 해당 작업에 대한 충분한 권한이 없습니다.
  • 클라이언트는 자원에 접근할 수 없습니다.
  • 클라이언트가 접근하고자 시도하는 아이템이 존재하지 않습니다.
  • 기타 등등.

 

이러한 경우, 보통 400 범위 내 (400부터 499까지) HTTP 상태 코드를 반환합니다.

 

이것은 (200부터 299까지의) 200 HTTP 상태 코드에도 유사합니다. "200" 상태 코드는 요청이 어떻게든 "성공"했다는 걸 의미합니다.

 

400 범위 내의 상태 코드는 클라이언트에 오류가 있다는 걸 의미합니다.

 

모든 "404 찾지 못함(Not Found)" 오류 (그리고 농담)을 기억하십니까?

 

HTTPException 사용

클라이언트에 오류와 함께 HTTP 응답을 반환하기 위해 HTTPException 을 사용합니다.

 

HTTPExepction 임포트

 

코드에서의 HTTPException 발생

HTTPException 은 API와 연관된 추가 데이터를 사용하는 보통의 파이썬 예외입니다.

 

파이썬 예외이기 때문에, return 하지 않고, raise 합니다.

 

이것은 또한 경로 동작 함수 내부에서 호출하는 유틸리티 함수 내부에 있고, 그 유틸리티 함수 내부로부터 HTTPException 를 발생시키는 경우, 경로 동작 함수의 나머지 코드를 실행하지 않고, 해당 요청을 즉시 종료시키며 HTTPException 으로부터 HTTP 오류를 클라이언트에 전송하는 걸 의미합니다.

 

값을 return 하는 것보다 예외를 발생시키는 것이 이점인 이유는 의존성 및 보안 섹션에서 더 구체적으로 다룰 것입니다.

 

이 예시에서, 클라이언트가 존재하지 않는 ID로 아이템을 요청한다면, 404 상태 코드와 함께 예외를 발생시킵니다:

 

 

결과 응답

만약 클라이언트가 ( item_id"foo" 인 ) http://example.com/items/foo 에 요청한다면, 그 클라이언트는 HTTP 상태 코드 200 및, 아래와 같은 JSON 응답을 전달 받을 것입니다:

 

 

그러나 만약 클라이언트가 (존재하지 않는 item_id"bar" ) http://example.com/items/bar 에 요청한다면, 그 클라이언트는 ("찾지 못함(not found)" 오류를 의미하는) HTTP 상태 코드 404 및, 아래와 같은 JSON 응답을 전달 받을 것입니다:

 

 



HTTPException 을 발생시켰을 때, str 뿐만 아니라, JSON으로 변환될 수 있는 어떤 변수도 매개변수 detail 로 전달 할 수 있습니다.

예를 들어 dict , list , 기타 등등을 전달할 수 있습니다.

FastAPI에 의해 자동으로 처리되고 JSON으로 변환됩니다.

 

사용자 정의 헤더 추가

HTTP 오류에 사용자 정의 헤더를 추가할 수 있는 게 유용한 몇 가지 상황이 있습니다. 예를 들어, 일부 보안 유형입니다.

 

아마 코드 내부에 직접 사용하고 싶지 않을 것입니다.

 

그러나 더 숙련된 상황에 필요한 경우, 사용자 정의 헤더를 추가할 수 있습니다.

 

 

사용자 정의 예외 핸들러 설치

Starlette의 동일한 예외 유틸리티를 사용하여 사용자 정의 예외 핸들러를 추가할 수 있습니다.

 

당신 (또는 라이브러리가) raise 할 사용자 정의 예외 UnicornException 이 있다고 가정해봅시다.

 

그리고 FastAPI와 함께 이 예외를 전역적으로 다루기를 원합니다.

 

@app.exception_handler() 를 사용하여 사용자 정의 예외 핸들러를 추가할 수 있습니다:

 

 

여기서, 만약 /unicorns/yolo 에 요청을 보내면, 경로 동작은 UnicornExceptionraise 합니다.

 

그러나 이것은 unicorn_exception_handler 에 의해 처리됩니다.

 

따라서, HTTP 상태 코드 418 과 아래와 같은 JSON 콘텐츠와 함께, 깔끔한 오류를 전달 받게 됩니다.

 

 

기술적 세부사항

from starlette.requests import Requestfrom starlette.responses import JSONResponse 를 사용할 수 있습니다.

FastAPI는 개발자의 편의성을 위해 starlette.responses 와 동일한 fastapi.responses 를 제공합니다. 그러나 대부분의 사용가능한 응답은 Starlette으로부터 직접 전달 받습니다.

 

기본 예외 핸들러 재정의

FastAPI는 기본 예외 핸들러를 가지고 있습니다.

 

이 핸들러는 HTTPExceptionraise 하고 요청이 유효하지 않은 데이터일 때 기본 JSON 응답을 반환하도록 되어 있습니다.

 

이러한 예외 핸들러를 본인의 것으로 재정의할 수 있습니다.

 

요청 유효성 검사 예외 재정의

요청에 유효하지 않은 데이터가 포함되어 있을 때, FastAPI는 내부적으로 RequestValidationError 를 발생시킵니다.

 

그리고 이를 위한 기본 예외 핸들러를 포함하고 있습니다.

 

이를 재정의하기 위해서는, RequestValidationError 를 임포트하고 @app.exception_handler(RequestValidationError) 와 함께 사용해서 예외 핸들러에 데코레이트해야 합니다.

 

예외 핸들러는 Request 와 예외를 전달 받습니다.

 

 

이제, /items/foo 로 이동하면, 아래와 같이 기본 JSON 오류를 얻는 것 대신:

 

 

아래와 같은 텍스트 버전을 얻을 수 있습니다:

 

 

RequestValidationError vs ValidationError

주의

지금 당장 중요하지 않다면 이 기술적 세부사항은 건너 뛰셔도 좋습니다.

 

RequestValidationError 는 Pydantic의 ValidationError 의 서브-클래스 입니다.

 

FastAPI는 이를 사용하므로, 만약 response_model 속 Pydantic 모델을 사용하고, 데이터에 오류가 존재한다면, 로그에서 그 오류를 확인할 수 있습니다.

 

그러나 클라이언트/사용자는 이를 볼 수 없습니다. 대신, 클라이언트는 HTTP 상태 코드 500 과 함께 "내부 서버 오류"를 전달 받게 됩니다.

 

이렇게 동작하는 이유는, Pydantic ValidationError 가 (클라이언트의 요청이 아닌) 응답 또는 코드 내부 어딘가에 존재한다면, 실제로 코드 내부의 버그이기 때문입니다.

 

그리고 이를 고칠 때, 클라이언트/사용자는, 보안 취약점을 노출할 수 있기 때문에 오류에 관한 내부 정보에 접근하면 안됩니다.

 

HTTPExceiption 오류 핸들러 재정의

동일한 방법으로, HTTPException 핸들러를 재정의할 수 있습니다.

 

예를 들어, 오류에 대해 JSON 대신 순수 텍스트 응답을 반환하고 싶을 수 있습니다:

 

 

기술적 세부사항

from starlette.response import PlainTextRespons 를 사용할 수 있습니다.

FastAPI는 개발자의 편의성을 위해 starlette.responses 와 동일한 fastapi.responses 를 제공합니다. 그러나 대부분의 사용가능한 응답은 Starlette으로부터 직접 전달 받습니다.

 

RequestValidationError 바디 사용

RequestValidationError 는 유효하지 않는 데이터를 전달 받은 body 를 포함합니다.

 

애플리케이션을 개발할 때 이것을 바디에 관한 로그를 남기고 디버깅하며, 사용자에게 반환하는 등으로 사용할 수 있습니다.

 

 

이제 아래와 같이 유효하지 않은 아이템 송신을 시도해보기 바랍니다:

 

 

전달 받은 바디가 포함된 데이터가 유효하지 않다는 걸 알려주는 응답을 전달 받습니다:

 

 

FastAPI의 HTTPException vs Starlette의 HTTPException

FastAPI에는 본인만의 HTTPException 이 존재합니다.

 

그리고 FastAPIHTTPException 오류 클래스는 StarletteHTTPException 오류 클래스를 상속 받습니다.

 

유일한 차이점은, FastAPIHTTPException 은 응답에 헤더가 포함되게 추가할 수 있다는 것입니다.

 

이것은 OAuth 2.0 및 몇몇의 보안 유틸리티에 내부적으로 요구/사용됩니다.

 

따라서, 코드에 평소와 같이 FastAPIHTTPException 을 계속 발생시킬 수 있습니다.

 

그러나 예외 핸들러를 등록할 때 Starlette의 HTTPException 에 대해 등록해야 합니다.

 

이 방법을 통해, 만약 Starlette 내부 코드의 어떤 부분이라도, 또는 Starlette 확장 및 플러그 인이 Starlette HTTPException 을 발생시킨다면, 처리기는 오류를 잡고 다룰 수 있습니다.

 

이 예시에서, Starlette의 예외를 StarletteHTTPException 이라 재명명하여, 두 HTTPException 을 모두 동일한 코드 내에서 사용할 수 있게 하였습니다.

 

 

FastAPI 예외 핸들러 재사용

어떻게든 예외만을 사용하고 싶지만, FastAPI로부터 동일한 기본 예외 핸들러를 사용하고 싶을 수 있습니다.

 

fastapi.exception_handlers 로부터 기본 예외 핸들러를 임포트하고 재사용할 수 있습니다.

 

 

이 예시에서, 단지 표현이 풍부한 메세지와 함께 오류를 print 할 뿐입니다.

 

그러나 이로부터 아이디어를 얻어, 예외를 사용하고 기본 예외 핸들러를 재사용할 수 있습니다.

 


원문

https://fastapi.tiangolo.com/tutorial/handling-errors/

 

Handling Errors - FastAPI

Handling Errors There are many situations in where you need to notify an error to a client that is using your API. This client could be a browser with a frontend, a code from someone else, an IoT device, etc. You could need to tell the client that: The cli

fastapi.tiangolo.com

728x90
반응형

'FastAPI > Tutorial - User Guide' 카테고리의 다른 글

[ FastAPI ] JSON 호환 부호화  (0) 2021.10.03
[ FastAPI ] 경로 동작 구성  (0) 2021.10.01
[ FastAPI ] 요청 폼과 파일  (0) 2021.09.27
[ FastAPI ] 요청 파일  (0) 2021.09.27
[ FastAPI ] 폼 데이터  (0) 2021.09.25