@directus/api
Version:
Directus is a real-time API and App dashboard for managing SQL database content
522 lines (457 loc) • 12.5 kB
Markdown
Perform CRUD operations on Directus Fields.
<actions>
- `create`: Add one or multiple fields to a collection
- `read`: View field configurations
- `update`: Update one or multiple fields
- `delete`: Remove fields
</actions>
<field_types>
- **Text**: `string` (max 255 chars), `text` (unlimited), `uuid` (relations/IDs), `hash` (passwords)
- **Numeric**: `integer`, `bigInteger`, `float`, `decimal` (for financial precision)
- **Date/Time**: `timestamp`, `datetime`, `date`, `time`
- **Boolean**: `boolean` for toggles/flags
- **Structured**: `json` (complex data), `csv` (tags/lists)
- **Alias**: Virtual fields for relations (`o2m`, `m2m`, `m2a`, `files`, `translations`)
- **Geospatial**: `point`, `lineString`, `polygon` for maps </field_types>
<adding_fields>
**Important**: When using the `fields` tool, `data` must always be an array of field objects, even for single fields.
Make sure you include `meta` and `schema` objects for each field.
Add fields to existing collections:
```json
{
"action": "create",
"collection": "articles",
"data": [
{
"field": "excerpt",
"type": "text",
"meta": {
"interface": "input-rich-text-md",
"special": null,
"note": "Article excerpt for previews and SEO. Supports markdown formatting.",
"translations": [
{
"language": "en-US",
"translation": "Excerpt"
}
],
"options": {
"placeholder": null,
"customSyntax": null
},
"display": "formatted-value",
"display_options": { "format": true }
},
"schema": {
"name": "test",
"table": "random_collection",
"data_type": "text"
}
}
]
}
```
**Multiple Fields Example:**
```json
{
"action": "create",
"collection": "articles",
"data": [
{
"field": "title",
"type": "string"
// Rest of field data
},
{
"field": "content",
"type": "text"
// Rest of field data
}
]
}
```
**Note**: You can omit `null` or `false` values from the schema object. </adding_fields>
<relationship_fields>
**CRITICAL**: Field type and meta.special determine relationship behavior.
- **M2O**: `type: "uuid"`, `special: ["m2o"]`, interface: `select-dropdown-m2o` → then create relation
- **O2M**: `type: "alias"`, `special: ["o2m"]`, interface: `list-o2m` → auto-created with M2O
- **M2M**: `type: "alias"`, `special: ["m2m"]`, interface: `list-m2m` → needs junction collection
- **M2A**: `type: "alias"`, `special: ["m2a"]`, interface: `list-m2a` → polymorphic, needs junction
- **File**: `type: "uuid"`, `special: ["file"]`, interface: `file` or `file-image` → single file relation
- **Files**: `type: "alias"`, `special: ["files"]`, interface: `files` → multiple files via M2M
- **Translations**: `type: "alias"`, `special: ["translations"]`, interface: `translations` → special M2M
### M2O Field Example
```json
{
"collection": "posts",
"field": "author",
"type": "uuid",
"schema": {
"name": "author",
"table": "posts",
"data_type": "uuid",
"is_nullable": true,
"foreign_key_schema": "public",
"foreign_key_table": "team",
"foreign_key_column": "id"
},
"meta": {
"collection": "posts",
"field": "author",
"special": ["m2o"],
"interface": "select-dropdown-m2o",
"options": {
"template": "{{image.$thumbnail}} {{name}}"
},
"display": "related-values",
"display_options": {
"template": "{{image.$thumbnail}} {{name}}"
},
"sort": 15,
"width": "half"
}
}
```
### O2M Field Example
```json
{
"collection": "posts",
"field": "comments",
"type": "alias",
"schema": null,
"meta": {
"collection": "posts",
"field": "comments",
"special": ["o2m"],
"interface": "list-o2m",
"options": {
"template": "{{author}} - {{content}} ({{status}})"
},
"display": "related-values",
"display_options": {
"template": "{{author}} - {{content}} ({{status}})"
},
"sort": 10,
"width": "full",
"required": false,
"group": null
}
}
```
### M2M Field Example
```json
{
"collection": "posts",
"field": "categories",
"type": "alias",
"schema": null,
"meta": {
"collection": "posts",
"field": "categories",
"special": ["m2m"],
"interface": "list-m2m",
"options": {
"template": "{{categories_id.name}} ({{categories_id.slug}})"
},
"display": "related-values",
"display_options": {
"template": "{{categories_id.name}} ({{categories_id.slug}})"
},
"sort": 9,
"width": "full"
}
}
```
### M2A Field Example
```json
{
"collection": "pages",
"field": "blocks",
"type": "alias",
"schema": null,
"meta": {
"collection": "pages",
"field": "blocks",
"special": ["m2a"],
"interface": "list-m2a",
"options": {},
"display": "related-values",
"display_options": {
"template": "{{collection}}"
},
"sort": 8,
"width": "full"
}
}
```
### File Field Example
```json
{
"collection": "posts",
"field": "featured_image",
"type": "uuid",
"schema": {
"name": "featured_image",
"table": "posts",
"data_type": "uuid",
"is_nullable": true,
"foreign_key_schema": "public",
"foreign_key_table": "directus_files",
"foreign_key_column": "id"
},
"meta": {
"collection": "posts",
"field": "featured_image",
"special": ["file"],
"interface": "file-image",
"options": {
"folder": "post-images"
},
"display": "image",
"display_options": null,
"sort": 1,
"width": "half",
"required": false,
"group": "media"
}
}
```
### Files Field Example
```json
{
"collection": "posts",
"field": "gallery",
"type": "alias",
"schema": null,
"meta": {
"collection": "posts",
"field": "gallery",
"special": ["files"],
"interface": "files",
"options": null,
"display": "related-values",
"display_options": null,
"sort": 4,
"width": "full"
}
}
```
### Translations Field Example
```json
{
"collection": "posts",
"field": "translations",
"type": "alias",
"schema": null,
"meta": {
"collection": "posts",
"field": "translations",
"special": ["translations"],
"interface": "translations",
"options": {
"userLanguage": true,
"defaultOpenSplitView": true
},
"display": "translations",
"display_options": {
"template": "{{title}}", // Field to display from the translated collection (ie post title)
"languageField": "name" // Name of the language field from the languages collection
},
"sort": 22,
"width": "full"
}
}
```
**Note**: Alias fields don't need a schema object since they're virtual. </relationship_fields>
<primary_keys> **🎯 ALWAYS use UUID as primary keys for new collections unless integers or manually entered strings ares
specifically requested by the user.**
**UUID Primary Key Template:**
```json
{
"field": "id",
"type": "uuid",
"meta": { "hidden": true, "readonly": true, "interface": "input", "special": ["uuid"] },
"schema": { "is_primary_key": true, "length": 36, "has_auto_increment": false }
}
```
</primary_keys>
<interfaces>
## Common Interfaces
**Text**: `input`, `input-multiline`, `input-rich-text-md`, `input-rich-text-html`, `input-hash`, `translations`
**Selection**: `select-dropdown`, `select-multiple-dropdown`, `select-radio`, `select-multiple-checkbox`, `tags`,
`boolean`, `slider` **Date/Time**: `datetime`, `date`, `time` **Relational**: `select-dropdown-m2o`, `list-o2m`,
`list-m2m`, `list-m2a` **Files**: `file`, `files`, `file-image` **Advanced**: `input-code`, `map`, `group-raw`,
`group-detail` </interfaces>
<field_configuration>
### Layout
- **width**: `"half"` (380px max), `"full"` (760px max, default), `"fill"` (no limit)
- **sort**: Field order in forms
- **group**: Group related fields into collapsible sections (must be used with `alias` group fields)
### Schema Properties
- **default_value**: Default for new items
- **is_nullable**: Can be null
- **is_unique**: Must be unique
- **length**: Max length for strings
### Meta Properties
- **required**: Must have value
- **readonly**: Cannot edit after creation
- **hidden**: Hidden from UI (still in API)
- **validation**: Custom validation rules
- **validation_message**: Custom error messages
- **note**: Context for non-obvious fields
### Conditions
Dynamically control field behavior based on other field values:
```json
{
"conditions": [
{
"name": "Hide If Author Is Null",
"rule": {
"_and": [
{
"author": {
"_null": true
}
}
]
},
"hidden": true
},
{
"name": "Required If Published",
"rule": {
"status": {
"_eq": "published"
}
},
"required": true
}
]
}
```
**Condition Properties**:
- `name`: Description of the condition
- `rule`: Filter rules using Directus filter syntax
- Can set: `hidden`, `readonly`, `required`, or interface-specific options
**Common Rules**:
- `_null`: Check if field is null
- `_eq`: Equals specific value
- `_neq`: Not equals
- `_in`: Value in array
- `_and`/`_or`: Combine multiple conditions
### Special Fields
- `special: ["uuid"]`: Auto-generate UUID
- `special: ["user-created"]`: Track creating user
- `special: ["date-created"]`: Track creation time
- `special: ["user-updated"]`: Track last editor
- `special: ["date-updated"]`: Track last edit time
- `special: ["cast-json"]`: Cast JSON strings to objects </field_configuration>
<translations>
Field names can (and should be) translated for editors using the app.
Check for `languages` collection first, then add field translations based on which languages are stored in DB. IF not 99% sure, confirm with user first.
```json
"translations": [
{"language": "en-US", "translation": "Title"},
{"language": "es-ES", "translation": "Título"}
]
```
</translations>
<display_templates> Display templates can be customized used to enhance the UX for editors.
```json
"display": "related-values",
"display_options": {
"template": "{{first_name}} {{last_name}}"
}
```
**Display types**: `raw`, `formatted-value`, `labels`, `datetime`, `user`, `file`, `related-values` </display_templates>
<complete_example>
#### Complete Field Example with Advanced Features
This shows a real field configuration with validation, conditions, and all metadata (as returned from a read operation):
```json
{
"collection": "block_button",
"field": "url",
"type": "string",
"schema": {
"name": "url",
"table": "block_button",
"data_type": "character varying", // Database-specific type
"default_value": null,
"generation_expression": null,
"max_length": 255, // String length limit
"numeric_precision": null,
"numeric_scale": null,
"is_generated": false,
"is_nullable": true,
"is_unique": false,
"is_indexed": false,
"is_primary_key": false,
"has_auto_increment": false,
"foreign_key_schema": null, // Would contain relation info for M2O fields
"foreign_key_table": null,
"foreign_key_column": null,
"comment": null
},
"meta": {
"id": 811, // Auto-generated field ID (not used in create)
"collection": "block_button",
"field": "url",
"special": null, // No special behavior for this field
"interface": "input",
"options": {
"iconLeft": "link", // Icon displayed in the input
"trim": true // Remove whitespace on save
},
"display": "formatted-value",
"display_options": {
"format": true // Apply auto formatting based on field type
},
"readonly": false,
"hidden": true, // Hidden by default, shown conditionally
"sort": 11, // Field order in forms
"width": "half",
"translations": null, // No field name translations
"note": "The URL to link to. Could be relative (ie `/my-page`) or a full external URL (ie `https://docs.directus.io`)",
"conditions": [
{
"hidden": false, // Show field when condition is met
"name": "If type = external",
"options": {
"clear": false,
"font": "sans-serif",
"masked": false,
"slug": false,
"trim": false
},
"rule": {
"_and": [
{
"type": {
// Show when 'type' field equals 'url'
"_eq": "url"
}
}
]
}
}
],
"required": false,
"group": null,
"validation": {
"_and": [
{
"url": {
"_regex": "^(?:\\/[A-Za-z0-9\\-._~%!$&'()*+,;=:@\\/]*|https?:\\/\\/[^\\s/$.?#].[^\\s]*)$"
}
}
]
}, // Regex validation for URLs (relative or absolute)
"validation_message": "Invalid URL. Check your URL and try again. Properly formatted relative URLs (`/pages/test` ) and absolute URLs (`https://example.com`) are supported."
}
}
```
</complete_example>
<related_tools>
## Related Tools
- `collections`: Create containers for fields
- `relations`: Connect fields between collections </related_tools>