讓 FastAPI 帶你入門全端開發:打造一個簡單的留言板!
嗨,Python 新手們!👋 你是不是對程式設計充滿熱情,想知道如何將 Python 技能從腳本轉化為實際的網路應用?如果你聽過「全端開發」,感覺很高大上,別擔心!今天,我們將一起使用一個超棒的 Python 框架——FastAPI,來打造一個功能齊全的留言板應用,讓你輕鬆體驗前後端協作的樂趣!
這個專案不僅會用到後端 API,還會串接資料庫,並加上一個簡單的前端介面。即使是初學者,也能快速上手,並對整個開發流程有個初步認識。
專案 GitHub 連結:https://github.com/BpsEason/fastapi-message-board.git
為什麼選擇 FastAPI?
在眾多 Python 網頁框架中,FastAPI 異軍突起,受到許多開發者的喜愛。原因如下:
- 速度飛快:名稱中的「Fast」可不是說假的!FastAPI 基於 Starlette (處理 HTTP 請求) 和 Pydantic (處理資料驗證),提供了極高的性能。
- 易學易用:它的設計理念非常直觀,寫起程式碼來非常簡潔。
- 自動生成 API 文件:這是一個超級方便的功能!當你寫好 API 後,FastAPI 會自動生成互動式的 API 文件 (Swagger UI 和 ReDoc),讓測試和協作變得輕而易舉。
- 現代化且支援非同步:原生支援 Python 的
async
/await
,適合開發高效能的非同步應用。
專案概覽:我們要打造什麼?
我們將建立一個留言板應用,包含以下核心功能:
- 創建留言:使用者可以輸入作者和內容,提交新的留言。
- 查看留言:顯示所有已發布的留言。
- 更新留言:可以編輯已發布留言的作者或內容。
- 刪除留言:移除不需要的留言。
這個專案將涵蓋:
- 後端 API:使用 FastAPI 處理所有資料操作。
- 資料庫:使用 MySQL 儲存留言資料。
- 容器化:透過 Docker 輕鬆部署和管理應用環境。
- 前端介面:使用 Bootstrap 5 建立一個簡潔的網頁來展示和操作留言。
專案結構速覽
為了讓專案更有條理,我們會將程式碼分成幾個部分:
├── backend/
│ ├── app/
│ │ ├── main.py # FastAPI 主程式,定義 API 端點
│ │ ├── models.py # 定義資料庫表格結構 (留言)
│ │ ├── schemas.py # 定義資料驗證和序列化模型
│ │ ├── database.py # 資料庫連接設定
│ │ └── crud.py # 定義資料庫的 CRUD (增、查、改、刪) 操作
│ ├── requirements.txt # 後端所需的 Python 套件
│ └── Dockerfile # 後端應用的 Docker 配置
├── frontend/
│ ├── static/
│ │ ├── css/
│ │ │ └── styles.css # 自定義 CSS 樣式
│ │ └── js/
│ │ └── main.js # 前端 JavaScript 邏輯,與後端 API 互動
│ └── templates/
│ └── index.html # 前端網頁的 HTML 模板
├── .env.example # 環境變數範例檔
├── docker-compose.yml # Docker Compose 配置檔,用於啟動所有服務 (後端、資料庫)
└── README.md # 專案說明文件
別被這麼多檔案嚇到了!每個檔案都有它明確的職責,我們會一一解釋。
環境準備:啟動你的開發環境
為了讓專案能順利運行,我們需要用到 Docker。如果你還沒有安裝,請先前往
準備好了嗎?讓我們開始吧!
-
下載專案程式碼
首先,你需要將專案程式碼從 GitHub 下載到你的電腦上。打開你的終端機 (Terminal 或 Command Prompt),輸入以下指令:
Bashgit clone https://github.com/BpsEason/fastapi-message-board.git cd fastapi-message-board
-
配置環境變數
在專案的根目錄下,你會看到一個名為
env.example
的檔案。這個檔案包含了資料庫連接所需的環境變數。請複製一份,並將其命名為.env
:Bashcp env.example .env
打開
.env
檔案,你會看到類似這樣的內容:PlaintextDATABASE_URL=mysql+mysqlconnector://user:password@mysql:3306/messages PORT=8000
這裡的
DATABASE_URL
定義了如何連接到 MySQL 資料庫。在我們的 Docker 設定中,user
、password
、mysql
(資料庫服務名稱) 和messages
(資料庫名稱) 都已預設好,所以對於本地開發,你通常不需要修改它。PORT
則是 FastAPI 應用運行的端口。 -
啟動應用
現在,最令人興奮的一步來了!只需一個指令,Docker Compose 就會自動幫我們建立並啟動所有必要的服務 (FastAPI 後端和 MySQL 資料庫)。
Bashdocker-compose up --build
這個指令會做幾件事:
--build
:如果鏡像不存在或 Dockerfile 有更新,它會重新建立 Docker 鏡像。- 它會啟動
docker-compose.yml
中定義的backend
服務 (我們的 FastAPI 應用) 和mysql
服務 (MySQL 資料庫)。 - FastAPI 應用會自動創建資料庫表格,所以你不需要手動設定資料庫結構。
等待一段時間,直到你看到終端機輸出類似「
Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
」的訊息,這表示你的 FastAPI 應用已經成功啟動了!
體驗你的留言板!
應用啟動後,你就可以在瀏覽器中訪問它了:
- 前端介面:開啟瀏覽器,訪問
http://localhost:8000
。你將看到一個簡潔的留言板頁面,可以在這裡提交新留言、查看、編輯或刪除留言。 - API 文件:訪問
http://localhost:8000/docs
。這是 FastAPI 自動生成的 Swagger UI 介面,你可以透過它來查看所有可用的 API 端點,甚至直接進行測試,非常方便!
程式碼導覽 (快速認識核心檔案)
現在,我們來看看幾個核心檔案的內容,讓你對整個專案有更深入的了解。
backend/app/models.py
- 資料庫模型
這個檔案定義了我們在 MySQL 資料庫中 messages
表格的結構。
from sqlalchemy import Column, Integer, String, DateTime
from sqlalchemy.sql import func
from .database import Base
# 定義留言表格模型
class Message(Base):
__tablename__ = "messages" # 表格名稱為 "messages"
id = Column(Integer, primary_key=True, index=True) # 留言ID,主鍵且有索引
author = Column(String, nullable=False) # 作者,字串類型,不可為空
content = Column(String, nullable=False) # 內容,字串類型,不可為空
created_at = Column(DateTime(timezone=True), server_default=func.now()) # 創建時間,預設為當前時間
這段程式碼使用 SQLAlchemy 庫來定義資料庫中的 Message
表。它指定了留言的 ID、作者、內容以及創建時間,並設定了各自的資料類型和約束。
backend/app/schemas.py
- 資料驗證與序列化
Pydantic 在這裡扮演了重要角色,它幫助我們定義資料的「形狀」,並自動進行驗證。
from pydantic import BaseModel
from datetime import datetime
# 創建留言的輸入格式
class MessageCreate(BaseModel):
author: str # 留言作者必須是字串
content: str # 留言內容必須是字串
# 完整留言的輸出格式
class Message(BaseModel):
id: int
author: str
content: str
created_at: datetime
class Config:
orm_mode = True # 支援 SQLAlchemy ORM 轉換
MessageCreate
定義了創建新留言時需要提供的資料 (作者和內容)。Message
則定義了從資料庫中讀取出來的完整留言資料的結構,包括 id
和 created_at
。orm_mode = True
讓 Pydantic 可以直接從 SQLAlchemy 的 ORM 物件轉換成 Pydantic 模型。
backend/app/crud.py
- 資料庫操作 (CRUD)
CRUD (Create, Read, Update, Delete) 是對資料庫進行操作的四個基本動作。這個檔案包含了與資料庫互動的函式。
from sqlalchemy.orm import Session
from . import models, schemas
# 創建留言
def create_message(db: Session, message: schemas.MessageCreate):
db_message = models.Message(author=message.author, content=message.content)
db.add(db_message) # 將新留言物件加入會話
db.commit() # 提交事務到資料庫
db.refresh(db_message) # 重新整理物件,獲取資料庫生成的值 (如 ID 和創建時間)
return db_message
# 獲取所有留言
def get_messages(db: Session):
return db.query(models.Message).order_by(models.Message.created_at.desc()).all() # 查詢所有留言並按時間降序排列
# ... (其他 update_message 和 delete_message 函式)
你可以看到,create_message
函式接受一個資料庫會話 (db
) 和一個 MessageCreate
物件,然後創建一個 models.Message
實例並將其存入資料庫。get_messages
則負責從資料庫中取出所有留言。
backend/app/main.py
- FastAPI 應用主程式
這是我們的 FastAPI 應用程式的核心,它定義了所有的 API 端點,並將前端介面和後端邏輯連接起來。
from fastapi import FastAPI, Depends, HTTPException
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse
from starlette.requests import Request
from sqlalchemy.orm import Session
from . import models, schemas, crud, database
from typing import List
# 初始化 FastAPI 應用
app = FastAPI(title="留言系統 API")
# 創建資料庫表格 (如果不存在)
models.Base.metadata.create_all(bind=database.engine)
# 掛載靜態檔案與模板
app.mount("/static", StaticFiles(directory="frontend/static"), name="static")
templates = Jinja2Templates(directory="frontend/templates")
# API 端點:獲取首頁
@app.get("/", response_class=HTMLResponse)
async def read_root(request: Request):
"""渲染前端首頁"""
return templates.TemplateResponse("index.html", {"request": request})
# API 端點:創建留言
@app.post("/messages/", response_model=schemas.Message)
async def create_message(message: schemas.MessageCreate, db: Session = Depends(database.get_db)):
"""創建新留言並存入 MySQL"""
return crud.create_message(db=db, message=message)
# ... (其他 get, put, delete 端點)
main.py
做了幾件重要的事情:
- 初始化 FastAPI 應用。
- 在應用啟動時,使用
models.Base.metadata.create_all(bind=database.engine)
自動創建資料庫表格,如果它們還不存在的話。 - 使用
app.mount
掛載了前端的靜態檔案 (CSS 和 JavaScript)。 - 使用
Jinja2Templates
加載前端 HTML 模板。 - 定義了各種 API 端點 (例如
POST /messages/
用於創建留言)。每個端點都通過Depends(database.get_db)
獲取資料庫會話,並呼叫crud.py
中對應的函式來執行資料庫操作。
frontend/templates/index.html
- 前端頁面
這是留言板的 HTML 骨架,它連結了 Bootstrap 框架和我們自定義的 CSS/JavaScript。
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>留言板</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="/static/css/styles.css">
</head>
<body>
<div class="container mt-5">
<h1 class="text-center mb-4">留言板</h1>
<form id="message-form" class="mb-4">
<button type="submit" class="btn btn-primary">提交留言</button>
</form>
<div id="message-list">
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="/static/js/main.js"></script>
</body>
</html>
index.html
包含一個提交留言的表單和一個用於顯示留言的 div
元素。最重要的部分是它引入了 main.js
,所有的前端邏輯都在那裡。
frontend/static/js/main.js
- 前端邏輯
這個 JavaScript 檔案負責與後端 API 進行互動,獲取、顯示、新增、編輯和刪除留言。
const apiUrl = '/messages/';
async function fetchMessages() {
const response = await fetch(apiUrl); // 從後端獲取所有留言
const messages = await response.json();
const messageList = document.getElementById('message-list');
messageList.innerHTML = ''; // 清空現有留言
messages.forEach(msg => {
// 動態創建留言卡片並添加到頁面
const card = document.createElement('div');
card.className = 'card message-card';
card.innerHTML = `
<div class="card-body">
<h5 class="card-title">${msg.author}</h5>
<p class="card-text">${msg.content}</p>
<p class="card-text"><small class="text-muted">${new Date(msg.created_at).toLocaleString('zh-TW')}</small></p>
<button class="btn btn-sm btn-warning" onclick="editMessage(${msg.id})">編輯</button>
<button class="btn btn-sm btn-danger" onclick="deleteMessage(${msg.id})">刪除</button>
</div>
`;
messageList.appendChild(card);
});
}
async function createMessage(author, content) {
const response = await fetch(apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ author, content }) // 將資料轉換為 JSON 格式發送
});
if (response.ok) fetchMessages(); // 如果成功,重新載入留言列表
}
// ... (editMessage 和 deleteMessage 函式)
document.getElementById('message-form').addEventListener('submit', async (e) => {
e.preventDefault(); // 阻止表單預設提交行為
const author = document.getElementById('author').value;
const content = document.getElementById('content').value;
await createMessage(author, content);
e.target.reset(); // 提交後清空表單
});
window.onload = fetchMessages; // 頁面載入時自動獲取留言
main.js
使用 fetch
API 來向後端發送 HTTP 請求。當頁面載入時,fetchMessages()
會被呼叫以顯示所有現有的留言。當用戶提交表單時,createMessage()
會將數據發送到後端。編輯和刪除功能也透過類似的 fetch
請求來實現。
恭喜你!🎉
你已經成功地運行了你的第一個全端留言板應用!這是一個很棒的開始。透過這個專案,你已經接觸到了:
- 後端框架:FastAPI 的基本用法。
- 資料庫互動:如何透過 ORM (SQLAlchemy) 操作資料庫。
- API 設計:如何定義 RESTful API 端點。
- 前後端溝通:前端如何透過 JavaScript (Fetch API) 與後端 API 互動。
- 容器化:Docker 和 Docker Compose 的基本使用,讓環境配置變得簡單。
下一步:繼續探索!
- 深入了解 FastAPI:查閱 FastAPI 的官方文件,學習更多高級特性,例如認證、依賴注入等。
- 前端優化:你可以嘗試為留言板添加更多樣式,或者使用更進階的前端框架 (如 React、Vue 或 Angular)。
- 錯誤處理:在 API 中加入更完善的錯誤處理機制,讓應用更健壯。
- 單元測試:為你的後端 API 編寫單元測試,確保功能的穩定性。
希望這篇文章能為你的 Python 全端開發之旅點亮一盞燈。祝你編程愉快!如果你有任何問題或建議,歡迎在留言區討論!
沒有留言:
張貼留言