본문 바로가기

백엔드(FastAPI)

[백엔드 > FastAPI] 5장. 구조화

Planner 애플리케이션 프로젝트 만들기

 

1. Planner 폴더 안에 서브폴더를 만들어준다. 

$ Mkdir database routes models

 

 

2. __init__.py 파일을 모든 폴더 안에 만들어준다.

$ touch {database,routes,models}/__init__.py

 

 

3. Database 폴더에 connection.py 라는 빈 파일을 만들어준다.

(이 파일은 데이터베이스 추상화 설정에 사용되는 파일 입니다.)

 

$ touch database/connection.py

 

 

4. routes와 models 폴더 모두에 events.py 와 users.py 두 개의 파일을 만든다.

$ touch {routes,models}/{events,users}.py

 

  • Routes 폴더
  • Models 폴더

 

주요 기능

  • 등록된 사용자는 이벤트를 추가, 변경, 삭제
  • 이벤트 페이지에서 생성된 이벤트 확인
  • 등록된 사용자, 이벤트는 모두 고유한ID를 가짐 (사용자와 이벤트 중복 방지)
  • 각 사용자는 Events 필드를 가지며 여러 개의 이벤트를 저장

5. 개발을 시작하기에 앞서, 가상화 환경을 활성화한다.

$ python3 -m venv venv

$ source venv/bin/activate

 

6. 애플리케이션 의존 라이브러리 설치 

$ pip install fastapi uvicorn “pydantic[email]”

 

 

7. 필요한 라이브러리를 requirements.txt에 저장

$ pip freeze > requirements.txt

 

8. 사용자 모델과 이벤트 모델을 정의한다.

  • 사용자 모델
from pydantic import BaseModel, EmailStr
from typing import Optional, List
from models.events import Event

class User(BaseModel):
    email: EmailStr
    password: str
    events: Optional[List[Event]]

 

  • 이벤트 모델
from pydantic import BaseModel
from typing import List

class Event(BaseModel):
    id: int
    title: str
    image: str
    description: str
    tags: List[str]
    location: str

 

 

9. 라우트 구현

사용자 라우트 구성

  • 로그인, 로그아웃, 등록으로 구성
  • 인증 완료된 사용자는 이벤트 생성, 변경, 삭제 가능
  • 불인증 사용자는 생성된 이벤트를 확인만 가능

Route 폴더 users.py 에 아래 라우트를 추가한다

아래 라우트는 사용자를 등록하기 전 데이터베이스에 비슷한 이메일이 존재하는지

확인한다.

# 사용자 등록 라우트 정의
from fastapi import APIRouter, HTTPException, status
from models.users import User, UserSignIn

user_router = APIRouter(
    tags=["User"],
)

users = {}

@user_router.post("/signup")
async def sign_new_user(data: User) -> dict:
    if data.email in users:
        raise  HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail="User with supplied username exists"
        )

    users[data.email] = data
    return {
        "message": "User successfully registered"
    }

 

아래 라우트는 로그인하려는 사용자가 데이터베이스에 존재하는지를 먼저 확인한다.

없으면, 예외를 발생시킨다.

(예외: 사용자가 존재하면 패스워드가 일치하는지 확인해서 성공 또는 실패 메세지를 반환)

 

패스워드를 암호화하지 않고 일반 텍스트로 저장했지만 소프트웨어 개발 관점에서는 잘못된 방식임. (Chapter06 데이터베이스 연결 참고)

 

# 로그인 라우트 정의
@user_router.post("/signin")
async def sign_user_in(user:UserSignIn) -> dict:
    if user.email not in users:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User does not exist"
        )

    if users[user.email].password != user.password:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Wrong credentials passed"
        )

    return {
        "message": "User signed in successfully."
    }

 

 

10. Main.py에 라우트를 등록, 애플리케이션 실행

  • 라이브러리와 사용자 라우트 정의를 임포트
  • FastAPI() 인스턴스를 만들고 정의한 라우트 등록
  • Unicorn.run() 메서드를 사용해 8000번 포트에서 애플리케이션 실행 설정
  • Python main.py 를 통해 애플리케이션 실행
from fastapi import FastAPI
from routes.users import user_router
import uvicorn

app = FastAPI()

# 라우트 등록
app.include_router(user_router, prefix="/user")

if __name__ == "__main__":

    uvicorn.run("main:app", host="127.0.0.1", port=8000,reload=True)

 

11. 이벤트 처리용 라우트 구현

  • Routes 폴더 > events.py 의존라이브러리 임포트, 이벤트 라우트 정의
  • 모든 이벤트를 추출 또는 특정 ID의 이벤트만 추출하는 라우트 정의

(예외: 특정ID의 이벤트만 추출하는 라우트에서 해당 ID의 이벤트가 없으면 HTTP_404_NOT_FOUND 예외 발생)

 

12. 이벤트 생성 및 삭제 라우트 정의

  • 첫번째: 이벤트 생성
  • 두번째: 데이터베이스에 있는 단일 이벤트 삭제
  • 세번째: 전체 이벤트 삭제
from fastapi import APIRouter, Body, HTTPException, status
from models.events import Event
from typing import List

event_router = APIRouter(
    tags=["Events"]
)

events = []

# 모든 이벤트 추출 또는 특정 ID의 이벤트만 추출하는 라우트 정의
@event_router.get("/", response_model=List[Event])
async def retrieve_all_events() -> List[Event]:
    return events


@event_router.get("/{id}", response_model=Event)
async def retrieve_event(id: int) -> Event:
    for event in events:
        if event.id == id:
            return event

    raise HTTPException(
        status_code=status.HTTP_404_NOT_FOUND,
        detail="Event with supplied ID does not exist"
    )
    
# 1. 이벤트 생성
@event_router.post("/new")
async def create_event(body: Event = Body(...)) -> dict:
    events.append(body)
    return {
        "message": "Event created successfully."
    }

# 2. 데이터베이스에 있는 단일 이벤트 삭제
@event_router.delete("/{id}")
async def delete_event(id: int) -> dict:
    for event in events:
        if event.id == id:
            events.remove(event)
            return {
                "message": "Event deleted successfully."
            }
    raise HTTPException(
        status_code=status.HTTP_404_NOT_FOUND,
        detail="Event with supplied ID does not exist"
    )

# 3. 전체 이벤트 삭제
@event_router.delete("/")
async def delete_all_events() -> dict:
    events.clear()
    return {
        "message": "Events deleted successfully."
    }

 

 

13. Main.py 라우트 설정 변경, 이벤트 라우트 추가

 

14. 라우트를 테스트한다 (이벤트 등록 - POST)

{
  "id": 1,
  "title": "FastAPI Book Launch",
  "image": "https://linkomyimage.com/image.png",
  "description": "we will be discussing the contents of the FastAPI book in this event. Ensure to come with your own copy to win gifts!",
  "tags": [
    "python", "fastapi", "book", "launch"
  ],
  "location": "Google Meet"
}

 

 

정리

  • Chapter 5에서는 FastAPI 애플리케이션을 구조화하는 방법과 이벤트 플래너 애플리케이션의 라우트와 모델을 구현하였음
  • Chapter 6에서는 애플리케이션을 SQL 및 NoSQL 데이터베이스와 연결하는 방법을 배움
  • 그런 다음 기존 이벤트 플래너 애플리케이션에 새로운 기능 추가할 것

 

'백엔드(FastAPI)' 카테고리의 다른 글

[백엔드 > FastAPI] 8장. 테스트  (0) 2024.01.31
[백엔드 > FastAPI] 7장. 보안  (0) 2024.01.20
[백엔드 > FastAPI] 2장. 라우팅  (0) 2023.12.23