iT邦幫忙

2026 iThome 鐵人賽

DAY 6
0
JavaScript

從看不懂到做出來,用 PawPal 走過前端新手村系列 第 6

Day 6|第一次接手寵物功能,真的沒有想像中簡單

  • 分享至 

  • xImage
  •  

今天的故事

正式開始製作 PawPal 後,我第一個接手的任務,是寵物基本資料相關功能。

我接手時,Dashboard 已經使用假資料呈現寵物卡片。之後我負責建立 pets 資料表與寵物 CRUD API,並把既有的新增按鈕與寵物基本資料彈窗串接真實資料,讓資料能寫入後端並更新 Dashboard。

原本以為只要把既有畫面接上真實資料,再把內容放進對應的位置,這個功能應該不會太困難。

但真正開始做之後,我才發現,一張看起來簡單的寵物卡片,背後其實牽涉到很多事情:

  • 寵物需要哪些資料?
  • 這些資料要用什麼型別保存?
  • 前端欄位要怎麼命名?
  • 資料庫要建立哪些欄位?
  • 寵物資料要怎麼和會員建立關聯?
  • 前端最後要怎麼取得並顯示真實資料?

這也是我第一次感受到:

畫面上看到的只是一張卡片,但一個完整功能遠遠不只有畫面。


一開始只是使用假資料切版

剛開始接手寵物區塊時,Dashboard 上的寵物卡片先使用假資料確認畫面。

概念大概像這樣:

const pet = {
  name: 'Milk',
  species: '貓',
  breed: '英國短毛貓',
  gender: 'male',
  birthday: '2022-05-10',
}

使用假資料的好處,是可以先專心處理前端畫面。

這時候不用等待 API,也不用先處理資料庫,只要確認:

  • 卡片的排版是否正確
  • 寵物名字是否能正常顯示
  • 照片的位置與大小是否合適
  • 不同資料長度會不會讓畫面跑版
  • 手機、平板和電腦版是否能正常呈現

當時的我以為,畫面完成後,接下來只要把假資料換成 API 資料就好了。

後來才發現,事情沒有這麼簡單。


寵物到底需要哪些資料?

當功能準備從假資料走向真實資料時,第一個要處理的問題不是寫 API,而是先決定:

一隻寵物到底需要保存哪些資料?

我們和有養寵物經驗的組員一起討論,整理出飼主實際需要記錄的內容。

除了名字、種類和品種之外,還包含:

  • 性別
  • 生日
  • 體重
  • 晶片號碼
  • 血型
  • 毛色
  • 結紮狀態
  • 寵物照片
  • 備註

這時我才發現,資料欄位不是想到什麼就直接加什麼。

每個欄位都還要進一步思考:

  • 這個欄位是不是必要的?
  • 使用者知道答案嗎?
  • 沒有填寫時要怎麼處理?
  • 適合使用文字、數字、日期,還是布林值?
  • 未來編輯資料時會不會用到?

例如寵物名字通常會是文字:

name: 'Milk'

體重會比較適合使用數字:

weight: 5.2

結紮狀態則可以使用布林值:

neutered: true

生日則需要考慮日期格式:

birthday: '2022-05-10'

以前練習 JavaScript 時,我知道字串、數字和布林值是不同的資料型別。

但直到真正規劃功能時,我才開始理解:

資料型別不是考試中的名詞,而是會直接影響資料怎麼保存、驗證和使用。


從前端畫面一路走到資料庫

原本我接手的是寵物基本資料功能,最先接觸到的是 Dashboard 上既有的寵物卡片與相關畫面。

但當我們開始討論資料從哪裡來時,工作很自然地一路延伸到資料庫和 API。

因為前端想顯示寵物資料,後端就必須能提供資料;後端要提供資料,資料庫裡就必須先有正確的資料表。

整個流程變成:

資料庫建立 pets 資料表
↓
後端建立寵物 API
↓
前端呼叫 API
↓
取得寵物資料
↓
顯示在寵物卡片上

這是我第一次不是只站在前端畫面的角度看功能。

以前我比較容易覺得,前端只要把畫面做出來就完成了。

但這次我開始理解,真實資料要出現在畫面上,必須經過資料庫、後端 API,再回到前端。

少了任何一段,功能都不完整。


第一次建立 pets 資料表

在規劃完欄位後,我開始建立 pets 資料表。

以下是依照當時欄位整理後的簡化範例:

CREATE TABLE pets (
  id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  user_id INTEGER NOT NULL REFERENCES users(id),
  name VARCHAR(100) NOT NULL,
  species VARCHAR(50) NOT NULL,
  breed VARCHAR(100),
  gender VARCHAR(20),
  birthday DATE,
  weight NUMERIC(5,2) CHECK (weight >= 0),
  microchip_number VARCHAR(50) UNIQUE,
  blood_type VARCHAR(20),
  fur_color VARCHAR(100),
  neutered BOOLEAN NOT NULL DEFAULT FALSE,
  avatar_url TEXT,
  notes TEXT
);

這段程式碼不是要一次背起來。

當時對我來說,真正重要的是開始理解每個欄位代表什麼。

例如:

id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY

代表每一隻寵物都會有自己的唯一 ID,而且新增資料時,資料庫會自動產生編號。

name VARCHAR(100) NOT NULL

代表名字是文字,而且不能沒有名字。

birthday DATE

代表生日要使用日期型別。

neutered BOOLEAN NOT NULL DEFAULT FALSE

代表結紮狀態只有兩種主要狀態,可以使用 truefalse

建立資料表時,我也需要使用 AI 協助確認 SQL 語法與欄位型別。

但 AI 給出的建議不能直接全部照抄。

我仍然需要確認:

  • 欄位是不是我們真的需要的
  • 型別是否符合實際資料
  • 哪些欄位必填
  • 哪些欄位允許沒有資料
  • 欄位名稱是否和專案規劃一致

這讓我開始理解,AI 可以幫助我整理與檢查,但資料結構最後仍然要由我們根據功能需求決定。


為什麼寵物資料需要 user_id

pets 資料表中,有一個當時讓我印象很深的欄位:

user_id INTEGER NOT NULL REFERENCES users(id)

一開始我只知道這個欄位和會員有關。

後來才逐漸理解,每一隻寵物都必須知道自己屬於哪一位會員。

假設資料庫裡有很多會員,也有很多寵物:

會員 1
├── Milk
└── Coco

會員 2
├── Lucky
└── Momo

user_id 的外鍵負責保存這筆寵物資料屬於哪一位會員。不過,外鍵本身只定義資料庫的關聯,並不會自動完成 API 的權限控制。

在 PawPal 中,查詢、修改與刪除寵物時,後端會先透過 JWT 驗證取得目前登入會員的 req.userId,再把它放進查詢條件。這樣才能限制會員只能操作自己的寵物資料。

也就是說,user_id 負責資料歸屬;JWT 驗證和後端查詢條件,則負責限制誰可以查詢或操作資料。

這時我第一次比較具體地理解資料表之間的關係:

users
  ↓
一位會員可以擁有多隻寵物
  ↓
pets

以前學習資料庫時,「關聯」對我來說只是名詞。

真正做到寵物功能後,我才知道,資料關聯和 API 權限控管需要分開理解,但兩者會一起影響使用者能看到和操作哪些資料。


API 不是憑空出現的資料

資料表建立後,接著要透過後端 API 讓前端取得寵物資料。

例如前端想取得目前會員的寵物列表,就需要呼叫一支查詢 API。

在 PawPal 中,列表查詢路徑是:

GET /api/v1/pets

前端發出請求後,後端會:

接收請求
↓
確認目前登入會員
↓
從 pets 資料表查詢資料
↓
將結果整理成 JSON
↓
回傳給前端

前端收到資料後,再把內容顯示成寵物卡片。

這讓我開始理解,API 回傳的資料並不是自己出現在畫面上。

它的背後有完整流程:

PostgreSQL
↓
Node.js / Express
↓
API Response
↓
Axios
↓
Vue
↓
寵物卡片

當時我不一定能完整說出每一層的責任,但我開始知道,遇到資料沒有顯示時,不能只看前端畫面。

問題會出現在資料庫、後端、API,或前端接收資料的任何一個位置。


第一次用 Postman 測試 API

在前端正式串接之前,我們先使用 Postman 測試後端 API。

Postman 可以幫助我們直接向後端發送請求,不需要先透過前端畫面。

例如測試查詢寵物資料時,可以確認:

  • API 路徑是否正確
  • 請求方法是否正確
  • 後端是否成功收到請求
  • 回傳狀態碼是什麼
  • Response 裡有沒有寵物資料
  • 欄位名稱是否符合預期

如果 Postman 已經能正確取得資料,代表這次請求經過的後端 API 與資料庫查詢流程基本上可以正常運作。

接著再處理前端串接時,排查範圍就會比較小。

這也是我第一次開始建立「分段測試」的概念。

不是等所有東西都完成後,再一次測整個功能,而是:

先確認資料庫
↓
再確認 API
↓
最後確認前端畫面

重新整理 Supabase 時,我以為資料不見了

第一次使用 Supabase 查看資料時,也發生了一個讓我印象很深的插曲。

當時我在 Postman 新增或測試完資料後,切回 Supabase 查看 pets 資料表。

但重新整理畫面時,我一度以為剛剛建立的資料消失了。

看到畫面沒有按照預期顯示時,我很緊張,開始懷疑:

  • 是不是 API 根本沒有成功?
  • 是不是資料沒有真的寫進去?
  • 是不是重新整理把資料刪掉了?
  • 還是我操作到錯的資料表?

後來重新確認後,才發現資料並沒有真的消失,只是當時對 Supabase 介面和更新方式還不熟悉。

現在回頭看,這只是一個很小的操作問題。

但對第一次接觸資料庫管理介面的我來說,畫面上的任何變化都很容易讓我以為自己把資料弄壞了。

這次經驗也讓我開始養成習慣:

看到資料不見時,不要立刻判斷資料真的被刪除了,而是先重新查詢、確認資料表與 API 回應。


從假資料換成真實資料

當資料表和 API 準備完成後,下一步就是把寵物卡片裡的假資料換成 API 回傳的真實資料。

原本是直接寫在前端:

const pet = {
  name: 'Milk',
  species: '貓',
}

串接後,資料則需要透過 API 取得。以下為省略 API_BASE_URL、共用 API 函式與欄位轉換流程後的簡化範例:

const response = await axios.get('/api/v1/pets', {
  headers: { Authorization: `Bearer ${token}` },
})
const pets = response.data.pets

實際專案會在 src/api/pet.js 透過 listPets() 讀取 pawpal_token、附上 Bearer Token,並使用 mapPetFromApiresponse.data.pets 轉成前端使用的欄位格式。

接著再將取得的資料顯示在畫面上。

當我第一次看到資料庫裡的寵物資料,成功出現在前端寵物卡片上時,我真的很有成就感。

因為那不再只是我手動寫進 JavaScript 的假資料。

而是一筆真正經過:

資料庫
↓
後端 API
↓
前端請求
↓
畫面顯示

的資料。

那一刻我第一次比較清楚地感受到,前端、後端和資料庫不是三個完全分開的東西。

它們是在同一個功能裡一起合作。


畫面顯示出來,不代表完全沒問題

雖然寵物資料成功出現在畫面上,但後來我們也發現,有些欄位沒有按照預期顯示或處理。

當時我一度以為是不是 API 邏輯寫錯,或資料庫沒有正確回傳。

找了很久後才發現,前端、後端與資料庫使用的欄位名稱並沒有完全一致。

例如前端使用:

microchipNumber

但後端和資料庫使用的是:

microchip_number

對人來說,兩個名稱都在表示晶片號碼。

但對程式來說,它們是兩個不同的欄位。

這個問題後來成為我串接 API 時非常深刻的一次經驗。

下一篇會再完整整理,欄位名稱沒有統一時,資料為什麼會對不上,以及我們最後怎麼集中處理轉換。


第一次知道一個功能不只有一張畫面

在接手寵物功能以前,我對前端任務的理解比較接近:

看到設計稿
↓
把畫面切出來
↓
加上互動
↓
完成

但這次真正走過一次後,我才發現,一個功能包含:

確認使用者需求
↓
規劃資料欄位
↓
選擇資料型別
↓
建立資料表
↓
建立 API
↓
測試資料
↓
前端串接
↓
顯示畫面
↓
處理錯誤

原本只是一張寵物卡片,最後卻讓我一路接觸到資料庫、API、會員關聯和前後端串接。

這個過程並沒有想像中順利。

很多時候,我只是先把眼前的問題處理好,再慢慢理解每一段程式和流程為什麼存在。

但也正是因為這個功能,我第一次真正看見一筆資料是怎麼從資料庫走到畫面上的。


今天的學習整理

第一次接手寵物功能,讓我學到幾件事:

  1. 前端畫面上的資料,背後需要資料庫和 API 支援。
  2. 建立欄位前,要先理解使用者真正需要記錄哪些資料。
  3. 字串、數字、布林值和日期會影響資料的保存與使用方式。
  4. 每一隻寵物都需要透過 user_id 和會員建立關聯。
  5. 使用 Postman 可以先確認特定請求的路徑、狀態碼與回傳資料是否符合預期,再處理前端串接。
  6. 假資料適合用來先完成畫面,但最後仍要換成真實資料。
  7. AI 可以協助整理語法與型別,但不能代替團隊做需求判斷。
  8. 一個功能能顯示出來,不代表所有欄位和資料流程都已經正確。

這次真正讓我有成就感的,不只是完成一張寵物卡片。

而是第一次看到自己參與建立的資料,從資料庫經過後端 API,最後真的出現在前端畫面上。

對現在的我來說,這也許只是前後端串接的基本流程。

但對當時剛開始接觸專案的我來說,這是第一次覺得:

原來我真的可以把一個功能,從資料一路做到畫面上。


下一篇預告

寵物資料成功出現在畫面後,我原本以為最困難的部分已經結束了。

但接著我才發現,前端、API 和資料庫只要有一個欄位名稱沒有對上,資料就無法按照預期顯示。

下一篇:

Day 7|表單、API 與資料庫:欄位沒有統一,資料就對不上


上一篇
Day 5|正式認識 PawPal 的架構,準備開始打造第一個功能
下一篇
Day 7|表單、API 與資料庫:欄位沒有統一,資料就對不上
系列文
從看不懂到做出來,用 PawPal 走過前端新手村12
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言