FastAPI 서버 환경 세팅

강태원·2023년 12월 8일
1

BACKEND

지난 번 게시글까지 해서 프로젝트에 사용될 AI모델을 학습하였다.
이제부터는 AI모델을 파이썬 백엔드에 붙여서 간단하게 API화 해보도록 하자.

FastAPI

이번에 내가 선택한 웹프레임워크는 FastAPI이다!
Django를 사용해서 이번 프로젝트를 진행하기에는 너무 가벼운 서비스였고,
Flask보다 FastAPI가 차후에 더 널리 쓰일 웹프레임워크라 생각해서 이를 선택하기로 했다.

사실 백엔드로 진행해보는 첫 번째 프로젝트이다..

예상 폴더 구조

MAIN
ㄴ APP/
  ㄴ AI/
  ㄴ API/
    ㄴ V1/
      ㄴ UTILS/
        ㄴ utils.py
      apis...
  ㄴ config.py
  ㄴ database.py
  ㄴ main.py
  ㄴ schemas.py
ㄴ SAVED_MODEL/
  ㄴ model_weights..
ㄴ dataset/
  ㄴ data.tsv
ㄴ .env
ㄴ server.py

프로젝트 생성

FastAPI를 사용하기 위해서 두 라이브러리를 설치해주자
uvicorn은 ASGI 서버를 구동하기 위한 라이브러리며, 비동기를 지원하는 FastAPI를 실행하기 위해 설치해준다.

pip install fastapi uvicorn sqlalchemy

1. server.py

# server.py
# 서버 구동 시 실행해줄 파이썬 스크립트

import uvicorn

if __name__ == "__main__":
	# 서버 구동 이후 디버깅을 위해 reload=True 옵션을 추가한다    
    uvicorn.run("app.main:app", host="0.0.0.0", port=8000, reload=True)

2. app/main.py

# app/main.py

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from app import api

app = FastAPI()

# 프론트를 다른 PC에서 구동할 예정이어서 CORS 에러 방지를 위해
# 미들웨어를 추가해줬다.
app.add_middleware(
    CORSMiddleware,
    allow_origins={"*"},
    allow_credentials=True,
    allow_methods={"OPTIONS", "GET", "POST"},
    allow_headers={"*"},
)

# 서버 최초 구동 시에 데이터베이스와 서버를 연결하는 작업
@app.on_event("startup")
def on_startup():
  from app import models
  from app.database import engine

  models.Base.metadata.create_all(bind=engine)

# 라우터를 포함하는 작업으로 엔드포인트들을 연결해준다
app.include_router(api.router)

3. .env 환경변수

.env 파일을 최상위 폴더에 생성하고 gitingnore에 추가해서 따로 관리하자

DB_USERNAME={USERNAME}
DB_HOST={HOST}
DB_PASSWORD={PASSWORD}
DB_NAME={NAME}
DB_PORT={PORT}

4. app/config.py

# app/config.py
import os
from dotenv import load_dotenv
from functools import lru_cache

load_dotenv()

class Settings():
  DB_USERNAME = os.environ.get("DB_USERNAME")
  DB_HOST = os.environ.get("DB_HOST")
  DB_PASSWORD = os.environ.get("DB_PASSWORD")
  DB_NAME = os.environ.get("DB_NAME")
  DB_PORT = int(os.environ.get("DB_PORT"))

@lru_cache
def get_settings():
    return Settings()

settings = get_settings()

lru_cache 데코레이터를 사용하면, 이 후에 get_settings 함수의 결과를 캐싱해서 빠르게 반환할 수 있도록 도와준다

5. app/database.py

SQLAlchemy ORM을 사용해서 파이썬 코드를 통해 MySQL에 접근할 수 있도록 세팅하는 스크립트다.

# app/database.py
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

from app.config import settings

# MySQL과 연결할 Engine 생성
engine = create_engine(
  "mysql+pymysql://{username}:{password}@{host}:{port}/{name}".format(
    username=settings.DB_USERNAME,
    password=settings.DB_PASSWORD,
    host=settings.DB_HOST,
    port=settings.DB_PORT,
    name=settings.DB_NAME,
  )
)

# SQLAlchemy가 데이터베이스와 상호작용할 때 사용하는 Session생성
SessionLocal = sessionmaker(
    bind=engine,
    autocommit=False,
    autoflush=False,
)

# 이 후 데이터베이스의 테이블을 정의할 때 이 Base를 상속받는다.
Base = declarative_base()

# 엔드포인트에서 Session 객체를 생성할 때 종속성 주입으로 이 함수의 리턴 값을 전달한다.
def get_db():
  db = SessionLocal()
  try:
    yield db
  finally:
    db.close()

6. app/models.py

MySQL의 테이블을 생성하는 코드를 작성하는 스크립트다.

# app/models.py
from sqlalchemy import Column, Integer, DateTime, func
from app.database import Base

# 테이블의 기본이 되는 인덱스, 생성시각, 변경시각을 사전 정의해두자
class BaseMin:
  id = Column(Integer, primary_key=True, index=True)
  created_at = Column(DateTime, nullable=False, default=func.utc_timestamp())
  updated_at = Column(DateTime, nullable=False, default=func.utc_timestamp(),
                      onupdate=func.utc_timestamp())

### 프로젝트를 진행하면서 필요한 테이블들을 추가하자

7. app/schemas.py

Pydantic 라이브러리를 이용하면 Response_model이나 엔드포인트에서 필요한 인자의 타입을 검증할 수 있다. 이에 필요한 class들을 정의하는 스크립트다.

# app/schemas.py
from pydantic import BaseModel

# 프로젝트에서 사용하지는 않지만 예시로 하나 작성해두었다.
### 프로젝트를 진행하면서 필요한 클래스들을 추가하자
class Example(BaseModel):
	id: int
    name: str

이 후 개발을 위한 환경설정을 해주었다. 앞으로 필요한 기능을 하나씩 추가해보면서 프로젝트를 완성해보자!

[수정]

리팩토링을 거치면서 위에서 작성한 폴더 구조도 다르고, 주요 코드들도 바뀌었다.
이후 게시글들과 https://github.com/fnzksxl/capston-design 의 v2 API들을 참고해주길 바란다.

profile
가치를 창출하는 개발자! 가 목표입니다

0개의 댓글