This guide covers advanced aspects of working with Orionjs schemas, including composition, inheritance, and complex validation.
Schema Composition
You can compose schemas together to create more complex structures:
import {schemaWithName, InferSchemaType} from '@orion-js/schema'
// Base schemas
export const AddressSchema = schemaWithName('AddressSchema', {
street: {type: String},
city: {type: String},
zipCode: {type: String}
})
export const NameSchema = schemaWithName('NameSchema', {
firstName: {type: String},
lastName: {type: String}
})
// Composed schema
export const UserSchema = schemaWithName('UserSchema', {
_id: {type: String},
// Embed the name schema
name: {type: NameSchema},
// Embed the address schema
address: {type: AddressSchema, optional: true},
email: {type: String}
})
export type UserType = InferSchemaType<typeof UserSchema>
Arrays of Complex Types
Working with arrays of objects:
import {schemaWithName, InferSchemaType} from '@orion-js/schema'
export const TagSchema = schemaWithName('TagSchema', {
name: {type: String},
color: {type: String, optional: true}
})
export const PostSchema = schemaWithName('PostSchema', {
_id: {type: String},
title: {type: String},
// Array of primitive values
categories: {type: [String]},
// Array of complex objects
tags: {type: [TagSchema], minLength: 1, maxLength: 10}
})
export type PostType = InferSchemaType<typeof PostSchema>
Conditional Validation
You can implement conditional validation based on other field values:
import {schemaWithName, InferSchemaType} from '@orion-js/schema'
export const PaymentSchema = schemaWithName('PaymentSchema', {
method: {
type: String,
allowedValues: ['credit_card', 'bank_transfer', 'paypal']
},
// Credit card details, required only when method is 'credit_card'
cardNumber: {
type: String,
optional: true,
validate: (value, {doc}) => {
if (doc.method === 'credit_card' && !value) {
return 'required-for-credit-card'
}
if (value && !/^\d{16}$/.test(value)) {
return 'invalid-card-number'
}
}
},
// PayPal email, required only when method is 'paypal'
paypalEmail: {
type: String,
optional: true,
validate: (value, {doc}) => {
if (doc.method === 'paypal' && !value) {
return 'required-for-paypal'
}
}
}
})
export type PaymentType = InferSchemaType<typeof PaymentSchema>
Creating a custom type with validation and transformation:
import {schemaWithName, InferSchemaType, createType} from '@orion-js/schema'
// Custom type for phone numbers
const PhoneNumberType = createType({
name: 'phoneNumber',
validate(value) {
if (!/^\+?[0-9\s-()]+$/.test(value)) {
return 'invalid-phone-format'
}
},
clean(value) {
// Remove non-digit characters
return value.replace(/[^0-9+]/g, '')
}
})
export const ContactSchema = schemaWithName('ContactSchema', {
name: {type: String},
phone: {type: PhoneNumberType}
})
export type ContactType = InferSchemaType<typeof ContactSchema>