FastApi Python

FastAPI Docs 따라하기

설치

pip install fastapi

fastapi의 설치는 간단합니다. 위와 같이, pip를 통해 간단하게 설치합니다.

pip install uvicorn

fastapi를 사용하기 위해서는 추가로, 서버역할을 하는 uvicorn을 설치해야합니다.


기본예제

from fastapi import FastAPI

app = FastAPI()


@app.get("/")
async def root():
    return {"message": "Hello World"}

docs를 보면 나오는 가장 간단한 FastAPI코드입니다. 해당 코드를 main.py에 작성하고, 서버를 실행해봅시다.

uvicorn main:app --reload

위의 코드로 서버를 실행할 수 있습니다.

이전에 설치한 uvicorn을 이용해서 서버를 실행합니다. main:app의 의미는 main이라는 파이썬 파일에서 app = FastAPI()줄에서 생ㅅ어한 오브젝트를 실행한다는 뜻입니다.

--reload는 변경사항이 있을 때, 재로드 한다는 뜻입니다. 개발할 때 참 편리한 기능입니다.

http://127.0.0.1:8000
http://127.0.0.1:8000/docs
http://127.0.0.1:8000/redoc
http://127.0.0.1:8000/openapi.json

FastAPI는 상당히 많은 도구를 지원해 줍니다. 하나씩 확인해보세요.


경로 동작 데코레이터 정의

from fastapi import FastAPI

app = FastAPI()


@app.get("/")
async def root():
    return {"message": "Hello World"}

위의 코드의 데코레이터를 보면, 경로가 ‘/’ 로 되어 있습니다.

@app.get("/hello")
async def root():
    return {"message": "Hello World- this is hello"}

만약 위와 같이 경로가 ‘/hello’로 설정되어 있다면, http://127.0.0.1:8000/hello 경로는 hello가 됩니다.


동작

여기서 “동작(Operation)”은 HTTP “메소드” 중 하나를 나타냅니다.

다음 중 하나이며:

  • POST
  • GET
  • PUT
  • DELETE

…이국적인 것들도 있습니다:

  • OPTIONS
  • HEAD
  • PATCH
  • TRACE

HTTP 프로토콜에서는 이러한 “메소드”를 하나(또는 이상) 사용하여 각 경로와 통신할 수 있습니다.

FastAPI Docs를 보면 위와같이, 기본적인 동작 이외 이국적인 것 까지 할 수 있습니다.


async def vs def

@app.get("/")
async def root():
    return {"message": "Hello World"}

@app.get("/")
def root():
    return {"message": "Hello World"}

async def와 def가 있는데, async의 경우 응답을 대기하지 않을 때 사용합니다.

async를 사용하면 기본 def보다 좋은 성능을 보여줍니다. 이것이 FastAPI의 장점입니다.


return

Return의 경우, 파이썬답게 딕셔너리를 사용해서 반환합니다.


매개변수 사용하기

from fastapi import FastAPI

app = FastAPI()


@app.get("/items/{item_id}")
async def read_item(item_id):
    return {"item_id": item_id}

위와 같이. {item_id} 처럼 매개변수를 인자로 받고 사용할 수 있습니다.

from fastapi import FastAPI

app = FastAPI()


@app.get("/items/{item_id}")
async def read_item(item_id: int):
    return {"item_id": item_id}

위와같이, int 등의 자료형을 설정하여 사용할 수 있습니다.

저는 플라스크랑 장고를 해본적 있어서 위와같이 사용하는 것이 익숙하네요.


순서문제

from fastapi import FastAPI

app = FastAPI()


@app.get("/users/me")
async def read_user_me():
    return {"user_id": "the current user"}


@app.get("/users/{user_id}")
async def read_user(user_id: str):
    return {"user_id": user_id}

FastAPI는 순서의 문제가 있는데, 위에있는 코드가 우선권을 가지게 됩니다.

즉, http://127.0.0.1:8000/users/me 로 접속할 경우, return 값은, {‘user_id’: “the current user”} 이 됩니다.


Enum 사용하기

from enum import Enum

from fastapi import FastAPI


class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"


app = FastAPI()


@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name == ModelName.alexnet:
        return {"model_name": model_name, "message": "Deep Learning FTW!"}

    if model_name.value == "lenet":
        return {"model_name": model_name, "message": "LeCNN all the images"}

    return {"model_name": model_name, "message": "Have some residuals"}

위와 같이, Enum을 정의하고 클래스를 통해 고정형 값을 사용할 수 있습니다.

이때 http://localhost:8000/docs 로 접속했을 때, FastAPI의 강점을 알겠더라구요. Available values 를 표기해줘서 테스트하기 좋게 구성되어 있습니다.


디폴트값 주기

from fastapi import FastAPI

app = FastAPI()

fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]


@app.get("/items/")
async def read_item(skip: int = 0, limit: int = 10):
    return fake_items_db[skip : skip + limit]

위의 코드와 같이, 디폴트 값을 줄 수 있습니다. 위의 경우 skip이라는 변수에 int=0, limit라는 변수에 int=10이 들어갑니다.


Post

from typing import Optional

from fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item

이전까지 get 요청을 사용했다면, 이번에는 post 요청입니다. Post요청은 위와 같이, 클래스를 선언해서 사용합니다.


Query

from typing import Optional

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: Optional[str] = Query(None, max_length=50)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

쿼리할 때, 조건을 추가할 수 있는데, 위와같이, Query함수를 사용해서 max_length=50 으로 설정할 수 있습니다.

이외에도, min, 정규표현식, 또는 기본값 설정 등 다양한 조건을 추가할 수 있습니다.