본문 바로가기

MLOps

FastAPI 시작과 CRUD 구현

시작

  • 원래 이전 글에서, 바로 FastAPI를 다루고자 했습니다. 그런데 간단한 API를 만들고 서빙을 하기 위해서는 결국 네트워크에 대한 지식이 아주 약간은 있어야 하기 때문에 관련 설명을 했습니다. 오늘은 원래 목표대로 FastAPI에 대해서 다루겠습니다.

FastAPI

  • 이전 글의 마지막에 언급한 것처럼, FastAPI는 파이썬의 웹 프레임워크 입니다. 외부에서 호출할 수 있는 API를 쉽게 구현할 수 있게 해주는 프레임워크죠.
  • Flask, Django 등 파이썬에는 자주 쓰이는 웹 프레임워크가 있는데, 예시로 FastAPI를 선택한 이유는 이렇습니다.
  • 머신러닝 엔지니어 (또는 데이터 분석가 등)은 파이썬이 가장 익숙한 프로그래밍 언어 일 것 입니다. FastAPI는 이렇게 파이썬에 익숙한 분들에게 더 좋은 언어인데, type hint 등을 이용해 데이터를 검증하는 등의 익숙함도 얻을 수 있습니다. 성능면에서도 빠르고, 비동기를 지원하는 등의 장점도 있죠. 또한 Swagger 라는 것을 이용해서 자동으로 API Docs를 만들어주는 장점도 있습니다.

CRUD

  • Create, Read, Update, Delete의 약자 입니다.
  • 웹 앱이나 API를 구현할때 가장 일반적으로 구현해야 하는 기능이자, 아주 중요한 기능입니다.
  • 이 기능을 구현하고, 실행하면서 FastAPI에 익숙해지는 것을 이번 글의 목표로 해보겠습니다.

세팅

  • 우선 블로그 글을 쓸때는 주로 집에서 작업하기 때문에 윈도우, 근데 또 익숙한건 리눅스 기반의 개발환경이라 WSL을 사용하고 있습니다. (wsl-ubuntu 20.04로 설치)
  • 파이썬 환경 세팅을 위해서는 anaconda를 쓰고 있고, WSL에서 conda를 쓰는 방식은 (https://seethefuture.tistory.com/131) 이글에서 참조했습니다. 다들 편한 방법으로 작업하면 될 것 같습니다.
  • 참고로 VSCODE를 편집기로 사용하는데, WSL 등의 환경에서도 잘 작동해서 유용하게 쓰고있습니다.

Conda 환경

  • Conda 를 사용 경우는 대략 다음과 같이 시작 하겠습니다.
conda create -n crud python=3.8
conda activate crud

필요한 패키지 설치

  • fastapi, 그리고 fastapi를 서버로 실행시키기 위한 uvicorn 설치
pip install fastapi
pip install uvicorn[standard]

CRUD 예제

FastAPI로 웹서버 시작

  • 먼저 main.py 에 아래의 내용을 적어줍니다.
# main.py

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Dict, List

app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "World"}
  • 실행하는 방법은
uvicorn main:app --reload

# uvicorn은 ASGI 서버
# main.py 에서 app 을 실행시키겠다 라는 뜻
# --reload는 코드가 수정 될때마다 서버를 다시 실행시키는 것 -> 즉 개발환경에서만 사용!
  • 실행을 해보면 다음과 같은 줄이 보일 것 입니다.

  • 그리고 실제로 위의 주소인 http://127.0.0.1:8000 에 들어가보면, 다음과 같이 뜹니다.
    • 이게 무슨 의미냐면,  “IP:Port:/”로 접근했을 때 위와 같이 Hello World를 보여주는 웹서버를 만들었다는 의미입니다!

CRUD 기능 추가 및 테스트

  • FastAPI 공식 예제를 따라가도 좋지만, ChatGPT를 통해 예시코드를 작성했습니다.
    • 아까 작성한 main.py에 이어서 다음의 내용을 적어줍니다.
    • 기초적인 CRUD 코드 - product를 CRUD 한다고 보면 됩니다.
class Product(BaseModel):
    name: str
    price: float
    description: str

products = []

@app.post("/products")
def create_product(product: Product):
    products.append(product)
    return product

@app.get("/products")
def get_products():
    return products

@app.get("/products/{product_id}")
def get_product(product_id: int):
    try:
        return products[product_id]
    except IndexError:
        raise HTTPException(status_code=404, detail="Product not found")

@app.put("/products/{product_id}")
def update_product(product_id: int, product: Product):
    try:
        products[product_id] = product
        return product
    except IndexError:
        raise HTTPException(status_code=404, detail="Product not found")

@app.delete("/products/{product_id}")
def delete_product(product_id: int):
    try:
        product = products.pop(product_id)
        return product
    except IndexError:
        raise HTTPException(status_code=404, detail="Product not found")
  • 위의 파일을 만들고 저장을 하면, 서버는 자동으로 다시 만들어집니다. (우리가 아까 서버를 킬때 --reload 옵션을 주었기 때문에)
  • 각 함수의 코드는 짧은데, 뭔가 정신이 없을 수 있습니다. 이걸 FastAPI에서 제공해주는 Docs로 볼수가 있는데, http://127.0.0.1:8000/docs ⇒ 즉 아까 접속한 주소에 /docs를 이어붙여서 실행시켜주면 다음과 같은 화면을 볼 수 있습니다.

  • 위 화면은 Swagger UI의 형태로, 단순히 API가 무엇이 있고 설명만 적혀있는게 아니라, 보통 실제로 API를 사용할 수 있도록 되어있습니다. 일단 Product 가 하나도 존재하지 않은 상황일테니, create product를 해볼 것입니다.
    • POST /products를 누르고, Try it out을 누르면 아래의 화면이 뜹니다.

  • Request body의 항목들을 수정한뒤에 Execute를 눌러주면 됩니다.

  • 성공적으로 보내진 것을 확인할 수 있습니다.
    • 추가로 몇개 더 보내봐도 좋다. 저는 [Coke, 800], [Sprite, 750] 추가했습니다.
  • 다음 예시로는, 그래서 내가 위의 POST /products 를 통해 추가한게 어떻게 되었는지 보겠습니다.
    • 이번엔 GET /products 를 확인해보면 됩니다.

  • 그렇다면 아까 제가 문서에서 추가한 Water, Coke, Sprite가 순서대로 추가되어있는 것을 확인할 수 있습니다.
  • 또 update 기능, delete 기능도 테스트 해보면서, CRUD 기능을 모두 테스트 해볼 수 있습니다.

API 

  • 위에서 쭉 진행한 것이 바로 CRUD 기능을 FastAPI로 구현한 것 입니다. 문서로 직접 들어가서 product를 만들고, 조회하고 하는 행동을 서버의 API로 만든 것이고, client가 server로 Request를 보낸 것 입니다.
  • 우리가 Try it out 버튼을 눌러서, parameter에 적절한 내용을 적고 execute를 누르면 다음과 같이 나옵니다.
    • Swagger 자체에서, 우리가 적은 내용을 어떻게 수정해서 API를 요청했고, 서버에서는 어떻게 Response를 해주었는지에 대한 내용입니다.

  • API를 만든다는 건 위와 같이 어떤 주소로 (IP와 port는 보통 도메인을 이용해서 이름을 바꾸거나 함, IP가 그대로 보이면 보안상의 문제도 있어서) 어떤 정보를 담아서 보내면, 어떤 정보를 주겠다 라고 결정하고 그에 맞게 코드와 서버를 구현한다고 정리할 수 있겠습니다.
  • 이런 API를 설계하는 방법은 정말 다양하겠지만 그 중 가장 유명한 방식이 REST API 또는 RESTful API 입니다. 이전글과 이번글이 어떻게 보면 REST API 또는 RESTful API 형태로 API를 설명하고 구현했다고 할 수 있습니다.
    • 다만, 이런 API 아키텍쳐의 경우에는 아직 저도 개념만 아는 정도이고, 그 외의 형태는 잘몰라서 관련 정보를 얻을만한 주소를 적어두겠습니다. - https://dev-coco.tistory.com/97
  •  

'MLOps' 카테고리의 다른 글

머신러닝 모델 서빙이란 - 서빙이 무엇...?  (0) 2023.03.01