Post

fastapi Swagger Response 분리하기

개요

fastapi 를 사용하고 있는데, fastapi 공식문서를 따라가면서 swagger문서를 작성하다보니 불편함을 느꼈다.

그것은 바로

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
@router.get("/ingredient",
            responses={
                status.HTTP_200_OK: {
                    "description": "재료 조회 성공",
                    "content": {
                        "application/json": {
                            "example": {
                                "code": 200,
                                "message": "Success",
                                "data": [
                                    {
                                        "ingredient_name": "당근",
                                        "ingredient_url": "https://default.image"
                                    },
                                    {
                                        "ingredient_name": "토마토",
                                        "ingredient_url": "https://default.image"
                                    },
                                    {
                                        "ingredient_name": "치즈",
                                        "ingredient_url": "https://default.image"
                                    }
                                ]
                            }
                        }
                    }
                },
                status.HTTP_401_UNAUTHORIZED: {"description": "토큰 에러",
                                               "content": {
                                                   "application/json": {
                                                       "example": {
                                                           "code": 401,
                                                           "message": "Parsing Error token",
                                                           "data": None
                                                       }
                                                   }
                                               }
                                               }
            }
            )
async def search_ingredient_history(
        db: Session = Depends(get_db),
        user: Optional[UserResponseByToken] = Depends(get_current_user_authorizer())
):
    return StandardizedResponse(code=200, data=await user_service.search_ingredient_history(db, user))

이런 코드들이 Controller에 너무 많이 있었다.

뭐가 불편한가?

service를 호출하는 코드는 return StandardizedResponse(code=200, data=await user_service.search_ingredient_history(db, user))단 한 줄인데 swagger를 작성하는 코드는 약 40줄에 달한다.

배보다 배꼽이 더 큰 상황인데, 이런 코드들이 점점 많아지니까 스웨거를 자세히 작성하는데에 불편함도 느끼고 함수를 찾아가는데에도 번거로움을 느꼈다. 무엇보다 정리되지 않은 느낌이 싫었다.

해결방법

분리하기 위해서는 2가지 방법이 있었다.

  1. 직접 .yml파일을 작성하고, 해당 파일을 명시하는 방법
  2. 함수형태로 호출

각각 장단점이 있는데, .yml파일을 작성하면 간결하게 읽을 수 있겠지만 모델이 변경하는 등의 수정작업이 있으면 .yml파일도 같이 수정해줘야한다.

함수호출형태는 수정작업이 이루어져도 모델을 참조하고 있기에 관리가 용이하지만 파일이 늘어난다는 단점이 있다.

나는 관리포인트를 최소화하고 싶어서 함수호출형태로 변경하였다.

사전준비

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@router.post(
    "/verification",
    description="사용자 토큰 검증 api",
    status_code=status.HTTP_200_OK,
    response_description="유저의 email과 이름 정보",
    responses=verification_user_response()
)

## 분리된 파일
def verification_user_response():
    return {
        status.HTTP_200_OK: {
            "description": "Success",
            "content": {
                "application/json": MediaType(
                    example=Example({
                        "code": 200,
                        "message": "Success",
                        "data": {
                            "name": "username",
                            "email": "test@naver.com",
                            "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuaWNrbmFtZSI6IkppaG8gSmFuZyIsImV4cCI6MTcxMjIyODAzM30.RUl1PC3VuuQuldnl0IZMg4YEgSq-P1oZmKDrnjzt-uZ"
                        }
                    })
                )
            }
        },
        status.HTTP_401_UNAUTHORIZED: {
            "description": "Unauthorized",
            "content":{
                "application/json": MediaType(
                    example=Example({
                        "code": 401,
                        "message": "Parsing Error token",
                        "data": None
                    })
                )
            }
        }
    }

이렇게 작성해주면 된다.

이게 가능한 이유는 @router에 response가 스키마를 구성할때 데이터 타입은 dictionary로 데이터를 받고 있기에 위와같은 구조가 가능한 것이다.

이렇게 한결 깔끔하게 문서관리를 할 수 있게 되었다.

This post is licensed under CC BY 4.0 by the author.