Architecture

RESTful API 설계 주의점! API 경로 충돌 분석 및 해결 방안

인텔로퍼 2025. 3. 27. 08:25
반응형

RESTful API 설계팁

API 경로 충돌 분석 및 해결 방안

이 보고서는 API 엔드포인트 경로 간 충돌 가능성을 분석하고, 발생 원인해결 방안을 제시합니다. 특히 두 그룹의 경로를 비교하여 충돌이 발생할 수 있는 경우와 그에 따른 개선 방법을 상세하게 설명합니다.


주요 포인트

  • 충돌 발생 가능성:
    두 번째 경로 그룹(예: /{variable1}/{variable2}/download/{fileName})은 특정 요청(예: /download/file.txt)에서 양쪽 모두 일치할 수 있으므로 충돌 가능성이 높습니다.
  • 충돌 미발생 사례:
    첫 번째 경로 그룹(예: /get-author-collections/{userID}/{start}/{limit}/get-collection-posts/{collectionID}/{start}/{limit})은 고정된 경로 구간이 서로 다르므로 충돌하지 않습니다.
  • 정의 순서의 영향:
    두 번째 그룹의 경우 경로가 정의된 순서에 따라 매칭되는 엔드포인트가 달라질 수 있으므로, 의도하지 않은 결과를 초래할 수 있습니다.
반응형

상세 분석

1. 문제 정의 및 배경

API 서버에서 동적 경로 매개변수를 사용할 때, 경로 패턴이 겹치는 경우 우선순위에 따라 어느 엔드포인트가 호출될지 결정됩니다.
보다 일반적인 경로가 특정 경로 패턴을 포함하게 되면 충돌이 발생할 수 있습니다.

2. 첫 번째 경로 그룹: 충돌 없음

  • 경로 예시:
    • /get-author-collections/{userID}/{start}/{limit}
    • /get-collection-posts/{collectionID}/{start}/{limit}
  • 분석:
    두 경로 모두 고정된 시작 문자열(get-author-collections vs. get-collection-posts)을 포함하고 있으므로,
    URL이 /get-author-collections/123/0/10 또는 /get-collection-posts/456/0/10과 같이 명확히 구분됩니다.
  • 예시 코드 (FastAPI):위 예시에서는 고정된 경로 부분 덕분에 두 엔드포인트가 서로 명확히 구분되므로 충돌이 발생하지 않습니다.
''' 충돌 발생 X '''
from fastapi import FastAPI
app = FastAPI() 


@app.get("/get-author-collections/{userID}/{start}/{limit}") 
async def get_author_collections(userID: int, start: int, limit: int): 
	return {"userID": userID, "start": start, "limit": limit} 


@app.get("/get-collection-posts/{collectionID}/{start}/{limit}")
async def get_collection_posts(collectionID: int, start: int, limit: int): 
	return {"collectionID": collectionID, "start": start, "limit": limit}

3. 두 번째 경로 그룹: 충돌 가능성 있음

  • 경로 예시:
    • /{variable1}/{variable2}
    • /download/{fileName}
  • 문제 상황 분석:
    예를 들어, /download/file.txt 요청 시 다음과 같이 두 경로에 모두 매칭될 수 있습니다:
    • /{variable1}/{variable2} → variable1 = "download", variable2 = "file.txt"
    • /download/{fileName} → fileName = "file.txt"
    이 경우, FastAPI는 경로가 정의된 순서에 따라 첫 번째 매칭된 엔드포인트를 호출하므로, 의도하지 않은 결과를 초래할 수 있습니다.
  • 예시 코드 (문제 상황):위와 같이 정의할 경우, /download/file.txt 요청은 general_route에 매칭될 가능성이 높습니다(정의 순서에 따라).
''' 충돌 발생 O '''
from fastapi import FastAPI 
app = FastAPI() # 일반 경로 


@app.get("/{variable1}/{variable2}") 
async def general_route(variable1: str, variable2: str): 
    return {"variable1": variable1, "variable2": variable2} # 특정 경로 
    
    
@app.get("/download/{fileName}") 
async def download_file(fileName: str): 
	return {"fileName": fileName}

해결 방안

1.경로 정의 순서 조정:
보다 구체적인 경로(/download/{fileName})를 먼저 정의하여 충돌 가능성을 줄일 수 있습니다.

 

예시 코드 (순서 조정):

from fastapi import FastAPI

app = FastAPI()

# 구체적인 경로를 먼저 정의
@app.get("/download/{fileName}")
async def download_file(fileName: str):
    return {"fileName": fileName}

@app.get("/{variable1}/{variable2}")
async def general_route(variable1: str, variable2: str):
    return {"variable1": variable1, "variable2": variable2}

 

2. 경로 재설계:
일반 경로의 패턴을 변경하여 특정 경로와 겹치지 않도록 할 수 있습니다.
예를 들어, 일반 경로를 /images/{variable1}/{variable2}와 같이 명시적으로 구분하면 충돌을 방지할 수 있습니다.

 

예시 코드 (경로 재설계):

from fastapi import FastAPI

app = FastAPI()

# 변경된 일반 경로
@app.get("/images/{variable1}/{variable2}")
async def image_route(variable1: str, variable2: str):
    return {"variable1": variable1, "variable2": variable2}

@app.get("/download/{fileName}")
async def download_file(fileName: str):
    return {"fileName": fileName}

 

 

3. 경로 제약 조건 적용:
경로 매개변수에 정규 표현식 등의 제약 조건을 추가하여, 특정 값(예: "download")이 일반 경로 매개변수로 들어가지 않도록 제한할 수 있습니다.

위 코드에서는 variable1에 "download"가 매칭되지 않도록 정규 표현식을 사용하여 제한함으로써 충돌을 예방할 수 있습니다.

 

예시 코드 (경로 제약 조건 적용):

from fastapi import FastAPI, Path

app = FastAPI()

@app.get("/download/{fileName}")
async def download_file(fileName: str):
    return {"fileName": fileName}

@app.get("/{variable1}/{variable2}")
async def general_route(
    variable1: str = Path(..., regex="^(?!download$).*$"),
    variable2: str = Path(...)
):
    return {"variable1": variable1, "variable2": variable2}

요약 비교

항목 첫 번째 경로 그룹 두 번째 경로 그룹

경로 예시 /get-author-collections/123/0/10/
get-collection-posts/456/0/10
/download/file.txt
충돌 가능성 없음 (고정 경로 부분이 명확하게 구분됨) 있음 (일부 URL에서 양쪽 경로에 모두 매칭됨)
매칭 기준 고정된 경로 부분으로 명확하게 구분 정의 순서에 따라 결정되어 의도치 않은 매칭 발생 가능
해결 방법 추가 조치 불필요 구체적 경로 우선 정의, 경로 재설계 또는 제약 조건 추가

결론

  • 첫 번째 경로 그룹은 고정된 경로 구간 덕분에 충돌 없이 정상적으로 작동합니다.
  • 두 번째 경로 그룹은 /download/file.txt와 같이 URL에 따라 양쪽 모두 일치할 가능성이 있으므로,
    정의 순서 변경, 경로 재설계 또는 경로 제약 조건을 적용하여 충돌 문제를 예방해야 합니다.

이와 같이 API 경로의 설계와 정의 순서에 주의하면, 의도하지 않은 동작이나 디버깅의 어려움을 크게 줄일 수 있습니다.

 

 

 

추천드리는 좋은글

2025년에 꼭 알아야 할 5가지 마이크로서비스 디자인 패턴 (Python FastAPI 예시 포함)

 

2025년에 꼭 알아야 할 5가지 마이크로서비스 디자인 패턴 (Python FastAPI 예시 포함)

마이크로서비스의 복잡성을 해결하는 필수 디자인 패턴마이크로서비스는 현대 소프트웨어 개발의 핵심으로 자리 잡았습니다. 하나의 거대한 애플리케이션 대신 작고 독립적인 서비스들로 시

intelloper.tistory.com

[Modern Python Project] 현대적 파이썬 프로젝트 관리, 개발법에 대하여

 

[Modern Python Project] 현대적 파이썬 프로젝트 관리, 개발법에 대하여

파이썬 프로젝트를 현대적으로 관리하고 개발하는 방법에 대해 이야기해보려 합니다. 여러 회사와 프로젝트에서 파이썬을 사용하면서 발견한 몇 가지 성가시고, 유지보수가 어렵고, 구식인 관

intelloper.tistory.com

FastAPI와 함께하는 SOLID 원칙: Python으로 깔끔한 코드 작성하기

 

FastAPI와 함께하는 SOLID 원칙: Python으로 깔끔한 코드 작성하기

소프트웨어 설계에서 중요한 SOLID 원칙을 FastAPI와 Python을 활용해 어떻게 적용할 수 있는지 알아보겠습니다. 🚀SOLID는 로버트 C. 마틴(일명 "Uncle Bob")이 제안한 5가지 설계 원칙으로, 코드를 더 깔

intelloper.tistory.com

 

반응형