Tables And Fields Api
Tables and Fields API
Learn how to programmatically access information about your application's data tables, fields, and structure using the REST API.
List All Data Tables
Get a list of all data tables in your application:
GET /api/v1/data-tables
Headers:
X-Tadabase-App-id: your_app_id
X-Tadabase-App-Key: your_app_key
X-Tadabase-App-Secret: your_app_secret
Response
{
"type": "success",
"data_tables": [
{
"id": "lGArg7rmR6",
"name": "Customers"
},
{
"id": "mH8s2pQtS9",
"name": "Orders"
},
{
"id": "nK9t3qRuT0",
"name": "Products"
}
],
"total_items": 3
}
Use Case: Dynamic Table Selection
async function getTables() {
const response = await fetch(
'https://api.tadabase.io/api/v1/data-tables',
{ headers }
);
const data = await response.json();
return data.data_tables;
}
// Build dropdown of tables
const tables = await getTables();
tables.forEach(table => {
console.log(`${table.name} (ID: ${table.id})`);
});
List Table Fields (Basic)
Get basic information about fields in a specific table:
GET /api/v1/data-tables/{tableId}/fields
Headers:
X-Tadabase-App-id: your_app_id
X-Tadabase-App-Key: your_app_key
X-Tadabase-App-Secret: your_app_secret
Response
{
"type": "success",
"fields": [
{
"slug": "first_name",
"name": "First Name",
"type": "Text"
},
{
"slug": "email",
"name": "Email",
"type": "Email"
},
{
"slug": "status",
"name": "Status",
"type": "Select"
},
{
"slug": "created_at",
"name": "Date Created",
"type": "Auto Date"
}
],
"total_items": 4
}
Field Properties
| Property | Description |
|---|---|
slug |
Field identifier used in API requests |
name |
Display name of the field |
type |
Field type (Text, Email, Select, etc.) |
Get Full Field Information
Get detailed metadata including options, validation rules, and relationships:
GET /api/v1/data-tables/{tableId}/full-fields-info
Headers:
X-Tadabase-App-id: your_app_id
X-Tadabase-App-Key: your_app_key
X-Tadabase-App-Secret: your_app_secret
Response
{
"fields": [
{
"slug": "status",
"fieldId": "field_40",
"name": "Status",
"type": "Select",
"description": "Customer status",
"default_value": "pending",
"is_unique": "No",
"is_required": "Yes",
"options": [
{
"label": "Pending",
"value": "pending"
},
{
"label": "Active",
"value": "active"
},
{
"label": "Inactive",
"value": "inactive"
}
]
},
{
"slug": "assigned_to",
"fieldId": "field_41",
"name": "Assigned To",
"type": "Connection",
"join": {
"join_type": "1-to-N",
"data_table_id": "users_table_id",
"field_slug": "full_name",
"field_id": "field_35"
}
},
{
"slug": "email",
"fieldId": "field_42",
"name": "Email",
"type": "Email",
"is_unique": "Yes",
"is_required": "Yes"
}
]
}
Detailed Field Properties
| Property | Description |
|---|---|
fieldId |
Internal field ID (e.g., "field_40") |
slug |
Field slug for API requests |
name |
Display name |
type |
Field type |
description |
Field description/help text |
default_value |
Default value (for forms only) |
is_unique |
Whether field must have unique values |
is_required |
Whether field is required |
options |
Available options (for Select, Radio, etc.) |
join |
Join configuration (for Connection fields) |
Working with Field Information
Build Dynamic Forms
async function buildFormFromFields(tableId) {
const response = await fetch(
`https://api.tadabase.io/api/v1/data-tables/${tableId}/full-fields-info`,
{ headers }
);
const data = await response.json();
const formFields = data.fields.map(field => {
const formField = {
slug: field.slug,
name: field.name,
type: field.type,
required: field.is_required === 'Yes'
};
// Add options for select fields
if (field.options) {
formField.options = field.options;
}
// Add validation for unique fields
if (field.is_unique === 'Yes') {
formField.unique = true;
}
return formField;
});
return formFields;
}
// Usage
const formFields = await buildFormFromFields('lGArg7rmR6');
renderForm(formFields);
Validate Data Before Submission
async function validateRecord(tableId, record) {
const response = await fetch(
`https://api.tadabase.io/api/v1/data-tables/${tableId}/full-fields-info`,
{ headers }
);
const data = await response.json();
const errors = [];
data.fields.forEach(field => {
// Check required fields
if (field.is_required === 'Yes' && !record[field.slug]) {
errors.push(`${field.name} is required`);
}
// Validate select options
if (field.options && record[field.slug]) {
const validOptions = field.options.map(opt => opt.value);
if (!validOptions.includes(record[field.slug])) {
errors.push(`${field.name} has invalid option`);
}
}
});
return {
valid: errors.length === 0,
errors
};
}
// Usage
const validation = await validateRecord('lGArg7rmR6', {
first_name: 'John',
// email missing (required field)
status: 'invalid_option'
});
if (!validation.valid) {
console.error('Validation errors:', validation.errors);
}
Get Connection Field Options
async function getConnectionOptions(tableId, fieldSlug) {
// Get field info
const response = await fetch(
`https://api.tadabase.io/api/v1/data-tables/${tableId}/full-fields-info`,
{ headers }
);
const data = await response.json();
const field = data.fields.find(f => f.slug === fieldSlug);
if (!field || field.type !== 'Connection') {
throw new Error('Field is not a connection field');
}
// Get records from connected table
const connectedTableId = field.join.data_table_id;
const displayField = field.join.field_slug;
const recordsResponse = await fetch(
`https://api.tadabase.io/api/v1/data-tables/${connectedTableId}/records?fields=id,${displayField}`,
{ headers }
);
const recordsData = await recordsResponse.json();
// Format as options
return recordsData.items.map(record => ({
value: record.id,
label: record[displayField]
}));
}
// Usage
const userOptions = await getConnectionOptions('lGArg7rmR6', 'assigned_to');
// Returns: [{ value: 'user_id_1', label: 'John Doe' }, ...]
List User Roles
Get all user roles configured in your application:
GET /api/v1/roles
Headers:
X-Tadabase-App-id: your_app_id
X-Tadabase-App-Key: your_app_key
X-Tadabase-App-Secret: your_app_secret
Response
{
"type": "success",
"items": [
{
"id": "role_id_1",
"name": "Admin",
"description": "Administrator role with full access",
"enable_stripe": "Yes"
},
{
"id": "role_id_2",
"name": "User",
"description": "Standard user role",
"enable_stripe": "No"
},
{
"id": "role_id_3",
"name": "Manager",
"description": "Manager role with elevated permissions",
"enable_stripe": "Yes"
}
],
"total_items": 3
}
Use Case: Role-Based Assignment
async function getRoles() {
const response = await fetch(
'https://api.tadabase.io/api/v1/roles',
{ headers }
);
const data = await response.json();
return data.items;
}
// Create user with specific role
async function createUserWithRole(userData, roleName) {
const roles = await getRoles();
const role = roles.find(r => r.name === roleName);
if (!role) {
throw new Error(`Role ${roleName} not found`);
}
return await createRecord({
...userData,
role: role.id
});
}
// Usage
await createUserWithRole(
{ name: 'John Doe', email: 'john@example.com' },
'Manager'
);
Practical Applications
1. Schema Introspection
async function getTableSchema(tableId) {
const response = await fetch(
`https://api.tadabase.io/api/v1/data-tables/${tableId}/full-fields-info`,
{ headers }
);
const data = await response.json();
return {
tableId,
fields: data.fields.map(field => ({
name: field.name,
slug: field.slug,
type: field.type,
required: field.is_required === 'Yes',
unique: field.is_unique === 'Yes',
options: field.options || null,
connection: field.join || null
}))
};
}
// Usage
const schema = await getTableSchema('lGArg7rmR6');
console.log(JSON.stringify(schema, null, 2));
2. Generate TypeScript Interfaces
async function generateTypeScriptInterface(tableId, interfaceName) {
const schema = await getTableSchema(tableId);
const typeMap = {
'Text': 'string',
'Email': 'string',
'Phone': 'string',
'Number': 'number',
'Currency': 'number',
'Decision Box': 'boolean',
'Date': 'string',
'DateTime': 'string',
'Select': 'string',
'Connection': 'string | string[]'
};
let interfaceCode = `interface ${interfaceName} {\n`;
schema.fields.forEach(field => {
const type = typeMap[field.type] || 'any';
const optional = field.required ? '' : '?';
interfaceCode += ` ${field.slug}${optional}: ${type};\n`;
});
interfaceCode += '}';
return interfaceCode;
}
// Usage
const tsInterface = await generateTypeScriptInterface('lGArg7rmR6', 'Customer');
console.log(tsInterface);
/* Output:
interface Customer {
first_name: string;
last_name: string;
email: string;
phone?: string;
status: string;
age?: number;
is_active?: boolean;
}
*/
3. Data Migration Tool
async function migrateData(sourceTableId, destTableId, fieldMapping) {
// Get source table schema
const sourceSchema = await getTableSchema(sourceTableId);
// Get all records from source
const sourceRecords = await getAllRecords(sourceTableId);
// Map and create records in destination
for (const sourceRecord of sourceRecords) {
const destRecord = {};
// Map fields according to mapping
Object.keys(fieldMapping).forEach(sourceField => {
const destField = fieldMapping[sourceField];
destRecord[destField] = sourceRecord[sourceField];
});
await createRecord(destTableId, destRecord);
}
}
// Usage
await migrateData(
'old_table_id',
'new_table_id',
{
'old_name': 'new_name',
'old_email': 'new_email',
'old_status': 'new_status'
}
);
4. Validation Schema Builder
async function buildValidationSchema(tableId) {
const response = await fetch(
`https://api.tadabase.io/api/v1/data-tables/${tableId}/full-fields-info`,
{ headers }
);
const data = await response.json();
const schema = {};
data.fields.forEach(field => {
const validators = [];
if (field.is_required === 'Yes') {
validators.push({ type: 'required', message: `${field.name} is required` });
}
if (field.is_unique === 'Yes') {
validators.push({ type: 'unique', message: `${field.name} must be unique` });
}
if (field.type === 'Email') {
validators.push({ type: 'email', message: 'Invalid email format' });
}
if (field.options) {
validators.push({
type: 'enum',
values: field.options.map(opt => opt.value),
message: `Invalid ${field.name}`
});
}
schema[field.slug] = validators;
});
return schema;
}
// Usage
const validationSchema = await buildValidationSchema('lGArg7rmR6');
console.log(validationSchema);
Caching Field Information
Field schemas don't change often, so cache them:
class FieldCache {
constructor(ttl = 3600000) { // 1 hour default
this.cache = new Map();
this.ttl = ttl;
}
async getFields(tableId) {
const cached = this.cache.get(tableId);
if (cached && Date.now() - cached.timestamp
Best Practices
- Cache field information: Field schemas rarely change, cache them to reduce API calls
- Use full-fields-info for detailed needs: Basic
/fieldsis faster, use/full-fields-infoonly when you need options/joins - Build dynamic interfaces: Use field info to generate forms, validation, and TypeScript types
- Validate before submission: Check required/unique constraints client-side using field info
- Document field slugs: Keep a reference of field slugs for your integration
- Handle connection fields carefully: Fetch connected records to show proper options
Next Steps
Learn how to perform bulk operations efficiently:
→ Batch Operations and Bulk Updates
Discover how to update multiple records at once and check batch operation counts.
We'd love to hear your feedback.