현상
FastAPI는 API 문서를 자동으로 생성하는 기능을 제공하고 있어 기본적으로 /docs, /redoc 경로로 접근하면 개발한 API의 문서를 확인할 수 있다.
최근 개인 컴퓨터가 아니라 별도의 개발 환경에서 FastAPI를 사용해 개발을 진행하고 있는데, API 문서를 확인하려고 했더니 아래와 같은 화면과 함께 오류가 발생했다.
현상을 해결해 보자.
원인
이 현상은 prefix가 제거된 프록시가 있을 때 발생한다. prefix가 제거되었다는 것은 FastAPI 내에서는 root 아래에서 제공하고 있는 경로가 FastAPI 외에서는 경로가 추가된 상태고 제공하고 있는 것을 의미한다. 예로 들면 FastAPI에서 /app 경로를 선언했으나, 실제 서비스에서는 /api/v1이라는 prefix를 추가하여 /api/v1/app 경로를 사용하는 상태에 해당한다.
보통 프록시 서버가 요청을 FastAPI 애플리케이션으로 전달하기 전에 경로의 prefix를 제거힌다. 마찬가지로 프론트엔드가 API 문서를 열 때 prefix가 제거된 경로에서 OpenAPI 스키마를 가져오려고 한다. 하지만 실제로는 prefix가 포함된 경로에서 가져와야 하기 때문에 404 Not Found 에러가 발생하는 것이다.
root_path
프록시가 처리하는 경로 prefix는 root_path라는 값으로 서버를 실행할 때나 프로그램 코드 상에서 FastAPI에 전달할 수 있다.
만약 서버로 uvicorn을 사용하고 있다면 아래와 같이 전달하면 된다.
uvicorn <모듈>:<앱> --root-path <prefix>
# 예시
uvicorn ttest:app --root-path /api/v1
외부에서 전달할 방법이 없다면 FastAPI 객체 생성 시 생성자의 매개변수로 전달하면 된다.
from fastapi import FastAPI
app = FastAPI(root_path="/api/v1")
테스트
예시로 아래와 같은 애플리케이션이 있고,
from fastapi import FastAPI
app = FastAPI()
items = {"foo": "The Foo Wrestlers"}
@app.get("/items/{item_id}")
async def read_item(item_id: str):
return {"item": items[item_id]}
애플리케이션 실행 시 root_path를 제공한다고 하자.
uvicorn ttest:app --reload --root-path /api/v1
그리고 traefik을 사용하여 9999 포트로는 /api/v1/이라는 경로 접두사를 사용하도록 설정했다.
(참고 : https://fastapi.tiangolo.com/ko/advanced/behind-a-proxy/#about-proxies-with-a-stripped-path-prefix)
애플리케이션의 경우 http://127.0.0.1:8000/items/foo, http://127.0.0.1:9999/api/v1/items/foo 모두 정상적으로 요청이 돌아온다.
하지만 API 문서의 경우에는 기존처럼 접근하면 에러가 발생한다.
반면 prefix가 포함된 경로로 접근하면 정상적으로 로드되는 것을 확인할 수 있다.
참고 문서
https://fastapi.tiangolo.com/ko/advanced/behind-a-proxy/