일기장 앱을 만드는 프로젝트를 예시로 들어보려고 한다.

 

프로젝트 구조는 다음과 같다

 

 

main.py : uvicorn 서버 실행 메소드가 담겨있는 메인 파일 , python3 app/main.py 로 실행하면 서버가 실행된다.

 

server 폴더

routes 폴더 : 라우터 파일들이 담겨있다. django의 urls.py 와 views.py 같은 느낌이라고 생각하면 될 것 같다

app.py : main.py 실행시 실행된다. FastAPI 앱 인스턴스 생성과 라우터 연결 등의 역할을 맡고 있다.

database.py : database와 연결된 부분을 관리한다. db에 정보를 저장하거나 불러오는 함수들을 가지고 있다.

exceptions.py : 예외처리 클래스들이 구현되어있다.

models.py : model 들이 구현되어있다. 응답양식, 데이터 모델 등등

 

자세한 코드를 알아보자

#main.py

import uvicorn

if __name__ == "__main__":
    uvicorn.run("server.app:app",host = "0.0.0.0", port = 8000, reload = True)

main.py 실행시 uvicorn을 이용해 app.py를 실행하는 서버를 띄운다.

 

#app.py

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from .routes import diary_router,search_router
from app.server.exceptions import APIException

app = FastAPI()
app.include_router(diary_router.router)
app.include_router(search_router.router)

@app.exception_handler(APIException)
async def api_exception_handler(request: Request, exc: APIException):
    return JSONResponse(
        status_code =  exc.status_code,
        content = exc.content
    )

app.py에선 FastAPI객체를 만들고 router를 추가한다.

예외처리 세팅도 여기서 한다.

 

#diary_router.py

from fastapi import APIRouter
from fastapi.encoders import jsonable_encoder
from app.server import database
from app.server.models import responseModel,Diary,UpdateDiary

router = APIRouter(prefix = "/diaries")

@router.get("",response_description="get all diaries")
async def get_all_diaries():
    response_message = "all diaries"
    diaries = await database.get_diaries()
    return responseModel(response_message, diaries)

@router.get("/{date}", response_description="read a diary")
async def get_a_diary(date: str):
    response_message = "read a diary"
    diary = await database.get_diary(date)
    return responseModel(response_message,diary)

/diaries 로 시작하는 url이 들어왔을때 app.py 에서 diary_router로 연결을 해준다.

diary_router에선 database.py의 db조회 함수를 사용해 db에서 일기장 정보들을 조회해 받아온다.

받아온 정보를 responseModel을 이용해 client에 반환한다.

 

#database.py

from motor import motor_asyncio
from .models import Diary
from app.server.exceptions import *

host = 'localhost'
port = 27017

#database settings
def get_db():
    client = motor_asyncio.AsyncIOMotorClient(host,port)
    db = client.iaryda
    return db

diary_collection = get_db().get_collection("diary")

#helpers
def diary_helper(diary) -> dict:
    diary.pop("_id")
    return diary

#db 조회, 관리 함수
async def get_diaries() -> list:
    result_data = []
    
    async for diary in diary_collection.find():
        result_data.append(diary_helper(diary))
        
    return result_data


async def get_diary(date: str) -> dict:
    diary = await diary_collection.find_one({"date" : date})
    if diary != None:
        return diary_helper(diary)
    else:
        raise DiaryDoseNotExistExecption()

database.py파일에서 db연결 및 조회 함수를 만들었다.

motor 를 이용해 몽고디비와 파이썬을 연결했다.

 

몽고디비에서 document를 저장할때 _id 항목을 생성해주는데

_id 항목은 굳이 client에 전달할 필요가 없으므로 _id를 제외해주는 diary_helper 함수를 만들어 사용했다.

 

오류가 발생하는 경우 exception 클래스를 이용해 오류 메세지를 전달한다.

 

#models.py

def responseModel(message, data) -> dict:
    if type(data) == list:
        return {
            "status" : 200,
            "message" : message,
            "data" : data
        }
    else:
        return {
            "status" : 200,
            "message" : message,
            "data" : [data]
        }

responseModel 함수는 models.py에 구현돼있다.

일정한 양식으로 응답을 할 수 있도록 해준다.

 

#exceptions.py

class StatusCode:
    HTTP_500 = 500
    HTTP_200 = 200
    
def make_error_content(message) -> dict:
    return {
        "status" : StatusCode.HTTP_500,
        "message" : message,
        "data" : []
    }
    
class APIException(Exception):
    status_code : int
    content: dict
        
class DiaryDoseNotExistExecption(APIException):
    def __init__(self,):
        self.status_code = StatusCode.HTTP_500
        self.content = make_error_content("Unvalid date. There is no diary in this date")

exceptions.py에선 오류 메세지 전달을 구현했다.

Exception객체를 상속하는 APIException 클래스를 먼저 만든 후 app.py에 exception_handler를 설정해준다.

 

그 이후 APIException 을 상속하는 exception 클래스들을 만든 후 사용하면 된다.

 

 

결론은 사용자에게서 요청이 오면 

app.py -> router -> database -> router ->  응답 반환 순으로 이루어진다.

 

router 파일들을 좀 더 손볼 필요가 있을 것 같긴한데

일단 이렇게 만들어놨다.

'FastAPI' 카테고리의 다른 글

사지방에서 FastAPI 공부하기 #1 - 개발환경 설정  (0) 2023.03.19

요즘 그렇게 핫하다는 (사실 예전부터 핫했지만 내가 이제 알았다)

파이썬 프레임워크 FastAPI를 찍먹해보려한다.

 

전부터 공부하고 싶었던 분야가

1. NoSQL Database (MongoDB)

2. 마이크로서비스

였는데 FastAPI로 프로젝트를 준비하면서 같이 찍먹해보려한다.

 

일단 FastAPI 찍먹을 해볼겸 간단한 프로젝트를 하면서 몽고디비 공부를 같이하고

나중에 이 프로젝트에 이것 저것 추가할 기능이 생긴다면 자연스럽게 마이크로서비스 공부로 이어가면 되지 않을까? 싶다.

 

 

개발환경 설정

사지방에서 공부를 하고 있기 때문에 Goorm IDE를 사용했다.

 

1. MongoDB 설치

Goorm IDE에서 컨테이너를 생성할때 기본 옵션으로 MongoDB 설치가 가능하다.

MongoDB 설치 체크박스를 클릭하고 컨테이너를 생성하자.

만약 못 했다면 아래 주소를 참고하자.

https://help.goorm.io/ko/goormide/18.faq/language-and-environment/how-to-install-mongodb

 

MongoDB를 설치하고 싶습니다 - goorm

apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 9DA31620334BD75D9DCB49F368818C72E52529D4 && (echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/4.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-4.0.list) &&

help.goorm.io

2. 가상환경 생성 및 fastapi 설치

mkdir venvs
cd venvs
python3 -m venv venv_for_fastapi #가상환경 생성

cd venv_for_fastapi/bin
source activate # 가상환경 실행

python venv 를 이용해 가상환경을 설치해줬다.

source activate를 이용해 가상환경을 실행시키자.

pip install fastapi
pip install uvicorn
pip install --upgrade pip

가상환경 실행 후 fastapi와 uvicorn을 설치해준다.

(fastapi 만으론 웹 개발이 불가능, uvicorn을 이용해 서버를 실행시키고 배포한다.)

 

3. 실행 url 및 포트 관리

좌측 상단 > 프로젝트 > 실행 ur과 포트 항목에서 원하는 url을 설정하고 포트 번호를 8000(fastapi 기본 포트)로 등록한후 확인을 누른다.

그리고 나온 url을 복사해둔다.

4. main.py 작성 및 테스트

#main.py
from fastapi import FastAPI

app = FastAPI() 

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

main.py 파일을 만든 이후 다음과 같이 작성해본다.

이후 터미널에서 아래 명령어를 입력한다.

uvicorn main:app --reload #기본 명령어
uvicorn main:app --reload --host=0.0.0.0 --port=8000 #goorm ide로 실행할때

그 후 3번에서 복사한 url로 접속해보면

hello world가 띄워져 있는 것을 확인 할 수 있다.

 

 

'FastAPI' 카테고리의 다른 글

사지방에서 FastAPI 공부하기 #2 - 프로젝트 구조  (1) 2023.04.01

+ Recent posts