[Side Project]Chat App — 實作專案(下)
在上一篇文章中我們已經完成了初始化專案,以及透過 Prisma 來完成資料 Model 的 migration。由於這次的個人專案主要關注在後端的部分,因此我會忽略專案的畫面,只專注於 API 的邏輯部分。
[Side Project]Chat App — 實作專案(下)

在上一篇文章中我們已經完成了初始化專案,以及透過 Prisma 來完成資料 Model 的 migration。由於這次的個人專案主要關注在後端的部分,因此我會忽略專案的畫面,只專注於 API 的邏輯部分。
因為沒有特別作畫面,因此我是使用 Postman [1]這個工具來幫助我測試專案中的 API 功能是否都符合要求,如果各位有相對應的習慣工具可以依照自己的習慣做調整,或是可以做一個簡易的畫面做連接來試試看功能測試。
根據專案設計的架構,接下來就是要來實現 API 的邏輯部分,就跟著我的步驟繼續完成專案吧👨💻
Controller
我的專案採取 MVC [2]這種設計模式 (Design Patterns),在完成 Model 並確認不需要製作 View 之後,接下來的重點是完成 Controller 部分。
而為了實現關注點分離 (Separation of Concerns)[3],我將 Controller 中的處理邏輯分離出來整理成 Services,如此一來,我的 Controller 只會專注在處理資料的管理,避免因 API 的邏輯部分或是程式碼的擴張造成 Controller 的衝突,這不僅提升了程式碼的可讀性和可維護性,也有助於後續除錯。
雖然我的專案不大,但透過這種更高效的管理方式,可以為自己養成良好的Coding 習慣,大家也可以嘗試透過這種小細節或是規範,藉此來不斷的提升自己。
在確認好 Controller 的結構後,我將專案的邏輯部分再進一步分成四個模組來處理,分別是 User、ChatRoom、Friends、Message,以下就讓我們來看我是如何處理邏輯的部分
User
在使用者的部分最主要是要處理會員系統的邏輯,分別是註冊、登入、取得用戶資料、編輯用戶資料,以下就來說明這幾項功能的主要邏輯
- 註冊 — 透過確認密碼以及檢查信箱是否重複做好基本的用戶確認,避免資料上的錯誤,另外使用 bcrypt.js 將密碼做加密存處,避免直接存處明碼遭成資安疑慮。
- 登入 —透過 Passport 套件驗證用戶的帳號和密碼,驗證通過後回傳 JWT token,保持用戶登入狀態。
- 取得用戶資料 — 透過 token 上的資訊來查詢用戶並回傳資料
- 編輯用戶資料 — 確認用戶身分後,接收並更新用戶的修改資料。
大家可能會有疑問為何沒有將登出這部分實做出來,這是因為我有時做一個 authenticate middleware 來對其他部分進行驗證。在各項功能使用前會先確認好身分,也就是確認 token,所以登出部分只需要交給前端做刪除 token 就可以達到登出的功能拉,所以在這裡我就沒有實做了
ChatRoom
在聊天室的部分我主要分成建立聊天室、取得聊天室資訊、建立聊天室連線這三項功能。以下為功能介紹
- 建立聊天室 — 聊天室分為個人和群組,因此在這裡會現做篩選,透過 Model 的 EMUN 來做分類
- 取得聊天室資訊 — 確認使用者身分後獲取該聊天室的資料
- 建立聊天室連線 — 確認使用者身分後建立該聊天室得連線
關於聊天室連線建立的部分,我的邏輯主要是先透過使用者身分的驗證,確認是否有獲取該聊天室的權限,在通過驗證後從後端給予聊天室編號再由前端去做連線。所以連線得部分主要是透過前端,這種方法這裡在對於聊天室的安全性以及資料處理上不是很好,我在一開始進行規畫時做的不夠全面,因此會在之後做修改,這裡先沿用我一開始的想法做介紹。
Friends
在好友部分,分為四個部分:尋找特定朋友、搜尋全部朋友、變更好友狀態和刪除好友。以下是各項功能介紹
- 尋找特定朋友 — 尋找使用者與特定使用者的好友關係
- 搜尋全部朋友 — 尋找使用者所有的好友關係
- 變更好友狀態 — 變更使用者彼此之間的好友狀態,例如好友->封鎖、封鎖->好友、陌生人->好友
- 刪除好友 — 刪除使用者之間的好友關係
好友的邏輯部分,主要是簡單的 CRUD 邏輯操作
Message
訊息邏輯的部分我分成三個部分,傳送訊息、獲取歷史訊息、刪除訊息,以下是各部分的介紹
- 傳送訊息 — 將使用者的訊息傳送到指定的聊天室做存儲
- 獲取歷史訊息 — 通過身分驗證後,讀取該聊天室的所有訊息
- 刪除訊息 — 通過身分驗證後,刪除使用者指定的特定訊息
由於訊息會透過 Socket.io 進行即時的傳送,因此在設計訊息邏輯時,我主要專注於訊息的存儲,確保資料僅能通過驗證後進行讀取和刪除。
在完成上述 Controller 所制定的邏輯後,我們算是完成了基本的專案雛型。為了後續更好的管理專案,我在完成 Controller 的邏輯後在程式碼中使用了 Winston 來進行日誌的管理,什麼是日誌管理呢?為何要使用日誌管理呢?以及如何使用呢?就讓我來介紹一下
什麼是日誌管理?
日誌管理是指在應用程式運行過程中,我們透過套件或是自己設計的方式,來記錄各種操作、事件和錯誤信息的過程。
為何要使用日誌管理?
我們可以透過設置日誌來監控系統狀況、排查問題、分析性能,並且在必要時提供詳細的故障診斷信息。
如何使用 Winston 進行日誌管理?
在了解日誌管理的強大之處以及好處後,我們來學習如何使用日誌管理吧。首先我使用的套件是 Winston,接下來會以 Winston 來做操作
- 安裝 Winston
使用以下指令進行安裝
npm install winston
- 配置 Winston
接著在專案中新增配置檔案 logger.js,我的 Winston 配置如下
import { createLogger, format, transports } from 'winston';
const {
combine, printf, timestamp, colorize,
} = format;
const logger = createLogger({
level: 'info',
format: combine(
timestamp(),
colorize(),
printf((info) => `${info.timestamp} ${info.level}: ${info.message}`),
),
transports: [new transports.Console()],
});
export default logger;
其中,相關客製化的設定可以參考 Winston 官方內容[4]。level 的部分主要是決定需要顯示的訊息等級,format 則是指定訊息輸出的格式。根據上述設定,我的日誌會顯示如下:
2024-07-08T15:37:19.697Z info: It's listen on http://localhost:3000
2024-07-08T15:39:07.061Z info: 登入成功
2024-07-08T15:40:08.002Z error: ValidationError: 尚未建立好友關係
- 引入 Controller 做日誌紀錄
在這裡,我們指的是在處理邏輯的 Services 進行日誌紀錄。透過將 Winston 引入邏輯控制的程式碼中,可以輕易掌握使用者的動向或錯誤紀錄。例如:
import logger from './logger';
const someServiceFunction = () => {
try {
// 處理邏輯
logger.info('某些操作成功');
} catch (error) {
logger.error(`操作失敗: ${error.message}`);
}
}
這樣我們就在專案中完成了基礎的日誌紀錄,是不是相當簡單也很好上手。
以上這樣就算完成專案的 Controller 的部分,整個專案也算是進入尾聲了,如果覺得看完講解還是不太清楚的話,也可以看看我放在 Github 上的專案[5]做為參考,連結我會放在最後面。
之後,我會將專案進行容器化並部署在 AWS 上,會在後續的文章中做詳細紀錄。希望這幾篇文章可以幫助到大家,謝謝。
參考及補充資料: [1]Postman:官方網站 [2]維基百科:MVC [3]維基百科:關注點分離 [4]Winston:官方內容 [5]Github:專案連結
메타데이터
- post_id
- cc9825dd7c1e
- slug
- side-project-chat-app-實作專案-下-cc9825dd7c1e
- url
- https://medium.com/@chacha0519/side-project-chat-app-%E5%AF%A6%E4%BD%9C%E5%B0%88%E6%A1%88-%E4%B8%8B-cc9825dd7c1e
- canonical_url
- https://medium.com/@chacha0519/side-project-chat-app-%E5%AF%A6%E4%BD%9C%E5%B0%88%E6%A1%88-%E4%B8%8B-cc9825dd7c1e
- author_url
- https://medium.com/@chacha0519
- status
- ok
- fetched_at
- 2026-08-28 05:25:41