FastAPI 서버개발, 중복 코드 줄이기를 위한 의존성 재사용

웹 애플리케이션을 개발할 때, 코드의 중복을 줄이는 것은 소프트웨어의 유지보수성과 확장성을 높이는 중요한 작업입니다. FastAPI는 이러한 작업을 효율적으로 처리하기 위한 다양한 방법을 제공하며, 특히 의존성 주입(Dependency Injection)의 개념을 통해 중복 코드를 줄일 수 있는 뛰어난 기능을 갖추고 있습니다.

1. FastAPI 소개

FastAPI는 Python으로 작성된 현대적인 웹 프레임워크로, 빠른 성능과 개발 생산성을 자랑합니다. ASGI(Asynchronous Server Gateway Interface)를 기반으로 하며, 비동기 프로그래밍을 지원합니다. 데이터 검증, 직렬화, OpenAPI 및 JSON Schema에 대한 자동화된 문서화를 쉽게 처리할 수 있습니다.

2. 의존성 주입(Dependency Injection)란?

의존성 주입이란 객체나 함수가 필요로 하는 외부의 의존 객체를 주입받아 사용하는 디자인 패턴입니다. 이를 통해 객체 간의 결합도가 낮아져 코드의 재사용성이 증가하고, 테스트가 쉬워지는 장점이 있습니다.

2.1 FastAPI에서 의존성 주입 사용하기

FastAPI에서는 의존성을 정의하고 주입하는 것이 매우 간단합니다. 의존성을 정의하기 위해서는 Depends 클래스를 사용합니다. 아래 코드 예제를 통해 이를 살펴보겠습니다.

from fastapi import FastAPI, Depends, HTTPException

app = FastAPI()

def get_query_param(q: str = None):
    return q

@app.get("/items/")
async def read_item(q: str = Depends(get_query_param)):
    if q:
        return {"query": q}
    return {"query": "No query provided"}

위 예제에서는 get_query_param이라는 함수를 정의하고 여기서 query parameter를 받아옵니다. Depends를 사용하여 이를 read_item 함수에 주입하고 있습니다.

3. 중복 코드 줄이기의 필요성

웹 애플리케이션의 크기가 커질수록, 비슷한 기능을 갖는 코드 블록이 여러 곳에서 반복되는 경우가 많습니다. 이러한 중복 코드는 코드의 복잡성을 증가시키고, 유지보수의 어려움을 초래합니다. 의존성 주입을 통해 이러한 중복 코드를 줄임으로써 효율적인 코드 작성을 할 수 있습니다.

4. 의존성 재사용을 통한 코드 최적화

의존성 재사용은 FastAPI의 핵심 특징 중 하나입니다. 기본적인 의존성을 여러 라우터에 재사용할 수 있고, 이를 통해 코드의 일관성을 유지하며 중복을 제거할 수 있습니다.

4.1 공통 의존성 정의하기

예를 들어, 사용자의 인증을 처리하는 공통 의존성을 정의할 수 있습니다. 아래 코드는 JWT 인증을 위한 예시입니다.

from fastapi import Security, Depends
from fastapi.security import OAuth2PasswordBearer

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

async def get_current_user(token: str = Depends(oauth2_scheme)):
    # 여기에 JWT 검증 로직을 추가합니다.
    if token != "valid-token":
        raise HTTPException(status_code=401, detail="Invalid authentication credentials")
    return {"username": "user1"}

@app.get("/users/me")
async def read_users_me(current_user: dict = Depends(get_current_user)):
    return current_user

여기서 get_current_user 함수는 JWT 토큰을 검증하는 역할을 하며, 여러 라우터에서 재사용될 수 있습니다.

4.2 동적으로 의존성 주입하기

FastAPI에서는 동적으로 의존성을 주입할 수도 있습니다. 이를 통해 상황에 따라 다른 의존성을 사용할 수 있습니다. 예를 들어, 환경에 따라 다른 데이터베이스 연결을 사용할 수 있습니다.

from fastapi import Depends

def get_database_connection():
    if app.state.environment == "production":
        return "Production DB Connection"
    return "Development DB Connection"

@app.get("/db/")
async def read_db(connection: str = Depends(get_database_connection)):
    return {"connection": connection}

위 코드에서 환경 변수를 통해 서로 다른 데이터베이스 연결을 주입받을 수 있습니다.

5. 의존성 재사용의 이점

  • 유지보수성: 중복이 제거됨으로써 코드 전반에 걸쳐 더 쉽게 수정할 수 있습니다.
  • 테스트 용이성: 더 적은 코드로 더 많은 기능을 구현할 수 있어, 테스트와 디버깅을 쉽게 할 수 있습니다.
  • 일관성: 의존성이 각기 다른 라우터에서 재사용됨으로써 코드의 일관성을 유지할 수 있습니다.

6. 고급 의존성 주입

FastAPI에서는 의존성 주입의 고급 기능도 제공하여, 클래스와 함께 사용할 수 있습니다. 이를 통해 더 복잡한 비즈니스 로직을 캡슐화할 수 있습니다. 아래는 클래스 기반의 의존성 주입 예제입니다.

class UserService:
    def get_user(self, user_id: int):
        # 데이터베이스에서 사용자 정보를 가져오는 로직
        return {"user_id": user_id, "name": "John Doe"}

def get_user_service() -> UserService:
    return UserService()

@app.get("/users/{user_id}")
async def read_user(user_id: int, user_service: UserService = Depends(get_user_service)):
    return user_service.get_user(user_id)

이 예제에서 UserService 클래스는 사용자의 정보를 제공하는 로직을 담당하며, 이를 의존성으로 주입받아 사용할 수 있습니다.

7. 결론

FastAPI는 의존성 주입을 통해 중복 코드를 최소화하고 코드의 재사용성을 극대화할 수 있는 훌륭한 도구입니다. 의존성을 통해 작성된 코드는 더 간결하고, 유지보수하기 쉬우며, 테스트가 용이합니다. 여러 가지 예제를 통해 의존성 재사용의 중요성과 이를 FastAPI에서 구현하는 방법을 살펴보았습니다.

참고 자료