내가 마주친 422 에러 (FastAPI)

개발 끄적끄적 .. ✍️·2021년 12월 21일
3

로컬 환경에서 api 요청을 테스트하기 위해 포스트 맨에서 FastAPI 서버로 http 요청을 보냈더니 아래와 같은 return 값을 받게 되었다.

{
    "result": null,
    "processTime": 0.011934995651245117,
    "message": "Unprocessable Entity",
    "code": 422
}

422 Unprocessable Entity

  • MDN Web Docs를 참조하니 아래와 같은 답을 얻을 수 있었다.

    이 응답은 서버가 요청을 이해하고 요청 문법도 올바르지만 요청된 지시를 따를 수 없음을 나타냅니다.

  • 서버도 내 요청을 받았고.. 문법도 올바르지 않지만 요청된 지시를 따를 수 없다 ..?

내가 겪은 422에러 1

  • 생각보다 에러의 원인을 찾기 쉬웠다. 에러의 원인은 요청하는 api의 파라미터에 대한 validation 문제였다(좀 더 정확히는 response Model)
  • FastAPI에서는 api 파라미터들에 대한 타입 힌트를 설정할 뿐 만 아니라 그것을 통해 타입에 대한 validation이 진행된다.
  • 정말 단순하게 api 요청 controller를 작성해보았다.
    @app.router.get('/log/{age}', tags=['age'])
    async def get_log_by_age(self, age: int):
    	    response = await appHandler.get_log_by_age(age:int)
          return {'result': response, 'message': '', 'code': 200}
  • 예를 들어 age에 따른 log를 조회하는 api를 작성 한다고 할 때 controller 단에서 입력 파라미터들에 대한 validation을 진행한다. age의 경우 int형의 타입을 받지만 클라이언트가 실수로 float나 string 타입의 데이터를 입력할 경우 422 Unprocessable Entity 에러를 반환한다.

내가 겪은 422에러 2

  • 분명히 요청 파리미터에 대한 validation도 정확하고 이상이 없었지만 다시 한 번 422 Unprocessable Entity를 만나게 되었다.
  • 결국 돌고 돌아 validation문제지만 상황이 조금은 다른다
  • 예를 들어 controller 에는 다양한 요청을 처리하는 func()이 있다
    @app.router.get('/log/{age}', tags=['age'])
    async def get_log_by_age(self, age: int):
    	    response = await appHandler.get_log_by_age(age:int)
          return {'result': response, 'message': '', 'code': 200}
    
    @app.router.get('/log/region', tags=['region'])
    async def get_log_by_region(self, age: int):
    	    response = await appHandler.get_log_by_region(region: string = 'seoul')
          return {'result': response, 'message': '', 'code': 200}
  • 알고보니 path parameter로 region이 있고 query parameter로 지역명을 받는(default = 'seoul') api요청 핸들러 func()이 같은 controller 스크립트 에 있다면, /log/region?region=seoul 이 api 요청은 (정상적으로 요청이 진행되었다면) 422 Unprocessable Entity를 반환할 것이다.
  • 이유는 /log/region?region=seoul의 /region 이 path parameter 부분이 /log/{age} 의 age: int로 인식되어 422 Unprocessable Entity를 return 한다.

해결책

  • 이러한 문제는 api 요청 핸들러 func()의 순서를 바꿔주면 간단하게 해결 된다
    @app.router.get('/log/region', tags=['region'])
    async def get_log_by_region(self, age: int):
    	    response = await appHandler.get_log_by_region(region: string = 'seoul')
          return {'result': response, 'message': '', 'code': 200}
    
    @app.router.get('/log/{age}', tags=['age'])
    async def get_log_by_age(self, age: int):
    	    response = await appHandler.get_log_by_age(age:int)
          return {'result': response, 'message': '', 'code': 200}
  • 이렇게 핸들러 func()의 순서를 바꾸게 되면 FastAPI가 요청 핸들러를 찾을 때 이상 없이 handler를 찾을 수 있다.

2개의 댓글

comment-user-thumbnail
2022년 3월 21일

도움이 되었네요. 감사합니다~

답글 달기
comment-user-thumbnail
2023년 8월 2일

422 에러는 처음 봤는데, FastAPI 특성에 따른 문제였나보군요. 잘 보고 갑니다!

답글 달기