설치

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, 정규표현식, 또는 기본값 설정 등 다양한 조건을 추가할 수 있습니다.