더 큰 애플리케이션 - 여러 파일
더 큰 애플리케이션 - 여러 파일 (Bigger Applications - Multiple Files)
애플리케이션이나 웹 API를 만들 때, 모든 걸 한 파일에 넣을 수 있는 경우는 거의 없어요.
FastAPI는 유연성을 모두 유지하면서 애플리케이션을 구조화할 수 있는 편리한 도구를 제공해요.
참고 — Flask에서 왔다면, 이건 Flask의 Blueprints에 해당하는 거예요.
출처: 공식문서
예시 파일 구조
이런 파일 구조를 갖고 있다고 해 볼게요:
.
├── app
│ ├── __init__.py
│ ├── main.py
│ ├── dependencies.py
│ └── routers
│ │ ├── __init__.py
│ │ ├── items.py
│ │ └── users.py
│ └── internal
│ ├── __init__.py
│ └── admin.py
팁 —
__init__.py파일이 여러 개 있어요. 각 디렉터리나 하위 디렉터리에 하나씩이죠. 이것이 한 파일에서 다른 파일로 코드를 임포트할 수 있게 해주는 거예요.
예를 들어 app/main.py에서 이런 줄을 쓸 수 있어요:
from app.routers import items
app디렉터리는 모든 걸 담아요. 그리고 빈 파일app/__init__.py가 있어서 "Python 패키지"(Python 모듈들의 모음)가 돼요:app.app/main.py파일이 있어요. Python 패키지(__init__.py파일이 있는 디렉터리) 안에 있으므로 그 패키지의 "모듈"이에요:app.main.app/dependencies.py파일도 있어요.app/main.py처럼 이것도 "모듈"이에요:app.dependencies.- 하위 디렉터리
app/routers/에 또 다른__init__.py파일이 있어서, "Python 서브패키지"예요:app.routers. - 파일
app/routers/items.py는 패키지app/routers/안에 있으므로 서브모듈이에요:app.routers.items. app/routers/users.py도 마찬가지로 또 다른 서브모듈이에요:app.routers.users.- 하위 디렉터리
app/internal/에도 또 다른__init__.py파일이 있어서, 또 다른 "Python 서브패키지"예요:app.internal. - 파일
app/internal/admin.py는 또 다른 서브모듈이에요:app.internal.admin.
같은 파일 구조를 주석과 함께 보면:
.
├── app # "app" is a Python package
│ ├── __init__.py # this file makes "app" a "Python package"
│ ├── main.py # "main" module, e.g. import app.main
│ ├── dependencies.py # "dependencies" module, e.g. import app.dependencies
│ └── routers # "routers" is a "Python subpackage"
│ │ ├── __init__.py # makes "routers" a "Python subpackage"
│ │ ├── items.py # "items" submodule, e.g. import app.routers.items
│ │ └── users.py # "users" submodule, e.g. import app.routers.users
│ └── internal # "internal" is a "Python subpackage"
│ ├── __init__.py # makes "internal" a "Python subpackage"
│ └── admin.py # "admin" submodule, e.g. import app.internal.admin
APIRouter
사용자만 처리하는 전용 파일이 /app/routers/users.py 서브모듈이라고 해 볼게요.
사용자와 관련된 경로 연산을 나머지 코드와 분리해서, 정리된 상태를 유지하고 싶어요.
하지만 여전히 같은 FastAPI 애플리케이션/웹 API의 일부예요(같은 "Python 패키지"의 일부죠).
APIRouter를 써서 그 모듈의 경로 연산을 만들 수 있어요.
APIRouter 임포트하기
FastAPI 클래스를 쓸 때와 같은 방식으로 임포트하고 "인스턴스"를 만들어요:
app/routers/users.py:
from fastapi import APIRouter
router = APIRouter()
@router.get("/users/", tags=["users"])
async def read_users():
return [{"username": "Rick"}, {"username": "Morty"}]
@router.get("/users/me", tags=["users"])
async def read_user_me():
return {"username": "fakecurrentuser"}
@router.get("/users/{username}", tags=["users"])
async def read_user(username: str):
return {"username": username}
APIRouter로 경로 연산 만들기
그리고 이걸 써서 경로 연산을 선언해요. FastAPI 클래스를 쓰는 것과 같은 방식으로 쓰면 돼요:
app/routers/users.py:
from fastapi import APIRouter
router = APIRouter()
@router.get("/users/", tags=["users"])
async def read_users():
return [{"username": "Rick"}, {"username": "Morty"}]
@router.get("/users/me", tags=["users"])
async def read_user_me():
return {"username": "fakecurrentuser"}
@router.get("/users/{username}", tags=["users"])
async def read_user(username: str):
return {"username": username}
APIRouter를 "미니 FastAPI" 클래스라고 생각할 수 있어요.
모든 같은 옵션을 지원해요. 같은 parameters, responses, dependencies, tags 등 모두요.
팁 — 이 예시에서는 변수 이름을
router로 했지만, 원하는 대로 이름을 지을 수 있어요.
이 APIRouter를 메인 FastAPI 앱에 포함시킬 거예요. 하지만 먼저 의존성과 또 다른 APIRouter를 확인해 볼게요.
의존성 (Dependencies)
애플리케이션의 여러 곳에서 쓰일 의존성들이 필요하다는 걸 알 수 있어요.
그래서 그걸 자체 dependencies 모듈(app/dependencies.py)에 넣어요.
이제 커스텀 X-Token 헤더를 읽는 간단한 의존성을 써 볼게요:
app/dependencies.py:
from typing import Annotated
from fastapi import Header, HTTPException
async def get_token_header(x_token: Annotated[str, Header()]):
if x_token != "fake-super-secret-token":
raise HTTPException(status_code=400, detail="X-Token header invalid")
async def get_query_token(token: str):
if token != "jessica":
raise HTTPException(status_code=400, detail="No Jessica token provided")
팁 — 예시를 단순화하기 위해 지어낸 헤더를 쓰고 있어요. 실제 상황에서는 내장된 보안 유틸리티를 쓰면 더 나은 결과를 얻어요.
APIRouter가 있는 또 다른 모듈
애플리케이션의 "items"를 처리하는 엔드포인트 전용 모듈도 app/routers/items.py에 있다고 해 볼게요.
다음을 위한 경로 연산이 있어요:
/items//items/{item_id}
app/routers/users.py와 같은 구조예요.
하지만 좀 더 똑똑하게 코드를 단순화하고 싶어요.
이 모듈의 모든 경로 연산이 같은 것들을 공유한다는 걸 알고 있어요:
- 경로
prefix:/items. tags: (태그 하나:items).- 추가
responses. dependencies: 모두 우리가 만든 그X-Token의존성이 필요해요.
그래서 모든 경로 연산에 그걸 추가하는 대신 APIRouter에 추가할 수 있어요.
app/routers/items.py:
from fastapi import APIRouter, Depends, HTTPException
from ..dependencies import get_token_header
router = APIRouter(
prefix="/items",
tags=["items"],
dependencies=[Depends(get_token_header)],
responses={404: {"description": "Not found"}},
)
fake_items_db = {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}}
@router.get("/")
async def read_items():
return fake_items_db
@router.get("/{item_id}")
async def read_item(item_id: str):
if item_id not in fake_items_db:
raise HTTPException(status_code=404, detail="Item not found")
return {"name": fake_items_db[item_id]["name"], "item_id": item_id}
@router.put(
"/{item_id}",
tags=["custom"],
responses={403: {"description": "Operation forbidden"}},
)
async def update_item(item_id: str):
if item_id != "plumbus":
raise HTTPException(
status_code=403, detail="You can only update the item: plumbus"
)
return {"item_id": item_id, "name": "The great Plumbus"}
각 경로 연산의 경로가 /로 시작해야 하므로, 이렇게요:
@router.get("/{item_id}")
async def read_item(item_id: str):
...
...prefix는 마지막에 /를 포함하면 안 돼요.
그래서 이 경우 prefix는 /items예요.
이 라우터에 포함된 모든 경로 연산에 적용될 tags 목록과 추가 responses도 더할 수 있어요.
그리고 라우터의 모든 경로 연산에 추가되어, 각 요청마다 실행/해결될 dependencies 목록도 추가할 수 있어요.
팁 — 경로 연산 데코레이터의 의존성과 비슷하게, 경로 연산 함수에 값이 전달되지 않는다는 점을 주목하세요.
최종 결과로 item 경로들은 이렇게 돼요:
/items//items/{item_id}
...우리가 의도한 대로예요.
- 문자열 하나
"items"를 포함한 태그 목록으로 표시돼요.- 이 "tags"는 (OpenAPI를 쓰는) 자동 대화형 문서 시스템에 특히 유용해요.
- 모두 미리 정의된
responses를 포함해요. - 이 모든 경로 연산은 그것들 앞에
dependencies목록이 평가/실행돼요.- 특정 경로 연산에서도 의존성을 선언하면 그것도 실행돼요.
- 라우터 의존성이 먼저 실행되고, 그다음 데코레이터의
dependencies, 그리고 나서 일반적인 파라미터 의존성이 실행돼요. scopes가 있는Security의존성도 추가할 수 있어요.
팁 —
APIRouter에dependencies를 두는 건, 예를 들어 경로 연산 전체 그룹에 인증을 요구하는 데 쓸 수 있어요. 각각에 개별적으로 추가하지 않아도요.
팁 —
prefix,tags,responses,dependencies파라미터는 (다른 많은 경우처럼) 코드 중복을 피하도록 도와주는 FastAPI의 기능일 뿐이에요.
의존성 임포트하기
이 코드는 모듈 app.routers.items, 파일 app/routers/items.py에 있어요.
그리고 의존성 함수는 모듈 app.dependencies, 파일 app/dependencies.py에서 가져와야 해요.
그래서 의존성에 ..를 쓰는 상대 임포트(relative import)를 사용해요:
app/routers/items.py:
from fastapi import APIRouter, Depends, HTTPException
from ..dependencies import get_token_header
router = APIRouter(
prefix="/items",
tags=["items"],
dependencies=[Depends(get_token_header)],
responses={404: {"description": "Not found"}},
)
fake_items_db = {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}}
@router.get("/")
async def read_items():
return fake_items_db
@router.get("/{item_id}")
async def read_item(item_id: str):
if item_id not in fake_items_db:
raise HTTPException(status_code=404, detail="Item not found")
return {"name": fake_items_db[item_id]["name"], "item_id": item_id}
@router.put(
"/{item_id}",
tags=["custom"],
responses={403: {"description": "Operation forbidden"}},
)
async def update_item(item_id: str):
if item_id != "plumbus":
raise HTTPException(
status_code=403, detail="You can only update the item: plumbus"
)
return {"item_id": item_id, "name": "The great Plumbus"}
상대 임포트가 어떻게 동작하는지
팁 — 임포트가 어떻게 동작하는지 완벽히 안다면 아래 섹션으로 넘어가세요.
점 하나 .은 이렇게요:
from .dependencies import get_token_header
이걸 의미해요:
- 이 모듈(파일
app/routers/items.py)이 살고 있는 같은 패키지(디렉터리app/routers/)에서 시작해서... - 모듈
dependencies(가상의 파일app/routers/dependencies.py)를 찾고... - 그 모듈에서 함수
get_token_header를 임포트해요.
하지만 그 파일은 없어요. 우리 의존성은 app/dependencies.py에 있어요.
우리의 앱/파일 구조가 어떻게 생겼는지 기억하세요.
점 두 개 ..은 이렇게요:
from ..dependencies import get_token_header
이걸 의미해요:
- 이 모듈(파일
app/routers/items.py)이 살고 있는 같은 패키지(디렉터리app/routers/)에서 시작해서... - 부모 패키지(디렉터리
app/)로 가고... - 거기서 모듈
dependencies(파일app/dependencies.py)를 찾고... - 그 모듈에서 함수
get_token_header를 임포트해요.
그게 올바르게 동작해요! 🎉
같은 방식으로, 점 세 개 ...을 썼다면 이렇게요:
from ...dependencies import get_token_header
이걸 의미해요:
- 이 모듈(파일
app/routers/items.py)이 살고 있는 같은 패키지(디렉터리app/routers/)에서 시작해서... - 부모 패키지(디렉터리
app/)로 가고... - 그 패키지의 부모로 갑니다(부모 패키지가 없어요.
app이 최상위입니다 😱)... - 그리고 거기서 모듈
dependencies(파일app/dependencies.py)를 찾고... - 그 모듈에서 함수
get_token_header를 임포트해요.
그건 app/ 위의 어떤 패키지(자체 __init__.py 파일을 가진)를 가리킬 거예요. 하지만 우리는 그런 게 없어요. 그래서 이 예시에서는 에러가 날 거예요. 🚨
하지만 이제 어떻게 동작하는지 알게 됐으니, 아무리 복잡한 앱이라도 상대 임포트를 쓸 수 있어요. 🤓
커스텀 tags, responses, dependencies 추가하기
각 경로 연산에 prefix /items나 tags=["items"]를 추가하지 않았어요. APIRouter에 그걸 추가했으니까요.
하지만 특정 경로 연산에 적용될 tags를 더 추가할 수도 있고, 그 경로 연산에 특화된 responses도 추가할 수 있어요:
app/routers/items.py:
from fastapi import APIRouter, Depends, HTTPException
from ..dependencies import get_token_header
router = APIRouter(
prefix="/items",
tags=["items"],
dependencies=[Depends(get_token_header)],
responses={404: {"description": "Not found"}},
)
fake_items_db = {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}}
@router.get("/")
async def read_items():
return fake_items_db
@router.get("/{item_id}")
async def read_item(item_id: str):
if item_id not in fake_items_db:
raise HTTPException(status_code=404, detail="Item not found")
return {"name": fake_items_db[item_id]["name"], "item_id": item_id}
@router.put(
"/{item_id}",
tags=["custom"],
responses={403: {"description": "Operation forbidden"}},
)
async def update_item(item_id: str):
if item_id != "plumbus":
raise HTTPException(
status_code=403, detail="You can only update the item: plumbus"
)
return {"item_id": item_id, "name": "The great Plumbus"}
팁 — 이 마지막 경로 연산은 태그 조합
["items", "custom"]을 갖게 돼요.
그리고 문서에 404용 responses와 403용 responses가 둘 다 생겨요.
메인 FastAPI
이제 app/main.py의 모듈을 볼게요.
여기가 FastAPI 클래스를 임포트하고 쓰는 곳이에요.
이건 여러분 애플리케이션에서 모든 걸 묶어 주는 메인 파일이 될 거예요.
그리고 대부분의 로직이 이제 각자의 전용 모듈에 살게 되므로, 메인 파일은 꽤 단순해질 거예요.
FastAPI 임포트하기
평소처럼 FastAPI 클래스를 임포트하고 만들어요.
그리고 각 APIRouter의 의존성과 결합될 전역 의존성을 선언할 수도 있어요:
app/main.py:
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
APIRouter 임포트하기
이제 APIRouter를 가진 다른 서브모듈들을 임포트해요:
app/main.py:
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
파일 app/routers/users.py와 app/routers/items.py가 같은 Python 패키지 app의 일부인 서브모듈이므로, 단일 점 .을 써서 "상대 임포트"로 임포트할 수 있어요.
임포트가 어떻게 동작하는지
이 섹션:
from .routers import items, users
이걸 의미해요:
- 이 모듈(파일
app/main.py)이 살고 있는 같은 패키지(디렉터리app/)에서 시작해서... - 서브패키지
routers(디렉터리app/routers/)를 찾고... - 그 패키지에서 서브모듈
items(파일app/routers/items.py)와users(파일app/routers/users.py)를 임포트해요...
모듈 items는 변수 router(items.router)를 가질 거예요. 이건 파일 app/routers/items.py에서 만든 그거예요. APIRouter 객체죠.
그리고 모듈 users에 대해서도 똑같이 해요.
이렇게도 임포트할 수 있어요:
from app.routers import items, users
참고 — 첫 번째 버전은 "상대 임포트"예요:
from .routers import items, users두 번째 버전은 "절대 임포트"예요:
from app.routers import items, users
Python 패키지와 모듈에 대해 더 배우려면 Python 공식 문서의 Modules를 읽어 보세요.
이름 충돌 피하기
서브모듈 items를, 단지 그 변수 router만 임포트하는 대신 직접 임포트하고 있어요.
이건 서브모듈 users에도 router라는 또 다른 변수가 있기 때문이에요.
하나씩 순서대로 임포트했다면 이렇게요:
from .routers.items import router
from .routers.users import router
users의 router가 items의 것을 덮어쓰고, 동시에 둘을 쓸 수 없게 돼요.
그래서 같은 파일에서 둘 다 쓰려면 서브모듈을 직접 임포트해요:
app/main.py:
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
users와 items의 APIRouter 포함하기
이제 서브모듈 users와 items의 router들을 포함해요:
app/main.py:
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
참고 —
users.router는 파일app/routers/users.py안의APIRouter를 담고 있어요.그리고
items.router는 파일app/routers/items.py안의APIRouter를 담고 있어요.
app.include_router()로 각APIRouter를 메인FastAPI애플리케이션에 추가할 수 있어요. 그 라우터의 모든 라우트를 그것의 일부로 포함해요.
기술적 세부사항 — 라우터가 메인 애플리케이션에 포함될 때 FastAPI는 원래 APIRouter와 그 APIRoute들을 활성 상태로 유지해요. 즉 커스텀 APIRouter와 APIRoute 서브클래스가 라우터 포함 후에도 여전히 참여할 수 있다는 뜻이에요.
팁 — 라우터를 포함할 때 성능을 걱정할 필요 없어요. 이건 가볍게 설계됐고, 각 요청에 오버헤드를 추가하지 않도록 설계됐어요. 그래서 성능에 영향을 주지 않아요. ⚡
커스텀 prefix, tags, responses, dependencies로 APIRouter 포함하기
이제 조직이 여러분에게 app/internal/admin.py 파일을 줬다고 상상해 볼게요.
조직이 여러 프로젝트에서 공유하는 몇몇 admin 경로 연산을 가진 APIRouter를 담고 있어요.
이 예시에서는 매우 단순할 거예요. 하지만 조직의 다른 프로젝트와 공유되기 때문에, 그 APIRouter에 직접 prefix, dependencies, tags 등을 추가해서 수정할 수 없다고 해 볼게요:
app/internal/admin.py:
from fastapi import APIRouter
router = APIRouter()
@router.post("/")
async def update_admin():
return {"message": "Admin getting schwifty"}
하지만 여전히 APIRouter를 포함할 때 커스텀 prefix를 설정해서 모든 경로 연산이 /admin으로 시작하게 하고 싶고, 이 프로젝트를 위해 이미 갖고 있는 dependencies로 보호하고 싶으며, tags와 responses를 포함하고 싶어요.
원래 APIRouter를 수정하지 않고도 이 모든 걸 선언할 수 있어요. 그 파라미터들을 app.include_router()에 넘기면 되죠:
app/main.py:
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
그렇게 하면 원래 APIRouter는 수정되지 않은 채 남아서, 같은 app/internal/admin.py 파일을 조직의 다른 프로젝트와 계속 공유할 수 있어요.
그 결과 우리 앱에서 admin 모듈의 각 경로 연산은 이걸 갖게 돼요:
- prefix
/admin. - 태그
admin. - 의존성
get_token_header. - 응답
418. 🍵
하지만 그건 우리 앱의 그 APIRouter에만 영향을 주고, 그걸 쓰는 다른 코드에는 영향을 주지 않아요.
예를 들어 다른 프로젝트는 다른 인증 방법으로 같은 APIRouter를 쓸 수 있어요.
경로 연산 포함하기
FastAPI 앱에 경로 연산을 직접 추가할 수도 있어요.
여기서는... 할 수 있다는 걸 보여주려고 해요 🤷:
app/main.py:
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
그리고 app.include_router()로 추가된 다른 모든 경로 연산과 함께 올바르게 동작해요.
매우 기술적인 세부사항 — 참고: 이것은 아마 건너뛸 수 있는 매우 기술적인 세부사항이에요.
APIRouter들은 "마운트"되지 않아요. 애플리케이션의 나머지와 격리되지 않죠.
왜냐하면 우리는 그 경로 연산을 OpenAPI 스키마와 사용자 인터페이스에 포함시키고 싶기 때문이에요.
FastAPI는 원래 라우터와 경로 연산을 활성 상태로 유지하고, 요청을 처리하고 OpenAPI를 생성할 때 라우터의 prefix, 의존성, 태그, 응답 및 기타 메타데이터를 결합해요.
pyproject.toml에서 entrypoint 설정하기
여러분의 FastAPI app 객체가 app/main.py에 있으므로, pyproject.toml 파일에서 entrypoint를 이렇게 설정할 수 있어요:
[tool.fastapi]
entrypoint = "app.main:app"
이건 다음과 같이 임포트하는 것과 같아요:
from app.main import app
그렇게 하면 fastapi 명령이 여러분 앱을 어디서 찾을지 알 수 있어요.
참고 — 명령에 경로를 넘길 수도 있어요, 이렇게요:
$ uv run fastapi dev app/main.py하지만
fastapi명령을 호출할 때마다 올바른 경로를 기억해서 넘겨야 해요.게다가 VS Code 확장이나 FastAPI Cloud 같은 다른 도구는 그것을 찾지 못할 수도 있으므로,
pyproject.toml의entrypoint를 쓰는 걸 권장해요.
자동 API 문서 확인하기
이제 앱을 실행해요:
uv run fastapi dev
그리고 http://127.0.0.1:8000/docs에서 문서를 열어요.
모든 서브모듈의 경로를 올바른 경로(와 prefix)와 올바른 태그로 포함한 자동 API 문서를 볼 수 있어요.
같은 라우터를 다른 prefix로 여러 번 포함하기
.include_router()를 같은 라우터로 다른 prefix를 쓰며 여러 번 쓸 수도 있어요.
예를 들어 같은 API를 다른 prefix로 노출하는 데 유용해요. /api/v1과 /api/latest처럼요.
정말 필요하지 않을 수도 있는 고급 사용법이지만, 필요할 때를 대비해 있어요.
APIRouter를 다른 것 안에 포함하기
FastAPI 애플리케이션에 APIRouter를 포함할 수 있는 것과 같은 방식으로, 이렇게 써서 다른 APIRouter에 APIRouter를 포함할 수 있어요:
router.include_router(other_router)
router를 FastAPI 앱에 포함하기 전에나 후에 이걸 할 수 있어요. FastAPI는 여전히 other_router의 경로 연산을 라우팅과 OpenAPI에 포함해요.
나중에 라우터에 추가되는 경로 연산에도 마찬가지예요. 그것들은 앞선 포함을 통해서도 보여요.
기술적 세부사항 — 라우터를 포함한 뒤 router.routes를 직접 변경하는 건 피하세요. FastAPI는 라우터 포함을 "실시간(live)"으로 취급하므로, 원래 라우터와 그 라우트가 라우팅과 OpenAPI 생성의 일부로 남아요. 라우트와 라우터를 추가하려면 경로 연산 데코레이터나 .include_router() 같은 문서화된 API를 쓰세요. router.routes를 라우트 정의와 포함된 라우터를 담을 수 있는 저수준 라우트 트리로 취급하고, 그것을 최종 경로 연산의 평평한 목록으로 의존하지 마세요.