实战示例
通过实际案例学习 farrow-schema 的应用场景。
REST API
typescript
import { ObjectType, String, Number, List, Optional } from 'farrow-schema'
import { Validator } from 'farrow-schema/validator'
// 定义模型
class User extends ObjectType {
id = String
name = String
email = String
age = Number
tags = List(String)
}
// 创建输入(排除自动生成的字段)
const CreateUserInput = omitObject(User, ['id'])
// API 端点
app.post('/users', async (req, res) => {
// 验证输入
const result = Validator.validate(CreateUserInput, req.body)
if (result.kind === 'Err') {
return res.status(400).json({
error: 'Validation failed',
message: result.value.message,
path: result.value.path
})
}
// result.value 类型安全
const newUser = await db.users.create({
id: generateId(),
...result.value
})
res.json(newUser)
})
// 更新输入(所有字段可选)
const UpdateUserInput = partialObject(
omitObject(User, ['id'])
)
app.patch('/users/:id', async (req, res) => {
const result = Validator.validate(UpdateUserInput, req.body)
if (result.kind === 'Err') {
return res.status(400).json({ error: result.value.message })
}
const updated = await db.users.update(req.params.id, result.value)
res.json(updated)
})表单验证
typescript
class SignUpForm extends ObjectType {
username = RegExp(/^[a-zA-Z0-9_]{3,16}$/)
email = EmailType
password = StringLength(8, 32)
confirmPassword = String
}
// 自定义验证器:检查密码匹配
class SignUpValidator extends ValidatorType<TypeOf<typeof SignUpForm>> {
validate(input: unknown) {
const result = Validator.validate(SignUpForm, input)
if (result.kind === 'Err') return result
if (result.value.password !== result.value.confirmPassword) {
return this.Err('密码不匹配')
}
return this.Ok(result.value)
}
}
// 在前端使用
async function handleSubmit(formData: unknown) {
const result = Validator.validate(SignUpValidator, formData)
if (result.kind === 'Err') {
showError(result.value.message)
return
}
await api.signUp(result.value)
}配置验证
typescript
import { Union, Literal, Struct } from 'farrow-schema'
const DatabaseConfig = Struct({
type: Literal('postgres'),
host: String,
port: Int,
database: String,
user: String,
password: String
})
const RedisConfig = Struct({
type: Literal('redis'),
host: String,
port: Int,
password: Optional(String)
})
const AppConfig = Struct({
port: Int,
database: Union(DatabaseConfig, RedisConfig),
logging: Struct({
level: Union(
Literal('debug'),
Literal('info'),
Literal('warn'),
Literal('error')
),
format: Union(
Literal('json'),
Literal('text')
)
})
})
// 加载配置
const config = loadConfigFile('app.json')
const result = Validator.validate(AppConfig, config)
if (result.kind === 'Err') {
throw new Error(`Invalid config: ${result.value.message} at ${result.value.path}`)
}
// 类型安全的配置
startServer(result.value)树形数据结构
typescript
class Category extends ObjectType {
id = String
name = String
description = Optional(String)
children = List(Category) // ✅ 递归引用
parent = Optional(Category)
}
// 验证分类树
const categoryTree = {
id: '1',
name: 'Electronics',
description: 'Electronic products',
children: [
{
id: '1-1',
name: 'Computers',
children: [
{ id: '1-1-1', name: 'Laptops', children: [] }
]
}
]
}
const result = Validator.validate(Category, categoryTree)
if (result.kind === 'Ok') {
// 递归遍历分类树
function traverse(category: TypeOf<typeof Category>) {
console.log(category.name)
category.children.forEach(traverse)
}
traverse(result.value)
}复杂业务场景:电商订单
typescript
import { ObjectType, String, Number, List, Union, Literal, Optional } from 'farrow-schema'
// 商品
class Product extends ObjectType {
id = String
name = String
price = Number
stock = Int
}
// 订单项
class OrderItem extends ObjectType {
product = Product
quantity = Int
subtotal = Number
}
// 地址
class Address extends ObjectType {
street = String
city = String
state = String
zipCode = String
country = String
}
// 支付方式
const PaymentMethod = Union(
Struct({
type: Literal('credit_card'),
cardNumber: String,
cardHolder: String,
expiryDate: String
}),
Struct({
type: Literal('paypal'),
email: String
}),
Struct({
type: Literal('bank_transfer'),
bankName: String,
accountNumber: String
})
)
// 订单状态
const OrderStatus = Union(
Literal('pending'),
Literal('paid'),
Literal('shipped'),
Literal('delivered'),
Literal('cancelled')
)
// 完整订单
class Order extends ObjectType {
id = String
userId = String
items = List(OrderItem)
shippingAddress = Address
billingAddress = Optional(Address)
paymentMethod = PaymentMethod
status = OrderStatus
total = Number
createdAt = String
updatedAt = String
}
// 创建订单输入
const CreateOrderInput = Struct({
items: List(Struct({
productId: String,
quantity: Int
})),
shippingAddress: Address,
billingAddress: Optional(Address),
paymentMethod: PaymentMethod
})
// API 处理
app.post('/orders', async (req, res) => {
const result = Validator.validate(CreateOrderInput, req.body)
if (result.kind === 'Err') {
return res.status(400).json({
error: 'Invalid order data',
details: result.value.message,
path: result.value.path
})
}
const order = await createOrder(result.value)
res.status(201).json(order)
})多层嵌套验证
typescript
class Company extends ObjectType {
id = String
name = String
departments = List(Department)
}
class Department extends ObjectType {
id = String
name = String
manager = Employee
employees = List(Employee)
}
class Employee extends ObjectType {
id = String
name = String
email = String
position = String
salary = Number
projects = List(Project)
}
class Project extends ObjectType {
id = String
name = String
deadline = String
status = Union(
Literal('not_started'),
Literal('in_progress'),
Literal('completed')
)
}
// 验证整个公司结构
const companyData = loadCompanyData()
const result = Validator.validate(Company, companyData)
if (result.kind === 'Ok') {
console.log(`公司 ${result.value.name} 验证通过`)
console.log(`共有 ${result.value.departments.length} 个部门`)
} else {
console.error(`数据验证失败: ${result.value.message}`)
console.error(`错误位置: ${result.value.path?.join('.')}`)
}