본문 바로가기
Fast API/fastapi배우기

Fast API 배우기 24부 - 라우터

by 붕어사랑 티스토리 2021. 11. 8.
반응형

여지껏 우리는 API를 main.py에다가 작성하였다.

 

그런데 사실 모든 코드들을 main.py에다가 작성하는건 그리 좋지 못한 방법이다.

 

이번 시간에는 이 문제를 해결할 방법인 router에 대해 알아보겠다.

 

 

라우터란?

mini fastapi application이라고 생각하면 될 것 같다.

한마디로 여러 API를 다른 파일에다 작성하고 이걸 main app에다가 넣었다 끼웠다 하면된다.

 

 

 

 

 

 

프로젝트 폴더 구조

fastapi 공식문서에서는 다음과 같은 폴더 구조를 사용하는것을 권장하고 있다.

 

.
├── app
│   ├── __init__.py
│   ├── main.py
│   ├── dependencies.py
│   └── routers
│   │   ├── __init__.py
│   │   ├── items.py
│   │   └── users.py
│   └── internal
│       ├── __init__.py
│       └── admin.py

 

자 여기서 위에 라우터로 items.py와 users.py가 라우터로 들어가 있다.

 

이 둘은 item와 user에 관한 API를 담은 코드가 들어갈 것이다.

 

API 라우터의 간단한 예제

 

첫번째로 간단하게 user 라우터를 만들어보겠다.

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를 선언한다

router = APIRouter()

 

 

나머지는 @app 데코레이션과 전부 똑같다.

path를 지정가능하고 디펜던시나 태그로 전부 지정 가능하다

 

@router.get("/users/", tags=["users"])
@router.get("/users/me", tags=["users"])
@router.get("/users/{username}", tags=["users"])

 

 

디펜던시

라우터와 관련없는 내용이나, 공식홈페이지 코드 공유를 위해 일단 여기다 작성한다. 내용을 이해하려면 그냥 넘어가는걸 추천

from fastapi import Header, HTTPException

async def get_token_header(x_token: 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")
반응형

 

좀더 복잡한 라우터 예제

이번에는 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"}

 

 

아래와 같이 API 라우터를 선언할때 라우터에 global하게 prefix와 tags, 디펜던시가 선언가능하다.

prefix에 /items 라고 붙어있다. 그럼 라우터의 모든 path operation은 /items 로 시작한다.

router = APIRouter(
    prefix="/items",
    tags=["items"],
    dependencies=[Depends(get_token_header)],
    responses={404: {"description": "Not found"}},
)

 

 

가령 아래의 path 는 /items/{item_id} 가 된다.

@router.get("/{item_id}")
async def read_item(item_id: str):

 

그리고 아래처럼 global하게 tags와 response를 지정해줘도 또한번 추가로 tags와 reponse를 추가 가능하다.

 

@router.put(
    "/{item_id}",
    tags=["custom"],
    responses={403: {"description": "Operation forbidden"}},
)

 

위 예제에서는 put의 태그는 ["items", "custom"]

두개가 되고 reponse도 404와 403을 가지게 된다.그리고 이것들도 docs에 두개다 반영된다.

 

 

 

 

라우터를 main 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!"}

 

라우터를 main fastapi에 합치는 방법은 include_rounter를 이용하는것이다

app.include_router(users.router)
app.include_router(items.router)

 

 

 

Custom 라우터 세팅

아래 예제는 admin.py에 대한 커스텀 세팅을 나타낸다.

app.include_router(
    admin.router,
    prefix="/admin",
    tags=["admin"],
    dependencies=[Depends(get_token_header)],
    responses={418: {"description": "I'm a teapot"}},
)

 

먼저 컨셉부터 이해하자.

 

회사로부터 여러 프로젝트에 공용으로 쓰이는 admin.py를 당신이 받았다고 치자.

그런데 당신이 이걸 조금 수정해서 쓰려고 한다. 그런데 이 admin.py는 여러군데에서 쓰이는 파일이라 함부로 수정하기가 뭐하다

 

그럴 때 위 예제처럼 include_router 함수를 통해서 admin.py를 수정하지 않고 커스텀 세팅이 가능하다.

 

 

반응형

댓글