๐ป ์ค์ ํ๋ก๊ทธ๋๋ฐ | FastAPI๋ก ๋ง๋๋ ๊ฐ๋จํ Todo List ์ฑ
์๋ ํ์ธ์! ์ค๋์ FastAPI๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ๋จํ Todo List ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค. FastAPI๋ ์ง๋ ๋ช ๋ ๊ฐ Python ๊ฐ๋ฐ์๋ค ์ฌ์ด์์ ๋งค์ฐ ์ธ๊ธฐ๊ฐ ๋์์ง ์น ํ๋ ์์ํฌ๋ก, API ๊ตฌ์ถ์ ์ต์ ํ๋ ์ฑ๋ฅ๊ณผ ํธ๋ฆฌํ ์ฌ์ฉ์ฑ์ ์ ๊ณตํฉ๋๋ค.
FastAPI๋ ๋ฌด์์ธ๊ฐ?
FastAPI๋ ๋น๋๊ธฐ์ฑ์ ๊ธฐ๋ฐ์ผ๋ก ๋์ ์ฑ๋ฅ์ ์ ๊ณตํ๋ Python์ ์๋ก์ด ์น ํ๋ ์์ํฌ์ ๋๋ค. ๋ ๋์ ๊ฐ๋ ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ ์ ๊ณตํ๋ฉฐ, Pydantic์ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ์ฝ๊ฒ ํ ์ ์์ต๋๋ค.
Todo List ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ถ
์ด์ FastAPI๋ก Todo List ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋๋ ๊ณผ์ ์ ๋จ๊ณ๋ณ๋ก ์ดํด๋ณด๊ฒ ์ต๋๋ค. ์ด ํ๋ก์ ํธ๋ CRUD(Create, Read, Update, Delete) ๊ธฐ๋ฅ์ ์ง์ํฉ๋๋ค.
ํ๋ก์ ํธ ์ค์
- ๋จผ์ ํ๋ก์ ํธ ๋๋ ํ ๋ฆฌ๋ฅผ ์์ฑํ๊ณ , ๊ฐ์ ํ๊ฒฝ์ ์ค์ ํฉ๋๋ค.
- ํ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ FastAPI์ Uvicorn, Jinja2 ๋ฑ์ ์ค์นํฉ๋๋ค.
mkdir TODO
cd TODO
python -m venv venv
source venv/bin/activate # Windows์์๋ 'venv\Scripts\activate'
pip install fastapi uvicorn jinja2 python-multipart
FastAPI ์๋ฒ ๊ตฌ์ถ
๋ค์์ผ๋ก, FastAPI์ ๊ธฐ๋ณธ ์๋ฒ๋ฅผ ์ค์ ํฉ๋๋ค. main.py ํ์ผ์ ์์ฑํ์ฌ ์๋์ ๊ฐ์ด ์์ฑํฉ๋๋ค.
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
์๋ฒ๋ฅผ ์คํํฉ๋๋ค.
uvicorn main:app --reload
์ด์ ๊ธฐ๋ณธ์ ์ผ๋ก API๊ฐ ๋์ํฉ๋๋ค. http://localhost:8000
์์ ํ์ธํ ์ ์์ต๋๋ค.
ํํ์ด์ง ํ ํ๋ฆฟ ์์ฑ
Jinja2 ํ ํ๋ฆฟ์ ์ฌ์ฉํด์ Todo ๋ชฉ๋ก์ ๋ณด์ฌ์ค HTML ํ์ผ์ ์์ฑํฉ๋๋ค.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TODO LIST</title>
</head>
<body>
<nav class="navbar bg-body-tertiary">
<div class="container-fluid">
<h1 class="navbar-brand">My To Do list</h1>
</div>
</nav>
<br>
<table class="table">
<tr>
<th>ToDo</th>
<th>Options</th>
</tr>
{% for id in tododict %}
<tr>
<td>{{ tododict[id] }}</td>
<td><a href="/delete/{{ id }}"><button class="btn btn-danger">Delete</button></a></td>
</tr>
{% endfor %}
<tr>
<form method="post" action="/add">
<td><input type="text" name="newtodo" required></td>
<td style="text-align: center;"><button type="submit" class="btn btn-primary">Add New</button></td>
</form>
</tr>
</table>
</body>
</html>
CRUD ๊ธฐ๋ฅ ๊ตฌํ
๊ฐ์ฅ ์ค์ํ ๋ถ๋ถ์ CRUD ๊ธฐ๋ฅ์ ํตํ ๋ฐ์ดํฐ ์กฐ์์
๋๋ค. database.json
ํ์ผ์ ์ด์ฉํด ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ณ ์ฝ์ด์ต๋๋ค.
from fastapi import FastAPI, Request
from fastapi.responses import RedirectResponse
from fastapi.templating import Jinja2Templates
import json
app = FastAPI()
templates = Jinja2Templates(directory="templates")
@app.get("/")
async def root(request: Request):
with open('database.json') as f:
data = json.load(f)
return templates.TemplateResponse("todolist.html", {"request": request, "tododict": data})
@app.get("/delete/{id}")
async def delete_todo(request: Request, id: str):
with open('database.json') as f:
data = json.load(f)
del data[id]
with open('database.json', 'w') as f:
json.dump(data, f)
return RedirectResponse("/", 303)
@app.post("/add")
async def add_todo(request: Request):
with open('database.json') as f:
data = json.load(f)
formdata = await request.form()
newdata = {str(len(data) + 1): formdata["newtodo"]}
data.update(newdata)
with open('database.json', 'w') as f:
json.dump(data, f)
return RedirectResponse("/", 303)
๊ฒฐ๋ก
FastAPI๋ฅผ ํตํด ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฝ๊ฒ ๊ฐ๋ฐํ ์ ์์ผ๋ฉฐ, ์ด ๊ณผ์ ์์ API ๋ฐ ์น ๊ธฐ์ ์ ๋ํ ๊น์ ์ดํด๋ฅผ ์ป์ ์ ์์ต๋๋ค. ์ด๋ฒ ์์ ๋ฅผ ๋ฐ์ ์์ผ ์ฌ์ฉ์ ์ธ์ฆ ์์คํ ์ด๋ ๋ ๋ณต์กํ ๋น์ฆ๋์ค ๋ก์ง์ ์ถ๊ฐํ์ฌ ๊ฐ๋ ฅํ ์น ์๋น์ค๋ฅผ ๊ตฌ์ถํ ์ ์์ต๋๋ค.
๋๊ธ
๋๊ธ ์ฐ๊ธฐ