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 |