xiaohongshu
xiaohongshu
bknd-crud-create
Use when inserting new records into a Bknd entity via the SDK or REST API. Covers createOne, createMany, creating with relations ($set), response handling, error handling, and common patterns for client-side record creation.
Full skill instructions
Insert new records into your Bknd database using the SDK or REST API.
bknd-create-entity first)UI steps: Admin Panel > Data > Select Entity > Click "+" or "Add" > Fill form > Save
import { Api } from "bknd";
const api = new Api({
host: "http://localhost:7654", // Your Bknd server
});
// If auth required:
api.updateToken("your-jwt-token");
Use createOne(entity, data):
const { ok, data, error } = await api.data.createOne("posts", {
title: "My First Post",
content: "Hello world!",
published: false,
});
if (ok) {
console.log("Created post:", data.id);
} else {
console.error("Failed:", error.message);
}
The response object:
type CreateResponse = {
ok: boolean; // Success/failure
data?: { // Created record (if ok)
id: number; // Auto-generated ID
// ...all fields with defaults applied
};
error?: { // Error info (if !ok)
message: string;
code: string;
};
};
Link to existing related records using $set:
// Link to single related record (many-to-one)
const { data } = await api.data.createOne("posts", {
title: "New Post",
author: { $set: 1 }, // Link to user with ID 1
});
// Link to multiple related records (many-to-many)
const { data } = await api.data.createOne("posts", {
title: "Tagged Post",
tags: { $set: [1, 2, 3] }, // Link to tag IDs 1, 2, 3
});
// Combine both
const { data } = await api.data.createOne("posts", {
title: "Complete Post",
content: "Full content here",
author: { $set: userId },
category: { $set: categoryId },
tags: { $set: [tagId1, tagId2] },
});
Use createMany(entity, data[]):
const { ok, data } = await api.data.createMany("tags", [
{ name: "javascript" },
{ name: "typescript" },
{ name: "bknd" },
]);
// data is array of created records
console.log("Created", data.length, "tags");
curl -X POST http://localhost:7654/api/data/posts \
-H "Content-Type: application/json" \
-d '{"title": "New Post", "content": "Hello!"}'
curl -X POST http://localhost:7654/api/data/posts \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-d '{"title": "Protected Post"}'
curl -X POST http://localhost:7654/api/data/tags \
-H "Content-Type: application/json" \
-d '[{"name": "tag1"}, {"name": "tag2"}]'
curl -X POST http://localhost:7654/api/data/posts \
-H "Content-Type: application/json" \
-d '{"title": "Post", "author": {"$set": 1}}'
import { useApp } from "bknd/react";
function CreatePostForm() {
const { api } = useApp();
const [title, setTitle] = useState("");
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setLoading(true);
setError(null);
const { ok, data, error: apiError } = await api.data.createOne("posts", {
title,
published: false,
});
setLoading(false);
if (ok) {
console.log("Created:", data.id);
setTitle("");
} else {
setError(apiError.message);
}
}
return (
<form onSubmit={handleSubmit}>
<input
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="Post title"
required
/>
<button type="submit" disabled={loading}>
{loading ? "Creating..." : "Create Post"}
</button>
{error && <p className="error">{error}</p>}
</form>
);
}
import { useApp } from "bknd/react";
import useSWR, { mutate } from "swr";
function PostsList() {
const { api } = useApp();
const { data: posts } = useSWR("posts", () =>
api.data.readMany("posts").then((r) => r.data)
);
async function createPost(title: string) {
const { ok, data } = await api.data.createOne("posts", { title });
if (ok) {
// Revalidate the posts list
mutate("posts");
}
return { ok, data };
}
return (
<div>
<CreateForm onCreate={createPost} />
<ul>
{posts?.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
);
}
import { Api } from "bknd";
const api = new Api({ host: "http://localhost:7654" });
// Authenticate first (if required)
await api.auth.login({ email: "[email protected]", password: "password" });
// Create a user
const { data: user } = await api.data.createOne("users", {
email: "[email protected]",
name: "New User",
role: "author",
});
// Create a post linked to user
const { data: post } = await api.data.createOne("posts", {
title: "My First Blog Post",
content: "This is the content of my post.",
published: true,
author: { $set: user.id },
});
// Create tags
const { data: tags } = await api.data.createMany("tags", [
{ name: "intro" },
{ name: "tutorial" },
]);
// Link tags to post (update after creation)
await api.data.updateOne("posts", post.id, {
tags: { $set: tags.map((t) => t.id) },
});
console.log("Created post:", post.id, "with tags:", tags.length);
Bknd applies defaults for omitted fields:
// Entity definition
entity("posts", {
title: text().required(),
status: text({ default_value: "draft" }),
view_count: number({ default_value: 0 }),
created_at: date({ default_value: "now" }),
});
// Create with minimal data
const { data } = await api.data.createOne("posts", {
title: "Just a title", // Only required field
});
// Result includes defaults
console.log(data);
// {
// id: 1,
// title: "Just a title",
// status: "draft", // default applied
// view_count: 0, // default applied
// created_at: "2025-01-20T..." // default applied
// }
Bknd validates data against schema:
// Entity with constraints
entity("users", {
email: text().required().unique(),
name: text(),
});
// Missing required field
const { ok, error } = await api.data.createOne("users", {
name: "No Email",
});
// ok: false, error: { message: "email is required" }
// Duplicate unique field
const { ok, error } = await api.data.createOne("users", {
email: "[email protected]", // Already exists
});
// ok: false, error: { message: "UNIQUE constraint failed" }
async function createOrFind(
api: Api,
entity: string,
data: object,
uniqueField: string
) {
// Try to find existing
const { data: existing } = await api.data.readOneBy(entity, {
where: { [uniqueField]: { $eq: data[uniqueField] } },
});
if (existing) {
return { created: false, data: existing };
}
// Create new
const { data: created } = await api.data.createOne(entity, data);
return { created: true, data: created };
}
// Usage
const { created, data } = await createOrFind(
api,
"users",
{ email: "[email protected]", name: "User" },
"email"
);
function useCreatePost() {
const { api } = useApp();
const [posts, setPosts] = useState<Post[]>([]);
async function createPost(title: string) {
// Optimistic: add temp post immediately
const tempId = `temp-${Date.now()}`;
const tempPost = { id: tempId, title, status: "creating" };
setPosts((prev) => [...prev, tempPost]);
// Actual create
const { ok, data } = await api.data.createOne("posts", { title });
if (ok) {
// Replace temp with real
setPosts((prev) =>
prev.map((p) => (p.id === tempId ? data : p))
);
} else {
// Remove temp on failure
setPosts((prev) => prev.filter((p) => p.id !== tempId));
}
return { ok, data };
}
return { posts, createPost };
}
async function batchCreate(
api: Api,
entity: string,
items: object[],
onProgress?: (done: number, total: number) => void
) {
const results = [];
const batchSize = 100;
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);
const { data } = await api.data.createMany(entity, batch);
results.push(...data);
onProgress?.(Math.min(i + batchSize, items.length), items.length);
}
return results;
}
// Usage
const items = generateItems(500);
await batchCreate(api, "products", items, (done, total) => {
console.log(`Progress: ${done}/${total}`);
});
Problem: NOT NULL constraint failed
Fix: Include all required fields:
// Entity: email is required
entity("users", { email: text().required(), name: text() });
// Wrong - missing email
await api.data.createOne("users", { name: "Test" });
// Correct
await api.data.createOne("users", { email: "[email protected]", name: "Test" });
Problem: FOREIGN KEY constraint failed
Fix: Ensure related record exists:
// Wrong - author ID doesn't exist
await api.data.createOne("posts", { title: "Post", author: { $set: 999 } });
// Correct - verify first or handle error
const { data: author } = await api.data.readOne("users", authorId);
if (author) {
await api.data.createOne("posts", { title: "Post", author: { $set: authorId } });
}
Problem: UNIQUE constraint failed
Fix: Check before create or handle error:
// Option 1: Check first
const { data: exists } = await api.data.exists("users", {
email: { $eq: email },
});
if (exists.exists) {
throw new Error("Email already registered");
}
await api.data.createOne("users", { email, name });
// Option 2: Handle error
const { ok, error } = await api.data.createOne("users", { email, name });
if (!ok && error.message.includes("UNIQUE")) {
throw new Error("Email already registered");
}
Problem: Assuming success without checking.
Fix: Always check ok:
// Wrong - assumes success
const { data } = await api.data.createOne("posts", { title });
console.log(data.id); // data might be undefined!
// Correct
const { ok, data, error } = await api.data.createOne("posts", { title });
if (!ok) {
throw new Error(error.message);
}
console.log(data.id);
Problem: Unauthorized error.
Fix: Authenticate first or check permissions:
// Login first
await api.auth.login({ email, password });
// Or set token
api.updateToken(savedToken);
// Then create
await api.data.createOne("posts", { title });
After creating, verify the record:
const { ok, data } = await api.data.createOne("posts", { title: "Test" });
if (ok) {
// Read back to verify
const { data: fetched } = await api.data.readOne("posts", data.id);
console.log("Created and verified:", fetched);
}
Or via admin panel: Admin Panel > Data > Select Entity > Find new record.
DO:
ok field before using data$setDON'T:
$set$set linkingxiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience