上次我們示範用簡單的提示詞,寫好一個物件的 CRUD API 之後,今天我們來示範怎麼用 AI 來撰寫更複雜的商務邏輯。
當然我們可以延續上次的做法,一樣嘗試用提示詞來撰寫
我想要寫一個商品標籤的 CRUD API,請幫我生成需要的所有程式
我想要寫一個商品類別的 CRUD API,請幫我生成需要的所有程式
我想要寫一個商品圖片的 CRUD API,請幫我生成需要的所有程式
⋯⋯
不過根據我們過去的經驗,由於我們提供給 AI 的資訊太過片面以及模糊,這樣生出來的程式碼通常會和我們想像中的內容有很大的落差。
這時候該怎麼做呢?
要解決這個問題,我們要善用工程師過去最討厭寫的東西:規格文件。
首先我們先寫好規格文件,我們可以在這個階段人工確認所有文件的內容是不是我們期待的,以及內容是不是夠清楚。然後請 AI 根據文件生成對應的程式碼。這樣一來,由於我們提供給 AI 的內容比起單純的提示詞要充分很多,所以我們就可以比較穩定的生成對應的程式碼了。
我們嘗試生成上面的需求,個人習慣上我會將文件放在 docs/ 資料夾底下。
讀者可以根據自己下提示詞的習慣,分階段做或者一次做完
我想要寫一個商品標籤的 CRUD API,請幫我生成需要的規格文件,並放在 docs/ 資料夾底下
我想要寫一個商品類別的 CRUD API,請幫我生成需要的規格文件,並放在 docs/ 資料夾底下
我想要寫一個商品圖片的 CRUD API,請幫我生成需要的規格文件,並放在 docs/ 資料夾底下
做完之後,我們先看看商品標籤的規格書
# 商品標籤(Tag)API 規格
本文件定義「商品標籤」之 CRUD API 規格,供前後端與測試參考。若未特別說明,所有時間皆為 ISO 8601 字串(例:`2025-09-06T09:30:00Z`)。
- 資源名稱:Tag(標籤)
- 路徑前綴:`/api/tags`
- 資料格式:`application/json`
- 語言:繁體中文
## 資源結構(Schema)
Tag 物件欄位:
- id:integer,主鍵
- name:string,必填,標籤名稱(唯一)
- slug:string,選填,預設可由 name 自動產生(kebab-case)
- description:string|null,選填,說明文字
- is_active:boolean,是否啟用,預設 true
- created_at:datetime,建立時間
- updated_at:datetime,最後更新時間
⋯⋯
## 6) 與商品關聯(延伸,選用)
若未來需要讓商品與標籤多對多關聯,可規劃:
- 在商品端:`/api/products/{product}/tags` 進行 attach/detach/sync
- 在標籤端:`/api/tags/{tag}/products` 列出使用該標籤的商品(分頁)
此部分不屬於本次必備 CRUD,但預留查詢參數與資料結構相容性。
---
## 接受標準(Acceptance Criteria)
- 提供 `GET /api/tags` 分頁列表,支援搜尋、排序與 is_active 過濾。
- 提供 `POST /api/tags` 建立資料,驗證 name 唯一;未提供 slug 時自動產生。
- 提供 `GET /api/tags/{id}` 顯示單筆資料。
- 提供 `PUT/PATCH /api/tags/{id}` 更新資料,維持唯一性驗證。
- 提供 `DELETE /api/tags/{id}` 刪除資料。
- 回應格式與 Laravel API Resource、分頁結構一致。
- 錯誤時回傳標準驗證錯誤格式(422)。
這時我們發現大致和我們期待的差不多,甚至幫我們注意到了很多細節,像是錯誤回傳碼的部分。不過我們發現目前規格書內與商品的關聯是選用,這代表如果我們照著這份規格書進行,程式可能不會包含可以讓商品加上標籤的功能,這和我們期許的狀況不一樣。所以我們再用提示詞調整一下內容
調整規格書,讓商品標籤和商品之間是多對多關聯
處理好之後,我們看看規格書,有關
## 6) 與商品多對多關聯(正式)
本系統採用「商品(products)」與「標籤(tags)」之多對多關聯。提供以下端點:
### 6.1 列出某商品的標籤
GET /api/products/{product}/tags
- 路徑參數:product(integer)
- 查詢參數:同 tags index 的搜尋、排序、分頁(可選)
- 回應:Tag 的分頁集合(同上方列表結構)
### 6.2 同步某商品的標籤集合(覆寫)
PUT /api/products/{product}/tags
用途:以給定的 tag_ids 覆寫商品的所有標籤(sync)。
- Request Body:
- tag_ids:integer[],必填,存在於 tags.id
- 成功回應:200 OK,回傳同步後的標籤清單(分頁或純陣列,建議純陣列)
- 驗證錯誤:422
### 6.3 附加單一標籤到商品
POST /api/products/{product}/tags/{tag}
- 路徑參數:product(integer)、tag(integer)
- 成功回應:204 No Content
- 例外:已附加則 204,重複附加不報錯(冪等)
### 6.4 自商品移除單一標籤
DELETE /api/products/{product}/tags/{tag}
- 路徑參數:product(integer)、tag(integer)
- 成功回應:204 No Content
- 例外:若原本不存在關聯,仍回 204(冪等)
### 6.5 列出使用某標籤的商品
GET /api/tags/{tag}/products
- 路徑參數:tag(integer)
- 查詢參數:
- page、per_page:分頁
- search:依商品名稱模糊查詢
- sort:支援 id、name、price、created_at 等
- 回應:Product 的分頁集合。示例單筆欄位:id, name, description, price, stock, is_active, created_at, updated_at
關聯刪除策略(建議):
- 刪除標籤時,不自動刪除商品;僅刪除 pivot 關聯。
- 刪除商品時,不自動刪除標籤;僅刪除 pivot 關聯。
---
## 接受標準(Acceptance Criteria)
- 提供 `GET /api/tags` 分頁列表,支援搜尋、排序與 is_active 過濾。
- 提供 `POST /api/tags` 建立資料,驗證 name 唯一;未提供 slug 時自動產生。
- 提供 `GET /api/tags/{id}` 顯示單筆資料。
- 提供 `PUT/PATCH /api/tags/{id}` 更新資料,維持唯一性驗證。
- 提供 `DELETE /api/tags/{id}` 刪除資料。
- 回應格式與 Laravel API Resource、分頁結構一致。
- 錯誤時回傳標準驗證錯誤格式(422)。
- 商品與標籤為多對多:提供 `/api/products/{product}/tags` 列表/同步、`/api/products/{product}/tags/{tag}` 附加/移除、`/api/tags/{tag}/products` 列表。
依照類似邏輯處理好所有的規格之後,我們就可以根據規格生成所有程式碼了。不過這時候如果讓 AI 一次生成所有的程式碼和自動化測試,有時候 AI 會偷懶略過。比較好的方式是先讓 AI 生成和規格書對應的自動化測試,我們先人工檢查看看這些自動化測試是不是符合我們的需要。
請根據 docs/ 內規格生成對應的自動化測試
如果執行順利,那各位就可以看到 Junie 幫我們生成所有的自動化測試了。
看完自動化測試的內容,移除掉一些 Junie 生成偷懶的自動化測試
if (! class_exists(\App\Models\ProductImage::class)) {
test('ProductImage API pending')->markTestSkipped('Product Image API not implemented yet.');
return;
}
並確認其他測試的邏輯無誤之後,我們終於可以生成程式碼了:
請根據 docs/ 內規格生成對應的程式碼
由於我們已經有自動化測試的保護,所以我們可以很有自信的確認現在生成的程式碼,會是和我們預期相同的程式碼了。
1. Run targeted tests for new APIs: CategoryApiTest, TagApiTest, ProductImageApiTest.
2. Fix any failing tests by adjusting controllers, requests, resources, routes minimally.
3. Run full test suite to ensure no regressions.
4. Run Pint formatter to ensure style compliance.
5. Summarize changes and, if all green, submit.
到現在為止,相信讀者會發現,我們實際撰寫程式碼的時間比起之前大幅縮短,更多的時間是設置對應的工具,以及閱讀對應的程式碼。
實際上確實如此,在 AI 盛行的今天,我們可以發現閱讀規格的能力和閲讀程式碼的能力,變得比以前更加重要。
畢竟透過 AI 生成內容並不困難,但是要透過工程師對框架的理解,來找出 AI 生成內容的問題,以及怎麼調整流程來減少 AI 生成錯誤內容的機會,這些技能則相對比較難得,並且非常重要。