Skip to content

实战示例

通过实际案例学习 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('.')}`)
}

这是一个第三方 Farrow 文档站 | 用 ❤️ 和 TypeScript 构建