Full-Stack Development
Data & CRUD
Define custom data models in TOML, get auto-generated REST APIs, and build the frontend data layer.
The Flow
TOML Definition → Auto DB Table → Auto CRUD API → Frontend Data LayerYou define the schema once. RaisFast handles the rest.
Step 1 — Define a Content Type
Create a TOML file in your project:
name = "Article"
table = "articles"
plural = "articles"
[fields.title]
type = "text"
required = true
index = true
[fields.slug]
type = "text"
required = true
unique = true
[fields.body]
type = "rich_text"
[fields.excerpt]
type = "text"
max_length = 500
[fields.cover_image]
type = "media"
accept = "image/*"
[fields.category]
type = "relation"
related_type = "categories"
relation = "many_to_one"
[fields.tags]
type = "relation"
related_type = "tags"
relation = "many_to_many"
[fields.status]
type = "enum"
options = ["draft", "published", "archived"]
default = "draft"
[fields.published_at]
type = "timestamp"Restart the server. The table and API are created automatically.
Step 2 — Use the Auto-Generated API
| Method | Endpoint | Description |
|---|---|---|
GET | /api/v1/admin/cms/articles | List (with pagination, filters, search) |
POST | /api/v1/admin/cms/articles | Create |
GET | /api/v1/admin/cms/articles/:id | Get by ID |
PUT | /api/v1/admin/cms/articles/:id | Update |
DELETE | /api/v1/admin/cms/articles/:id | Delete |
Query Examples
# List with pagination
GET /api/v1/admin/cms/articles?page=1&limit=10
# Filter by status
GET /api/v1/admin/cms/articles?status=published
# Search
GET /api/v1/admin/cms/articles?search=introduction
# Sort by date descending
GET /api/v1/admin/cms/articles?sort=created_at&order=descStep 3 — Frontend Data Layer
import { client } from "@/lib/client";
// List articles
const { data } = await client.contentTypes.list("articles", {
page: 1,
limit: 10,
status: "published",
sort: "created_at",
order: "desc",
});
// Create article
const article = await client.contentTypes.create("articles", {
title: "My Article",
slug: "my-article",
body: "<p>Content here</p>",
status: "draft",
});
// Update article
await client.contentTypes.update("articles", article.id, {
status: "published",
});
// Delete article
await client.contentTypes.delete("articles", article.id);import { client } from "@/lib/client";
// List articles
const { data } = await client.contentTypes.list("articles", {
page: 1,
limit: 10,
status: "published",
sort: "created_at",
order: "desc",
});
// Create article
const article = await client.contentTypes.create("articles", {
title: "My Article",
slug: "my-article",
body: "<p>Content here</p>",
status: "draft",
});
// Update article
await client.contentTypes.update("articles", article.id, {
status: "published",
});
// Delete article
await client.contentTypes.delete("articles", article.id);Available Field Types
| Type | Description | Example Use |
|---|---|---|
text | Short text (up to 255 chars) | Title, name |
rich_text | Long HTML content | Body, description |
number | Integer or float | Price, quantity |
boolean | True/false | Published, active |
enum | Predefined options | Status, role |
timestamp | Date/time | Created at, scheduled |
media | File upload | Cover image, attachment |
relation | Link to another type | Author, category |
json | Arbitrary JSON data | Metadata, settings |
Relations
# Many-to-one: each article belongs to one category
[fields.category]
type = "relation"
related_type = "categories"
relation = "many_to_one"
# Many-to-many: articles can have multiple tags
[fields.tags]
type = "relation"
related_type = "tags"
relation = "many_to_many"
# One-to-one: a user has one profile
[fields.profile]
type = "relation"
related_type = "profiles"
relation = "one_to_one"Next Step
Ready to build a real project? Follow the Blog Tutorial.
