RaisFastRaisFast
Content Types

Relations

6 relation types with automatic join tables and query population.

Relations link content types together. Define them with field_type = "relation" and a relation config.

Relation Types

TypeDescriptionFK LocationData Format
one_to_oneSingle related recordSource tableString (target ID)
one_to_manyMultiple records in targetTarget tableArray of IDs
many_to_oneBelongs toSource tableString (target ID)
many_to_manyVia junction tableJunction tableArray of IDs
one_wayUnidirectional referenceSource tableString (target ID)
many_wayUnidirectional manyJunction tableArray of IDs

Many To One

The most common relation — "belongs to". The foreign key lives in the source table.

# Each course belongs to one instructor
[[fields]]
name = "instructor"
field_type = "relation"
relation = { relation_type = "many_to_one", target = "instructors" }

This adds an instructor_id column to the courses table.

# Create a course linked to an instructor
curl -X POST http://localhost:9898/api/v1/cms/courses \
  -d '{"title":"Rust 101","instructor":"<instructor_id>"}'

One To Many

"inverse of many_to_one". The foreign key lives in the target table.

# An instructor has many courses (FK is in courses table)
[[fields]]
name = "courses"
field_type = "relation"
relation = { relation_type = "one_to_many", target = "courses" }

This does not add a column — it reads the existing FK on the target side. Use it for reverse lookups.

Many To Many

Links via an auto-created junction table.

# Courses have many tags
[[fields]]
name = "tags"
field_type = "relation"
relation = { relation_type = "many_to_many", target = "tags", through = "courses_tags" }

The system auto-creates the courses_tags junction table with columns course_id and tag_id. Duplicates are prevented with INSERT IGNORE.

# Create a course with tags
curl -X POST http://localhost:9898/api/v1/cms/courses \
  -d '{"title":"Rust 101","tags":["<tag_id_1>","<tag_id_2>"]}'

One To One

A single related record — FK in the source table.

# Each user has one profile
[[fields]]
name = "profile"
field_type = "relation"
relation = { relation_type = "one_to_one", target = "profiles" }

One Way

A unidirectional reference — same as many_to_one but no reverse relation is created on the target side.

# Bookmark references an article, but the article doesn't know about bookmarks
[[fields]]
name = "article_ref"
field_type = "relation"
relation = { relation_type = "one_way", target = "articles" }

Many Way

A unidirectional many relation via junction table — no back-reference on the target.

[[fields]]
name = "recommended"
field_type = "relation"
relation = { relation_type = "many_way", target = "courses", through = "course_recommendations" }

Relation Config Options

[[fields]]
name = "author"
field_type = "relation"
relation = { relation_type = "many_to_one", target = "users", foreign_key = "author_id" }
required = true
OptionRequiredDefaultDescription
relation_typeyesOne of the 6 types above
targetyesTarget table name
foreign_keyno{field_name}_idCustom FK column name
throughno{source}_{target}Junction table name (M2M / ManyWay)

Additionally, required = true makes the FK column NOT NULL.

Populate Relations with include

By default, relation fields return IDs. Use the include query parameter to expand them into full records:

# Populate single relation
curl http://localhost:9898/api/v1/cms/courses?include=instructor

# Populate multiple relations
curl http://localhost:9898/api/v1/cms/courses?include=instructor,tags

# Nested populate — include lessons inside courses
curl http://localhost:9898/api/v1/cms/courses?include=instructor,lessons,tags

Response with include:

{
  "id": "abc123",
  "title": "Rust 101",
  "instructor": {
    "id": "xyz789",
    "name": "Alice"
  },
  "tags": [
    { "id": "t1", "name": "Rust" },
    { "id": "t2", "name": "Programming" }
  ]
}

Without include, the same request returns:

{
  "id": "abc123",
  "title": "Rust 101",
  "instructor": "xyz789",
  "tags": ["t1", "t2"]
}

Filter by Relation

Use {field_name}_id to filter by relation:

# All courses by a specific instructor
curl "http://localhost:9898/api/v1/cms/courses?instructor_id=xyz789"

# All lessons for a specific course
curl "http://localhost:9898/api/v1/cms/lessons?course_id=abc123"

Junction Table Auto-Cleanup

When you delete a record that has ManyToMany / ManyWay relations, the junction table rows are automatically removed. No orphaned references.

Best Practices

  1. Define relations on both sides — e.g., many_to_one on Course → Instructor and one_to_many on Instructor → Courses. This enables bidirectional include.
  2. Let the system name junction tables — omit through unless you need a specific name; the default {source}_{target} convention is clear and consistent.
  3. Use one_way / many_way when the target content type should not have a reverse link (e.g., activity logs, audit references).

On this page