資料驗證(上)Pydantic 單一欄位驗證

2024 iThome 鐵人賽

這是 Django Ninja 系列教學的第 19 篇。進入第五章:資料驗證與錯誤處理

資料驗證是 API 開發中的關鍵需求之一,它負責確保從客戶端提交的資料是符合預期的,從而避免潛在的錯誤和安全問題。

有效的資料驗證可以在 API 接收到錯誤資料時,給出即時且友善的回應,提升系統的穩定性和使用者體驗

Django Ninja 中,資料驗證的核心工具是 Pydantic。它提供了強大的驗證功能,不僅能對資料型別進行檢查,還能輕鬆實現自定義驗證

本文將介紹如何在 Django Ninja 中使用 Pydantic 實作單一欄位的自定義驗證;下一篇則講述跨欄位的自定義驗證

本文所有的程式碼變動,可參考這個 PR

快速導覽

👉 完整系列目錄點此查看
👉 程式碼範例GitHub 範例專案


第五章總論

資料驗證很重要,而驗證失敗時,程式往往會拋出驗證錯誤。如何有效處理這些錯誤,則是「錯誤處理」要討論的範疇。

本章將探討這兩個密切相關的主題,共計 4 篇文章:

前兩篇,我們會學習如何實現靈活的資料驗證,以確保輸入資料符合預期,並在必要時拋出錯誤。

後兩篇,我們將討論如何處理 API 流程中可能出現的各種錯誤(不限於驗證錯誤),以提供更好的使用者體驗。

Django Ninja 的資料驗證與錯誤處理機制,相較 Django REST framework 更加複雜,因此我們得用完整的篇幅來介紹,幫助你清楚地理解它們。

API 文件(下)Pydantic Field 設定範例與預設值

2024 iThome 鐵人賽

這是 Django Ninja 系列教學的第 18 篇。

上一篇文章中,我們探討了 Django Ninja 影響 API 文件呈現的一些重要設定。它們是自動化 API 文件的基本功,不容忽視。

但這樣還不夠!我們想要讓這份文件更加生動,讀起來清晰易懂。

其中的關鍵在於 API 文件上的資料範例。好的範例讓人一讀就懂,能有效縮短理解和思考的時間。

本文將介紹如何運用 Pydantic 的Field設定,全方位提升 API 文件的清晰與可讀性。我們會探討如何為自動生成的文件加上栩栩如生的範例,讓文件更貼近真實

本文所有的程式碼變動,可參考這個 PR

快速導覽

👉 完整系列目錄點此查看
👉 程式碼範例GitHub 範例專案


Pydantic 在 Django Ninja 中的角色

Pydantic 是一個實現資料驗證、序列化的套件,廣泛應用於 FastAPI 和 Django Ninja 等框架。

在 Django Ninja 中,Pydantic 被用來定義 Schema,這些 Schema 決定了 API 如何處理 HTTP 請求和回應中的資料,並自動轉換成符合 OpenAPI 標準的文件

Pydantic 的強大之處在於,它不僅能驗證資料,還可以通過Field設定,為文件欄位提供額外的說明、範例和預設值

這些細節設定會自動反映在轉換後的 API 文件中,幫助開發者更好地理解 API 的行為與內涵。

API 文件(上)Django Ninja 文件實踐指南

2024 iThome 鐵人賽

這是 Django Ninja 系列教學的第 17 篇。我們開始第四章——API 文件

依程式碼自動產生 API 文件」是 Django Ninja 的一大賣點。

事實上,API 文件的自動化,正是我在工作上的專案從 Django REST framework 轉向 Django Ninja 的首要考量——也是我開始學習 Django Ninja 的契機。

Django Ninja 省去了大量人工撰寫(我們用 API Blueprint)API 文件的時間,特別是在 API 規格變動時,不需要再同步修改文件,大大減少了維護文件的心力。

可見這個特性有多麼重要。

教學順序的考量

那麼,為何我到了系列的第 17 篇文章——也就是本篇,才開始介紹 Django Ninja 的 API 文件功能呢?

原因在於,要產生優秀的 API 文件,需要你對 Schema 的使用有一定的了解。所以我不得不放在第三章之後。

現在,我們要開始探討如何使用 Django Ninja 產出高品質的 API 文件。

本文所有的程式碼變動,可參考這個 PR

回應(四)Resolver 方法——欄位資料格式化

2024 iThome 鐵人賽

這是 Django Ninja 系列教學的第 16 篇。

上一篇提到,API 回應常常是對 Django Model 物件內容的篩選與加工——然後 JSON 序列化。

其中「加工」部分,用更專業的說法,大概是「資料格式化」——依照一定的規則,對輸出資料進行某種轉換或重新組織,以符合特定的輸出格式

資料格式化的種類很多,例如:

  1. 時間格式轉換:將資料庫中的時間戳(timestamp),轉換為更易讀的格式。
  2. 數值轉換:將數字轉換為貨幣格式,或將小數點位數進行四捨五入。
  3. 字串處理:截斷過長的文字、加上統一的前綴等。

不論原因為何,絕大部分時候都是為了資料的「可讀性」,或符合特定業務規則。

可想而知,像資料格式化這樣的需求,不僅實務上重要,在 API 開發中也十分常見,值得我們用一整篇文章,細細探討。

本文所有的程式碼變動,可參考這個 PR

快速導覽

👉 完整系列目錄點此查看
👉 程式碼範例GitHub 範例專案


場景與需求

再次回到「取得單一文章資訊」API,這是目前的回傳格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
// http://127.0.0.1:8000/posts/2/
{
"id": 2,
"title": "Alice's Django Ninja Post 1",
"content": "Alice's Django Ninja Post 1 content",
"author": {
"id": 1,
"username": "Alice",
"email": "alice@example.com"
},
"created_at": "2024-09-12T02:28:16.801Z",
"updated_at": "2024-09-12T02:28:16.801Z"
}

我們決定簡化回應的時間字串,改採「"2024-09-12T02:28:16Z"」格式。

和舊版相比,只是少了「.801」這個小數部分而已,且依舊符合 ISO 8601 標準。

總之,回應中created_atupdated_at兩個欄位的內容,需要進行格式上的轉換。即上述提到的「資料格式化」。

回應(三)為何不用 ModelSchema?——相比 DRF,我更偏愛 Django Ninja 的理由

2024 iThome 鐵人賽

這是 Django Ninja 系列教學的第 15 篇。

Django API 回應,常常是對 Model 物件(即 db 資料)內容進行一定的篩選與加工

比如「取得單一文章資訊」API,實際上就是從Post物件挑選欄位,再進行序列化。

這個過程中,我們需要考慮如何將模型物件轉換為 API 的回應結構,同時保持程式碼的可維護性與靈活。

對此,Django REST framework(以下簡稱 DRF)提供了非常實用的「特製」序列化器——ModelSerializer,可說是 DRF 開發者必學的核心功能。

Django Ninja 雖然也有類似的實踐——ModelSchema,對我而言卻是雞肋般的存在,我幾乎不曾使用

這樣的差異,無疑是兩者的核心設計理念不同所導致。

我們曾在第 3 篇中討論過,兩者在功能上的主要區別。本文將透過「Django 模型物件的序列化」這個頗具代表性的議題,說明「為何相比於 DRF,我更喜歡寫 Django Ninja」。

回應(二)用 Schema 建立巢狀結構回應

2024 iThome 鐵人賽

這是 Django Ninja 系列教學的第 14 篇。

在 API 開發中,我們經常會遇到關聯模型之間的資料需要同時返回的情況。

特別是在處理「一對一」或「一對多」關聯時,多層結構往往是常態。

我們希望以巢狀結構Nested Objects)的方式返回資料,這樣可以讓 API 的使用者一次取得必要資訊,而不需要進行多次請求。

本文將繼續使用並擴充「單一文章資訊」API 這個範例,講述如何在 Django Ninja 中實現巢狀結構回應,讓我們的 API 回應更加豐富、有體系。

本文所有的程式碼變動,可參考這個 PR

快速導覽

👉 完整系列目錄點此查看
👉 程式碼範例GitHub 範例專案


一、問題背景

在之前的 API 設計中,「取得單一文章資訊」的回應包括了文章資訊及作者的 id

1
2
3
4
5
6
7
class PostResponse(Schema):
id: int
title: str
content: str
author_id: int
created_at: datetime
updated_at: datetime

有經驗的開發者都知道,無論是id還是author_id,通常不是給服務的使用者看的——而是給前端人員靈活運用的。

比如在系統的畫面中,文章可能包括作者的個人資訊連結,點進去可以看到作者資訊。此時前端必須透過 id,再呼叫另一支 API「取得用戶資訊」來獲得額外的內容。

如果額外資訊很多,這樣的「解耦」設計是非常合理的。但如果我們希望一併呈現作者的「必要資訊」,那分次呼叫的設計就略嫌拖沓

所以我們需要巢狀結構

API 可以直接在回應中,嵌入作者的「必要資訊」,這樣用戶就不必再進行多次請求。這裡我們以一併顯示作者的「名字」和「email」為例。

回應(一)Django Ninja 處理 HTTP 回應

2024 iThome 鐵人賽

這是 Django Ninja 系列教學的第 13 篇。

這一篇要正式進入「HTTP 回應」環節,也就是第三小節。

本節將透過 4 篇文章,介紹 Django Ninja 如何處理 HTTP 回應

我們會講述更多 Schema 用法,透過這些技巧,你能夠精確地控制 API 的輸出格式。無論是單一物件回應,還是複雜的嵌套結構,接下來都會一一提及。

本文所有的程式碼變動,可參考這個 PR