@gati-framework/runtime
Version:
Gati runtime execution engine for running handler-based applications
324 lines • 9.74 kB
JavaScript
/**
* @module runtime/gtype/examples
* @description Usage examples for the GType validation system
*/
import { primitive, object, array, union, literal, enumType, GTypes, validate, } from './index.js';
/**
* Example 1: Simple User Schema
*
* Validates a basic user object with required fields
*/
export const userSchema = object({
id: primitive('string'),
name: primitive('string'),
email: GTypes.email(),
age: primitive('number'),
}, { required: ['id', 'name', 'email'] });
// Usage:
const validUser = {
id: '123',
name: 'John Doe',
email: 'john@example.com',
age: 30,
};
const invalidUser = {
id: '123',
name: 'John Doe',
email: 'invalid-email', // Invalid email format
};
// Validate
const result1 = validate(validUser, userSchema);
console.log('Valid user:', result1.valid); // true
const result2 = validate(invalidUser, userSchema);
console.log('Invalid user:', result2.valid); // false
console.log('Errors:', result2.errors);
/**
* Example 2: Product Schema with Constraints
*
* Demonstrates custom validators and constraints
*/
export const productSchema = object({
id: GTypes.uuid(),
name: primitive('string', {
validators: [
{ type: 'minLength', value: 3, message: 'Name must be at least 3 characters' },
{ type: 'maxLength', value: 100, message: 'Name must be at most 100 characters' },
],
}),
price: primitive('number', {
validators: [
{ type: 'min', value: 0, message: 'Price must be positive' },
],
}),
category: enumType(['electronics', 'clothing', 'food', 'books']),
tags: array(primitive('string')),
inStock: primitive('boolean'),
}, { required: ['id', 'name', 'price', 'category'] });
/**
* Example 3: API Response Schema with Union Types
*
* Demonstrates union types for success/error responses
*/
export const apiResponseSchema = union([
// Success response
object({
success: literal(true),
data: object({
id: primitive('string'),
message: primitive('string'),
}),
}),
// Error response
object({
success: literal(false),
error: object({
code: primitive('string'),
message: primitive('string'),
details: GTypes.optional(array(primitive('string'))),
}),
}),
]);
/**
* Example 4: Nested Object Schema
*
* Demonstrates nested objects and optional fields
*/
export const orderSchema = object({
orderId: GTypes.uuid(),
customer: object({
id: primitive('string'),
name: primitive('string'),
email: GTypes.email(),
address: object({
street: primitive('string'),
city: primitive('string'),
zipCode: primitive('string', {
validators: [
{ type: 'pattern', value: '^\\d{5}(-\\d{4})?$', message: 'Invalid ZIP code' },
],
}),
country: primitive('string'),
}),
}),
items: array(object({
productId: primitive('string'),
quantity: primitive('number', {
validators: [
{ type: 'min', value: 1, message: 'Quantity must be at least 1' },
],
}),
price: primitive('number'),
})),
total: primitive('number'),
status: enumType(['pending', 'processing', 'shipped', 'delivered', 'cancelled']),
createdAt: primitive('string'), // ISO date string
updatedAt: GTypes.optional(primitive('string')),
});
/**
* Example 5: Handler Request/Response Schemas
*
* Demonstrates how to use GType for handler validation
*/
// Create User Request
export const createUserRequestSchema = object({
name: primitive('string', {
validators: [
{ type: 'minLength', value: 2 },
{ type: 'maxLength', value: 50 },
],
}),
email: GTypes.email(),
password: primitive('string', {
validators: [
{ type: 'minLength', value: 8, message: 'Password must be at least 8 characters' },
{
type: 'pattern',
value: '^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)',
message: 'Password must contain uppercase, lowercase, and number',
},
],
}),
age: GTypes.optional(primitive('number', {
validators: [
{ type: 'min', value: 18 },
{ type: 'max', value: 120 },
],
})),
}, { required: ['name', 'email', 'password'] });
// Create User Response
export const createUserResponseSchema = object({
id: GTypes.uuid(),
name: primitive('string'),
email: GTypes.email(),
createdAt: primitive('string'),
});
/**
* Example 6: Custom Validator
*
* Demonstrates custom validation logic
*/
export const passwordSchema = primitive('string', {
validators: [
{ type: 'minLength', value: 8 },
{
type: 'custom',
fn: (value) => {
if (typeof value !== 'string')
return false;
// Check for at least one uppercase, one lowercase, one digit, one special char
const hasUpper = /[A-Z]/.test(value);
const hasLower = /[a-z]/.test(value);
const hasDigit = /\d/.test(value);
const hasSpecial = /[!@#$%^&*(),.?":{}|<>]/.test(value);
return hasUpper && hasLower && hasDigit && hasSpecial;
},
message: 'Password must contain uppercase, lowercase, digit, and special character',
},
],
});
/**
* Example 7: Array with Constraints
*
* Demonstrates array validation with min/max items
*/
export const tagListSchema = array(primitive('string', {
validators: [
{ type: 'minLength', value: 2 },
{ type: 'maxLength', value: 20 },
{ type: 'pattern', value: '^[a-z0-9-]+$', message: 'Tags must be lowercase alphanumeric with hyphens' },
],
}), {
minItems: 1,
maxItems: 10,
});
/**
* Example 8: Discriminated Union (Type-safe API)
*
* Demonstrates discriminated unions for type-safe APIs
*/
export const eventSchema = union([
object({
type: literal('user.created'),
data: object({
userId: primitive('string'),
email: GTypes.email(),
}),
}),
object({
type: literal('user.updated'),
data: object({
userId: primitive('string'),
changes: array(primitive('string')),
}),
}),
object({
type: literal('user.deleted'),
data: object({
userId: primitive('string'),
deletedAt: primitive('string'),
}),
}),
]);
/**
* Example 9: Pagination Schema
*
* Common pagination pattern
*/
export const paginationSchema = object({
page: primitive('number', {
validators: [{ type: 'min', value: 1 }],
}),
pageSize: primitive('number', {
validators: [
{ type: 'min', value: 1 },
{ type: 'max', value: 100 },
],
}),
total: primitive('number'),
totalPages: primitive('number'),
});
export const paginatedResponseSchema = (itemSchema) => object({
items: array(itemSchema),
pagination: paginationSchema,
});
/**
* Example 10: Optional and Nullable Fields
*
* Demonstrates the difference between optional and nullable
*/
export const profileSchema = object({
// Required field
username: primitive('string'),
// Optional field (can be undefined, but not null)
bio: GTypes.optional(primitive('string')),
// Nullable field (can be null, but not undefined)
avatar: GTypes.nullable(primitive('string')),
// Optional and nullable (can be undefined or null)
website: GTypes.optional(GTypes.nullable(GTypes.url())),
});
/**
* Helper function to validate and throw on error
*/
export function validateOrThrow(value, schema, name = 'value') {
const result = validate(value, schema);
if (!result.valid) {
const errors = result.errors
.map((e) => ` - ${e.path.join('.')}: ${e.message}`)
.join('\n');
throw new Error(`Validation failed for ${name}:\n${errors}`);
}
}
/**
* Helper function to validate with type guard
*/
export function isValid(value, schema) {
return validate(value, schema).valid;
}
/**
* Example usage in a handler
*/
export function exampleHandlerUsage() {
// In a handler, you would validate request body:
const requestBody = {
name: 'John Doe',
email: 'john@example.com',
password: 'SecurePass123!',
};
try {
validateOrThrow(requestBody, createUserRequestSchema, 'request body');
// If we get here, requestBody is valid
console.log('Request is valid:', requestBody);
// Process the request...
const response = {
id: '550e8400-e29b-41d4-a716-446655440000',
name: requestBody.name,
email: requestBody.email,
createdAt: new Date().toISOString(),
};
// Validate response before sending
validateOrThrow(response, createUserResponseSchema, 'response');
return response;
}
catch (error) {
console.error('Validation error:', error);
throw error;
}
}
/**
* Example: Type-safe validation with type guards
*/
export function exampleTypeGuard() {
const data = {
id: '123',
name: 'John',
email: 'john@example.com',
};
if (isValid(data, userSchema)) {
// TypeScript knows data is a valid user here
console.log('User name:', data.name);
console.log('User email:', data.email);
}
else {
}
}
//# sourceMappingURL=examples.js.map