據 AlphaMoat 統計,截至 2026-09,Data Validation 累計下載 3,691 次、獲 1 個星標,在全部 5,078 個 AI 技能中排名第 2,920 位,在「開發程式設計」分類(577 個)中排名第 377 位。
| 平台 | 累計安裝 | 累計下載 | 星標 | 評論 |
|---|---|---|---|---|
| ClawHub ↗ | 117 | 3691 | 1 | - |
各平台的計數口徑不同,統計時間不一致。
適用於驗證 API 請求響應、使用者輸入、CSV/JSON 完整性、服務間資料契約和 ETL 遷移結果。
資料釋出於 2026-10-29
以下是根據技能文件生成的示例,不代表實際執行結果。
2026-09 起統計方法調整:同名技能按作者分別統計,並覆蓋全部技能。圖中虛線為調整前的月份,與之後的資料不直接比較,也不計算跨越調整的增長。
| 月份 | 累計下載 | 環比 | 星標 |
|---|---|---|---|
| 2026-09 | 3691 | — | 1 |
| 2026-08 | 3553 | +6.0% | 1 |
| 2026-07 | 3351 | +9.5% | 1 |
| 2026-06 | 3060 | +5.5% | 1 |
| 2026-05 | 2900 | — | 1 |
| 2026-03 | 2255 | — | 1 |
以下是作者釋出的原始檔案,按純文字顯示,本站未做修改或稽核;其中的連結不可點選,命令請核實後再執行。抓取於 2026-10-23。
---
name: data-validation
description: Validate data with schemas across languages and formats. Use when defining JSON Schema, using Zod (TypeScript) or Pydantic (Python), validating API request/response shapes, checking CSV/JSON data integrity, or setting up data contracts between services.
metadata: {"clawdbot":{"emoji":"✅","requires":{"anyBins":["node","python3","jq"]},"os":["linux","darwin","win32"]}}
---
# Data Validation
Schema-based data validation across languages and formats. Covers JSON Schema, Zod (TypeScript), Pydantic (Python), API boundary validation, data contracts, and integrity checking.
## When to Use
- Defining the shape of API request/response bodies
- Validating user input before processing
- Setting up data contracts between services
- Checking CSV/JSON file integrity before import
- Migrating data (did the ETL preserve everything?)
- Generating types or documentation from schemas
## JSON Schema
### Basic schema
```json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["name", "email", "age"],
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"email": {
"type": "string",
"format": "email"
},
"age": {
"type": "integer",
"minimum": 0,
"maximum": 150
},
"role": {
"type": "string",
"enum": ["user", "admin", "moderator"],
"default": "user"
},
"tags": {
"type": "array",
"items": { "type": "string" },
"uniqueItems": true,
"maxItems": 10
},
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" },
"zip": { "type": "string", "pattern": "^\\d{5}(-\\d{4})?$" }
},
"required": ["street", "city"]
}
},
"additionalProperties": false
}
```
### Common patterns
```json
// Nullable field
{ "type": ["string", "null"] }
// Union type (string or number)
{ "oneOf": [{ "type": "string" }, { "type": "number" }] }
// Conditional: if role is admin, require permissions
{
"if": { "properties": { "role": { "const": "admin" } } },
"then": { "required": ["permissions"] }
}
// Pattern properties (dynamic keys)
{
"type": "object",
"patternProperties": {
"^env_": { "type": "string" }
}
}
// Reusable definitions
{
"$defs": {
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" }
}
}
},
"properties": {
"home": { "$ref": "#/$defs/address" },
"work": { "$ref": "#/$defs/address" }
}
}
```
### Validate with command line
```bash
# Using ajv-cli (Node.js)
npx ajv-cli validate -s schema.json -d data.json
# Using jsonschema (Python)
pip install jsonschema
python3 -c "
import json, jsonschema
schema = json.load(open('schema.json'))
data = json.load(open('data.json'))
jsonschema.validate(data, schema)
print('Valid')
"
# Validate multiple files
for f in data/*.json; do
npx ajv-cli validate -s schema.json -d "$f" 2>&1 || echo "INVALID: $f"
done
```
## Zod (TypeScript)
### Basic schemas
```typescript
import { z } from 'zod';
// Primitives
const nameSchema = z.string().min(1).max(100);
const ageSchema = z.number().int().min(0).max(150);
const emailSchema = z.string().email();
const urlSchema = z.string().url();
// Objects
const userSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
age: z.number().int().min(0),
role: z.enum(['user', 'admin', 'moderator']).default('user'),
tags: z.array(z.string()).max(10).default([]),
createdAt: z.string().datetime(),
});
// Infer TypeScript type from schema
type User = z.infer<typeof userSchema>;
// { name: string; email: string; age: number; role: "user" | "admin" | "moderator"; ... }
// Validate
const result = userSchema.safeParse(data);
if (result.success) {
console.log(result.data); // typed as User
} else {
console.log(result.error.issues); // validation errors
}
// Parse (throws on invalid)
const user = userSchema.parse(data);
```
### Advanced patterns
```typescript
// Optional and nullable
const schema = z.object({
name: z.string(),
nickname: z.string().optional(), // string | undefined
middleName: z.string().nullable(), // string | null
suffix: z.string().nullish(), // string | null | undefined
});
// Transforms (validate then transform)
const dateSchema = z.string().datetime().transform(s => new Date(s));
const trimmed = z.string().trim().toLowerCase();
const parsed = z.string().transform(s => parseInt(s, 10)).pipe(z.number().int());
// Discriminated unions (tagged unions)
const eventSchema = z.discriminatedUnion('type', [
z.object({ type: z.literal('click'), x: z.number(), y: z.number() }),
z.object({ type: z.literal('keypress'), key: z.string() }),
z.object({ type: z.literal('scroll'), delta: z.number() }),
]);
// Recursive types
const categorySchema: z.ZodType<Category> = z.object({
name: z.string(),
children: z.lazy(() => z.array(categorySchema)).default([]),
});
// Refinements (custom validation)
const passwordSchema = z.string()
.min(8)
.refine(s => /[A-Z]/.test(s), 'Must contain uppercase')
.refine(s => /[0-9]/.test(s), 'Must contain digit')
.refine(s => /[^a-zA-Z0-9]/.test(s), 'Must contain special character');
// Extend/merge objects
const baseUser = z.object({ name: z.string(), email: z.string() });
const adminUser = baseUser.extend({ permissions: z.array(z.string()) });
// Pick/omit
const createUser = userSchema.omit({ createdAt: true });
const userSummary = userSchema.pick({ name: true, email: true });
// Passthrough (allow extra fields)
const flexible = userSchema.passthrough();
// Strip unknown fields
const strict = userSchema.strict(); // Error on extra fields
```
### API validation with Zod
```typescript
// Express middleware
import { z } from 'zod';
const createUserBody = z.object({
name: z.string().min(1),
email: z.string().email(),
password: z.string().min(8),
});
app.post('/api/users', (req, res) => {
const result = createUserBody.safeParse(req.body);
if (!result.success) {
return res.status(400).json({ errors: result.error.issues });
}
const { name, email, password } = result.data;
// ... create user
});
// Query parameter validation
const listParams = z.object({
page: z.coerce.number().int().min(1).default(1),
limit: z.coerce.number().int().min(1).max(100).default(20),
sort: z.enum(['newest', 'oldest', 'name']).default('newest'),
q: z.string().optional(),
});
app.get('/api/users', (req, res) => {
const params = listParams.parse(req.query);
// params.page is a number, params.sort is typed
});
```
## Pydantic (Python)
### Basic models
```python
from pydantic import BaseModel, Field, EmailStr, field_validator
from typing import Optional
from datetime import datetime
from enum import Enum
class Role(str, Enum):
USER = "user"
ADMIN = "admin"
MODERATOR = "moderator"
class Address(BaseModel):
street: str
city: str
zip_code: str = Field(pattern=r"^\d{5}(-\d{4})?$")
class User(BaseModel):
name: str = Field(min_length=1, max_length=100)
email: EmailStr
age: int = Field(ge=0, le=150)
role: Role = Role.USER
tags: list[str] = Field(default_factory=list, max_length=10)
address: Optional[Address] = None
created_at: datetime = Field(default_factory=datetime.now)
@field_validator("name")
@classmethod
def name_must_not_be_empty(cls, v: str) -> str:
if not v.strip():
raise ValueError("name cannot be blank")
return v.strip()
# Validate
user = User(name="Alice", email="[email protected]", age=30)
print(user.model_dump()) # dict
print(user.model_dump_json()) # JSON string
# Validation errors
try:
User(name="", email="bad", age=-1)
except Exception as e:
print(e) # Detailed validation errors
```
### Advanced patterns
```python
from pydantic import BaseModel, model_validator, ConfigDict
from typing import Literal, Union, Annotated
# Discriminated union
class ClickEvent(BaseModel):
type: Literal["click"]
x: int
y: int
class KeypressEvent(BaseModel):
type: Literal["keypress"]
key: str
Event = Annotated[Union[ClickEvent, KeypressEvent], Field(discriminator="type")]
# Model-level validation (cross-field)
class DateRange(BaseModel):
start: datetime
end: datetime
@model_validator(mode="after")
def end_after_start(self):
if self.end <= self.start:
raise ValueError("end must be after start")
return self
# Strict mode (no type coercion)
class StrictUser(BaseModel):
model_config = ConfigDict(strict=True)
age: int # "30" will be rejected, must be int 30
# Alias (accept different field names in input)
class APIResponse(BaseModel):
user_name: str = Field(alias="userName")
created_at: datetime = Field(alias="createdAt")
model_config = ConfigDict(populate_by_name=True)
# Computed fields
from pydantic import computed_field
class Order(BaseModel):
items: list[dict]
tax_rate: float = 0.08
@computed_field
@property
def total(self) -> float:
subtotal = sum(i.get("price", 0) * i.get("qty", 1) for i in self.items)
return round(subtotal * (1 + self.tax_rate), 2)
# Generate JSON Schema
print(User.model_json_schema())
```
### FastAPI integration
```python
from fastapi import FastAPI, Query
from pydantic import BaseModel
app = FastAPI()
class CreateUser(BaseModel):
name: str = Field(min_length=1)
email: EmailStr
password: str = Field(min_length=8)
class UserResponse(BaseModel):
id: int
name: str
email: str
@app.post("/api/users", response_model=UserResponse)
async def create_user(body: CreateUser):
# body is already validated
return {"id": 1, "name": body.name, "email": body.email}
@app.get("/api/users")
async def list_users(
page: int = Query(default=1, ge=1),
limit: int = Query(default=20, ge=1, le=100),
q: str | None = Query(default=None),
):
# All params validated and typed
pass
```
## Data Integrity Checks
### CSV validation
```bash
#!/bin/bash
# validate-csv.sh — Check CSV structure and data quality
FILE="${1:?Usage: validate-csv.sh <file.csv>}"
echo "=== CSV Validation: $FILE ==="
# Row count
ROWS=$(wc -l < "$FILE")
echo "Rows: $ROWS (including header)"
# Column count consistency
HEADER_COLS=$(head -1 "$FILE" | awk -F',' '{print NF}')
echo "Columns (header): $HEADER_COLS"
BAD_ROWS=$(awk -F',' -v expected="$HEADER_COLS" 'NR>1 && NF!=expected {count++} END {print count+0}' "$FILE")
if [ "$BAD_ROWS" -gt 0 ]; then
echo "ERROR: $BAD_ROWS rows have wrong column count"
awk -F',' -v expected="$HEADER_COLS" 'NR>1 && NF!=expected {print " Line "NR": "NF" columns (expected "expected")"}' "$FILE" | head -5
else
echo "Column count: consistent"
fi
# Empty fields
EMPTY=$(awk -F',' '{for(i=1;i<=NF;i++) if($i=="") count++} END {print count}' "$FILE")
echo "Empty fields: $EMPTY"
# Duplicate rows
DUPES=$(($(sort "$FILE" | uniq -d | wc -l)))
echo "Duplicate rows: $DUPES"
echo "=== Done ==="
```
### JSON validation
```bash
# Check if file is valid JSON
jq empty data.json && echo "Valid JSON" || echo "Invalid JSON"
# Validate structure of each object in an array
jq -e '
.[] |
select(
(.name | type) != "string" or
(.email | type) != "string" or
(.age | type) != "number" or
.age < 0
)
' data.json && echo "INVALID records found" || echo "All records valid"
# Check for required fields
jq -e '.[] | select(.id == null or .name == null)' data.json
# Check for unique IDs
jq '[.[].id] | length != (. | unique | length)' data.json
# true = duplicates exist
# Compare record counts between source and target
SRC=$(jq length source.json)
TGT=$(jq length target.json)
echo "Source: $SRC, Target: $TGT, Match: $([ "$SRC" = "$TGT" ] && echo yes || echo NO)"
```
### Migration validation
```python
#!/usr/bin/env python3
"""Validate that a data migration preserved all records."""
import json
import sys
def validate_migration(source_path, target_path, key_field="id"):
with open(source_path) as f:
source = {r[key_field]: r for r in json.load(f)}
with open(target_path) as f:
target = {r[key_field]: r for r in json.load(f)}
missing = set(source) - set(target)
extra = set(target) - set(source)
changed = []
for key in set(source) & set(target):
if source[key] != target[key]:
changed.append(key)
print(f"Source records: {len(source)}")
print(f"Target records: {len(target)}")
print(f"Missing in target: {len(missing)}")
print(f"Extra in target: {len(extra)}")
print(f"Changed: {len(changed)}")
if missing:
print(f"\nMissing IDs (first 10): {list(missing)[:10]}")
if extra:
print(f"\nExtra IDs (first 10): {list(extra)[:10]}")
if changed:
print(f"\nChanged IDs (first 5): {changed[:5]}")
for key in changed[:3]:
print(f"\n {key}:")
for field in set(source[key]) | set(target[key]):
s = source[key].get(field)
t = target[key].get(field)
if s != t:
print(f" {field}: {s!r} → {t!r}")
return len(missing) == 0 and len(extra) == 0
if __name__ == "__main__":
ok = validate_migration(sys.argv[1], sys.argv[2], sys.argv[3] if len(sys.argv) > 3 else "id")
sys.exit(0 if ok else 1)
```
## Tips
- Validate at system boundaries (API endpoints, file imports, message queues), not deep inside business logic. Trust internal data.
- Zod and Pydantic both generate JSON Schema from their definitions. Use this for documentation, OpenAPI specs, and cross-language contracts.
- `additionalProperties: false` in JSON Schema catches typos in field names. Use it for strict APIs.
- Pydantic v2 is significantly faster than v1. Use `model_config = ConfigDict(strict=True)` when you want no implicit type coercion.
- Zod's `.safeParse()` returns a result object; `.parse()` throws. Use `safeParse` in API handlers to return structured errors.
- For CSV validation, always check column count consistency first — most downstream errors trace back to misaligned columns.
- Data migration validation should compare record counts, check for missing/extra records, and sample-check field values. Counting alone isn't enough.
用 gh 命令列工具檢視 GitHub 上的 PR 檢查、工作流執行與 API 查詢的技能。
聚合 16 個搜尋引擎、無需 API Key 的檢索技能。
用命令列直接列出、配置、授權並呼叫 MCP 服務與工具。
根據文字描述生成 Mermaid 圖表程式碼。
用受管 OAuth 訪問 YouTube Data API,檢索影片並管理頻道內容。
透過受管的 OAuth 連線訪問 GitHub REST API。
覆蓋規劃、實現、驗證與測試的編碼工作流技能。
整理 Docker 常用命令與容器工作流的技能。
在命令列查詢、設計、遷移與最佳化 SQL 資料庫。
security-audit 提供程式碼與基礎設施安全審查的清單和命令示例。
git-workflows 提供歷史整理、除錯和倉庫管理的進階 Git 流程。
在命令列裡搭、測、寫文件與排錯 HTTP 介面。
解析、檢索與分析各類應用日誌,定位報錯。
資料月份:2026-09 · 下載/星標/安裝數聚合自公開技能註冊庫(ClawHub、SkillHub),按月更新。口徑說明見資料方法。