Metadata API
The Radish datalayer includes a runtime metadata API that provides schema introspection for dynamic UIs and tooling.
Overview
Metadata is generated at build time into .radish/lib/datalayer/contracts/metadata/ and exported from @generated/datalayer/metadata. It preserves all business information from your blueprints — labels, descriptions, field types, validation rules, and more — making it available at runtime without parsing blueprint files.
Import Path
import {
getEntityNames,
getEntityMetadata,
getAllEntitiesMetadata,
AllEntities,
ProductEntityMetadata,
ProductFieldsMetadata
} from '@generated/datalayer/metadata';
Accessor Functions
getEntityNames()
Returns a list of all entity names in the generated datalayer.
function getEntityNames(): string[]
Example:
const names = getEntityNames();
// ['Product', 'User', 'Role', 'Category', ...]
getEntityMetadata(entityName)
Returns the combined entity and field metadata for a specific entity.
function getEntityMetadata(entityName: string): {
entity: EntityMetadata;
fields: FieldsMetadata;
} | undefined
Example:
const meta = getEntityMetadata('Product');
console.log(meta.entity.label); // "Product"
console.log(meta.entity.plural); // "products"
console.log(meta.entity.ownership); // "user"
console.log(meta.fields.title.type); // "string"
getAllEntitiesMetadata()
Returns all entities with their metadata flattened into a list, useful for admin consoles and discovery tools.
function getAllEntitiesMetadata(): Array<{
name: string;
label: string;
description: string;
plural: string;
ownership: string;
filters?: string[];
searchFields?: string[];
indexes?: any[];
entityId: string;
fields: FieldsMetadata;
}>
Example:
const all = getAllEntitiesMetadata();
all.forEach(entity => {
console.log(`${entity.name} (${entity.plural}): ${entity.description}`);
console.log(` Ownership: ${entity.ownership}`);
console.log(` Fields: ${Object.keys(entity.fields).join(', ')}`);
});
Entity Metadata Shape
Each entity produces two named exports: {EntityName}EntityMetadata and {EntityName}FieldsMetadata.
{EntityName}EntityMetadata
export const ProductEntityMetadata = {
label: "Product",
description: "Product entity",
plural: "products",
ownership: "user",
filters: ["status", "categoryId"], // present if entity has filters
searchFields: ["title", "description"], // present if any field has search: true
indexes: [{ fields: ["sku"], unique: true }], // present if entity has indexes
entityId: "product"
} as const;
| Property | Type | Description |
|---|---|---|
label | string | Display name (from blueprint or PascalCase entity name) |
description | string | Entity description (from blueprint or default) |
plural | string | Plural form for URL paths and collections |
ownership | string | Ownership mode: "user", "system", "none" |
filters | string[] | Fields available as query filters (optional) |
searchFields | string[] | Fields searched by q parameter (optional) |
indexes | any[] | Compound index definitions (optional) |
entityId | string | Stable entity identifier |
{EntityName}FieldsMetadata
A map of field name to field metadata. Each field includes its type, display properties, validation rules, and relationship information.
export const ProductFieldsMetadata = {
title: {
type: "string",
label: "Title",
description: "Product title",
required: true,
search: true,
validation: {
required: true,
minLength: 1,
maxLength: 200
}
},
price: {
type: "float",
label: "Price",
required: true,
validation: {
required: true,
min: 0
}
},
categoryId: {
type: "objectId",
label: "Category",
ref: "Category",
required: true,
validation: {
required: true
}
},
status: {
type: "enum",
label: "Status",
values: ["DRAFT", "ACTIVE", "ARCHIVED"],
default: "DRAFT",
validation: {}
},
tags: {
type: "string[]",
label: "Tags",
optional: true,
validation: {
optional: true
}
}
} as const;
Field Metadata Properties
| Property | Type | Description |
|---|---|---|
type | string | Field type: string, int, float, boolean, enum, objectId, isoDate, url, email, secretKey, encryptedKey, object, string[], objectId[], etc. |
label | string | Display label for forms and tables |
description | string | Help text or tooltip content |
required | boolean | Whether the field is required |
optional | boolean | Whether the field is optional |
unique | boolean | Whether the field must be unique |
search | boolean | Whether the field is included in text search |
default | any | Default value |
placeholder | string | Placeholder text for form inputs |
helpText | string | Additional help text |
ref | string | Referenced entity name (for objectId fields) |
values | string[] | Allowed values (for enum fields) |
internal | boolean | Whether the field is internal-only |
expose | object | Field exposure rules |
access | object | Field-level access control by role |
fields | object | Sub-field definitions (for object type fields) |
validation | object | Validation constraints (see below) |
Secret key fields (secretKey, encryptedKey) also include:
| Property | Type | Description |
|---|---|---|
lastChars | number | Number of trailing characters to show |
hashField | string | Name of the hash storage field (secretKey only) |
encryptedField | string | Name of the encrypted storage field (encryptedKey only) |
displayField | string | Name of the display field (shows last N chars) |
Validation Object
The validation sub-object mirrors the field's validation constraints:
validation: {
required?: boolean;
optional?: boolean;
unique?: boolean;
minLength?: number;
maxLength?: number;
min?: number;
max?: number;
}
AllEntities Constant
The AllEntities object provides direct access to all metadata keyed by entity name:
const AllEntities = {
Product: { entity: ProductEntityMetadata, fields: ProductFieldsMetadata },
Category: { entity: CategoryEntityMetadata, fields: CategoryFieldsMetadata },
// ...
} as const;
This is what the accessor functions operate on internally.
Use Cases
- Dynamic form generation - Build forms from field metadata (type, required, values, validation)
- Admin panels - Generate CRUD interfaces automatically using entity and field metadata
- API documentation - Expose schema information to consumers
- Runtime validation - Use field constraints for client-side validation
- Search configuration - Know which fields support text search