Data Pin
Data pins are the primary mechanism for passing information between nodes in Xentom workflows. They carry actual data values-strings, numbers, objects, arrays-and form the backbone of data flow throughout your automation processes.
Key Characteristics
- Data Transport: Carry actual information between nodes
- Type-Safe: Support TypeScript type inference and validation
- UI Integration: Can include controls for user input
- Schema Validation: Support Standard Schema specification for data validation
- Examples: Can provide sample data for users and AI assistance
Basic Usage
import * as i from '@xentom/integration-framework';
// Simple data pin
i.pins.data();
// Data pin with display information
i.pins.data({
displayName: 'User Email',
description: 'Email address of the user',
});
// Data pin with control for user input
i.pins.data({
displayName: 'Message',
description: 'Message to send to the user',
control: i.controls.text({
label: 'Message Content',
placeholder: 'Enter your message...',
rows: 3,
}),
});Configuration Options
Prop
Type
Controls
Data pins can include controls to allow user input:
Text Input
i.pins.data({
displayName: 'Email Subject',
control: i.controls.text({
label: 'Subject Line',
placeholder: 'Enter email subject...',
defaultValue: 'Welcome to our service!',
}),
});Dropdown Selection
i.pins.data({
displayName: 'Task Priority',
control: i.controls.select({
label: 'Priority Level',
options: [
{ value: 'low', label: 'Low Priority' },
{ value: 'medium', label: 'Medium Priority' },
{ value: 'high', label: 'High Priority' },
{ value: 'urgent', label: 'Urgent' },
],
defaultValue: 'medium',
}),
});Boolean Toggle
i.pins.data({
displayName: 'Enable Notifications',
control: i.controls.switch({
label: 'Send Email Notifications',
defaultValue: true,
}),
});JavaScript Expression
i.pins.data({
displayName: 'Data Transform',
control: i.controls.expression({
label: 'Transform Logic',
rows: 6,
placeholder: 'return data.map(item => ({ ...item, processed: true }))',
}),
});Schema Validation
Data pins support schema validation using the Standard Schema specification. For comprehensive examples with Valibot, Zod, ArkType, and detailed documentation, see Schema Validation.
import * as v from 'valibot'; // or any Standard Schema compatible validator
// String validation
i.pins.data({
displayName: 'Email Address',
schema: v.pipe(
v.string(),
v.email('Please enter a valid email address'),
v.trim(),
),
control: i.controls.text({
label: 'Email',
placeholder: '[email protected]',
}),
});Examples
Provide sample data to help users understand expected formats:
i.pins.data({
displayName: 'API Request Body',
description: 'JSON data to send in the API request',
control: i.controls.expression({
label: 'Request Data',
rows: 10,
}),
examples: [
{
title: 'Simple User Creation',
value: {
name: 'John Doe',
email: '[email protected]',
role: 'user',
},
},
{
title: 'Bulk User Import',
value: {
users: [
{ name: 'Alice Smith', email: '[email protected]' },
{ name: 'Bob Johnson', email: '[email protected]' },
],
sendWelcomeEmail: true,
},
},
{
title: 'Product Data',
value: {
product: {
name: 'Widget Pro',
price: 29.99,
categories: ['electronics', 'gadgets'],
specifications: {
weight: '100g',
dimensions: '10x5x2 cm',
},
},
},
},
],
});Optional Pins
Optional pins are hidden by default to reduce UI clutter:
// Node definition with optional pins
export const apiCall = i.nodes.callable({
inputs: {
// Always visible
url: i.pins.data({
control: i.controls.text({
label: 'API URL',
placeholder: 'https://api.example.com/endpoint',
}),
}),
// Optional - hidden initially
headers: i.pins.data({
displayName: 'Custom Headers',
description: 'Additional HTTP headers to include',
optional: true,
control: i.controls.expression({
label: 'Headers',
defaultValue: {
'Content-Type': 'application/json',
'User-Agent': 'Xentom-Workflow/1.0',
},
}),
}),
timeout: i.pins.data({
displayName: 'Timeout (ms)',
description: 'Request timeout in milliseconds',
optional: true,
control: i.controls.text({
label: 'Timeout',
defaultValue: '30000',
}),
}),
},
// Implementation...
});Method Chaining
Use the .with() method to extend pin configurations:
// Base pin
const baseEmailPin = i.pins.data({
schema: v.pipe(v.string(), v.email()),
control: i.controls.text({
placeholder: 'Enter email address...',
}),
});
// Extended versions
const userEmailPin = baseEmailPin.with({
displayName: 'User Email',
description: 'Primary email address for the user account',
});
const notificationEmailPin = baseEmailPin.with({
displayName: 'Notification Email',
description: 'Email address for system notifications',
optional: true,
});Common Patterns
API Configuration
// URL input
i.pins.data({
displayName: 'API Endpoint',
description: 'Full URL to the API endpoint',
control: i.controls.text({
label: 'URL',
placeholder: 'https://api.example.com/v1/users',
}),
examples: [
{
title: 'Users API',
value: 'https://api.example.com/v1/users',
},
{
title: 'Products API',
value: 'https://api.example.com/v1/products',
},
],
});
// Headers configuration
i.pins.data({
displayName: 'HTTP Headers',
description: 'Key-value pairs for HTTP headers',
optional: true,
control: i.controls.expression({
label: 'Headers',
defaultValue: {
Authorization: 'Bearer {{ token }}',
'Content-Type': 'application/json',
},
}),
});Data Filtering
i.pins.data({
displayName: 'Filter Criteria',
description: 'Conditions to filter the dataset',
control: i.controls.expression({
label: 'Filter Expression',
rows: 4,
placeholder: 'item => item.status === "active" && item.age > 18',
}),
examples: [
{
title: 'Active Users Only',
value: 'item => item.status === "active"',
},
{
title: 'Recent Orders',
value: 'item => new Date(item.createdAt) > new Date("2024-01-01")',
},
{
title: 'High Value Customers',
value: 'item => item.totalSpent > 1000',
},
],
});Template Processing
i.pins.data({
displayName: 'Email Template',
description: 'Email content with template variables',
control: i.controls.text({
label: 'Template',
rows: 8,
placeholder: 'Hello {{ user.name }},\n\nWelcome to our service!',
}),
examples: [
{
title: 'Welcome Email',
value:
'Hello {{ user.name }},\n\nThank you for joining our service. Your account is now active!',
},
{
title: 'Order Confirmation',
value:
'Order #{{ order.id }} confirmed!\n\nTotal: ${{ order.total }}\nDelivery: {{ order.deliveryDate }}',
},
],
});Best Practices
Use Descriptive Names
// Good - Clear purpose
i.pins.data({
displayName: 'User Email Address',
description: 'Primary email for user communications',
});
// Avoid - Generic names
i.pins.data({
displayName: 'Data',
});Provide Helpful Examples
// Good - Multiple realistic examples
i.pins.data({
examples: [
{
title: 'User Creation',
value: {
name: 'John',
email: '[email protected]',
},
},
{
title: 'Product Update',
value: {
id: '123',
price: 29.99,
stock: 50,
},
},
],
});
// Avoid - Single or unclear examples
i.pins.data({
examples: [
{
title: 'Example',
value: {
foo: 'bar',
},
},
],
});Use Appropriate Controls
// Good - Suitable control for data type
i.pins.data({
displayName: 'Status',
control: i.controls.select({
options: [
{ value: 'active', label: 'Active' },
{ value: 'inactive', label: 'Inactive' },
],
}),
});
// Avoid - Wrong control type
i.pins.data({
displayName: 'Status',
control: i.controls.expression(), // Overkill for simple status
});Leverage Optional Pins
// Good - Optional for advanced features
i.pins.data({
control: i.controls.expression({
label: 'Advanced Configuration',
}),
optional: true, // Hidden by default
});Data pins are fundamental to creating powerful, user-friendly integrations in Xentom. They provide the data flow backbone while offering rich configuration options for both simple and complex use cases.