每個 Dart 專案都有一個這樣的文件— — 你知道的。
該檔案充滿了if (value == null || value is! String || value.isEmpty)
檢查。
該文件最初是“快速驗證”,但慢慢地變成了一堆沒人敢碰的意大利麵條程式碼。 🍝
我經歷過這種感覺。事實上,這正是促使我創立Eskema 的動力。
我發現大多數現有的解決方案都依賴程式碼生成,這意味著我最終得到的是固執己見、難以閱讀的樣板程式碼和神秘的生成類別。我想要的是別的東西:一個聲明式的、符合人體工學的、不固執己見的函式庫。一個能夠清楚地展示正在驗證的內容和驗證發生的位置,而不會在我的程式碼庫中堆砌一堆亂七八糟的東西。
Eskema 幾年前最初只是一個小型函數式函式庫,但後來逐漸發展壯大:現在它擁有基於類別的可靠核心、操作符糖和建構器 API。它的擴充功能仍然非常簡單;加入新的驗證器或轉換器基本上很容易,但它的功能足以滿足大多數實際的驗證需求。
Eskema 的主要特色包括:
可組合 API:驗證器只是 Dart 函數,它接受一個值並傳回一個Result
。你可以自由地嵌套和組合它們(使用all()
、 or()
或重載的&
|
運算子)。這使得驗證邏輯高度可組合且易於推理。
豐富的內建驗證器: Eskema 開箱即用,支援類型、數字、字串、列表、映射等驗證。例如, isString()
、 isInt()
、 isEmail()
、 listEach()
、 listIsOfLength()
等等。此外,還包含存在性檢查( isNotNull()
、 isNotEmpty()
、 isPresent()
)和比較性檢查( isGt()
、 isLte()
、 isIn()
等)。
運算子語法糖:將驗證器與&
(與)和|
(或)組合起來,並用not()
進行取反。例如,您可以簡單地寫$isString & isNotEmpty()
,而不是all([isString(), isNotEmpty()])
。您也可以使用>
運算子內聯覆蓋錯誤訊息,例如hasLength(5) > 'must be 5 chars'
。
可選與可空語意:預設情況下,鍵必須存在且非空。使用nullable(validator)
允許欄位為null
,或optional(validator)
允許欄位完全缺失。這有助於避免「無值」和「空值」之間的常見混淆。
建構器 API:如果您喜歡更流暢、類型安全的風格,Eskema 提供了一個建構器 API。例如:
final userValidator = $map().schema({
'id': $string().trim().toIntStrict().gt(0),
'email': $string().trim().toLowerCase().email(),
'age': $string().toIntStrict().gte(18).optional(),
});
無需程式碼產生– 完全在執行時進行:Eskema 在執行時驗證普通的 Dart 映射和值。無需建置步驟,也無需產生類別。
生產就緒:經過全面測試、文件齊全,並附有合理的錯誤訊息。錯誤訊息會產生一個結構化的期望清單(訊息、欄位路徑等),而不僅僅是一個布林值。
以下是使用功能 API 的使用者物件驗證器:
final userSchema = eskema({
'username': isString() & isNotEmpty(),
'password': isString() & hasLength(8, 32),
'email': isString() & isEmail(),
'signupDate': optional(isDateTime()),
});
final result = userSchema.validate({
'username': 'alice',
'password': 'secret123',
'email': '[email protected]',
// signupDate omitted is OK (optional)
});
if (!result.isValid) {
print(result.expectations);
}
每個欄位都對應到一個驗證器。我們將檢查與 & 結合起來,而不是寫成all([...])
,並使用了optional(isDateTime())
來允許 signupDate 缺失。 Result 物件包含.isValid
和.expectations
,其中包含詳細的錯誤訊息。
如果您只需要驗證一個值:
final isNonEmptyStr = isString() & isNotEmpty();
print(isNonEmptyStr.isValid('hello')); // true
print(isNonEmptyStr.validate('').isValid); // false
編寫自訂驗證器也很容易:
Validator isEven = Validator((value) {
return Result(
isValid: value is int && value % 2 == 0,
expected: 'even integer',
);
});
說實話:我們都曾經寫過這樣的驗證程式碼:
// Before: classic if/else soup
bool validateUser(Map<String, dynamic> user) {
if (user['username'] == null || user['username'] is! String || user['username'].isEmpty) {
return false;
}
if (user['password'] == null || user['password'] is! String) {
return false;
}
if ((user['password'] as String).length < 8 || (user['password'] as String).length > 32) {
return false;
}
if (user['email'] == null || user['email'] is! String) {
return false;
}
final email = user['email'] as String;
final emailRegex = RegExp(r'^[^@]+@[^@]+\.[^@]+');
if (!emailRegex.hasMatch(email)) {
return false;
}
return true;
}
這不僅冗長,而且脆弱:難以擴展,難以閱讀,而且容易出錯。
現在,Eskema 表達了同樣的邏輯:
// After: Eskema
final userSchema = eskema({
'username': isString() & isNotEmpty(),
'password': isString() & hasLength(8, 32),
'email': isString() & isEmail(),
});
final result = userSchema.validate({
'username': 'alice',
'password': 'secret123',
'email': '[email protected]',
});
print(result.isValid); // true
簡潔、聲明式、可組合。無需費力地處理 if/else 和正規表示式檢查,只需描述您的期望即可,Eskema 會處理剩下的事情。
對於那些喜歡流暢、IDE 友善方法的人來說,Eskema 的建構器 API 透過方法鏈提供了類似的功能:
**請注意**,一切都是驗證器,因此您可以組合和組成功能和建構器驗證器。
final mapValidator = $map().schema({
'id': $string().trim().toIntStrict().gt(0),
'tags': $list().each($string()).lengthMin(1),
});
// Usage:
final res = mapValidator.validate({'id': '42', 'tags': ['dart', 'eskema']});
print(res.isValid); // true
這與手動驗證器的結果相同,但語法更流暢。其優點在於人體工程學:IDE 自動補全、型別安全,且無需匯入大量自由函數。
使用$
快捷鍵:許多零參數驗證器都有快取的別名。例如, $isString
是一個預先建構的isString()
。它看起來簡潔,並且避免了重新分配函數。如果您想指定自訂錯誤訊息,請使用isString()
運算子重載:熟悉&
、 |
和not()
。它們使模式更簡潔,更易於閱讀。
清除錯誤訊息:使用>
覆蓋訊息,例如hasLength(5) > Expectation(...)
。
無需樣板:開箱即用,適用於 Flutter 表單、API 處理程序、設定檔 - 任何您需要驗證的地方。
非同步支援:需要非同步檢查?只需使用.validateAsync()
即可。 Eskema 會根據需要將驗證器升級為非同步驗證。
Eskema 提供了一個簡單靈活的工具包,讓您輕鬆擺脫執行時驗證的繁瑣。它功能強大,但可組合性極強。您可以驗證巢狀的 JSON、清單或單一值,語法清晰,錯誤報告豐富,無需任何程式碼產生或繁瑣的流程。
如果您的應用程式需要處理動態資料,不妨試試 Eskema。一些符合人體工學的驗證器或許能幫助您擺脫邊緣錯誤,甚至減輕編碼的痛苦。
👉 試試看: GitHub 上的 Eskema 。你未來的自己(以及你的隊友)會感謝你的。