Building a Basic App

Learn how to create a new module, schema, and API route with Bedest.

1. Define Your Schema

Create a new Drizzle schema file under src/features/post/schemas/SPost.ts. We will use the Bedest Core helpers to ensure our schema supports multi-tenancy and soft deletes.

import { pgTable, varchar, text, uuid } from "drizzle-orm/pg-core";
import { baseColumns, UtilDbSchema } from "bedest-core";

export const SPost = pgTable(
  "post",
  {
    ...baseColumns,
    tenantId: uuid("tenant_id").notNull(),
    title: varchar("title", { length: 255 }).notNull(),
    content: text("content"),
  },
  (t) => [
    UtilDbSchema.activeIndex("idx_post_active", t.id),
    UtilDbSchema.tenantIsolationPolicy(t.tenantId),
  ]
).enableRLS();

2. Create the Service

Extend the ServiceBaseTenant to automatically inherit robust, RLS-protected CRUD operations without writing any boilerplate SQL.

// src/features/post/services/ServicePost.ts
import { ServiceBaseTenant } from "bedest-core";
import { SPost } from "../schemas/SPost";

class ServicePost extends ServiceBaseTenant<typeof SPost> {
  constructor() {
    super(SPost);
  }
  
  // You can add custom business logic here
  // The base class already handles: create, update, remove, getAll, getById
}

export default new ServicePost();

3. Expose the Router

Now, map your service to Elysia routes. Use Bedest's validation objects and decorators to secure your API.

// src/features/post/routers/RouterPost.ts
import Elysia, { t } from "elysia";
import ServicePost from "../services/ServicePost";
import { defPaginatedSchema, VId, VQuery } from "bedest-core";

const RouterPost = new Elysia({ prefix: "/posts" })
  // Secure these routes using RoleGuard
  .guard({ RoleGuard: ["ADMIN", "USER"] })
  .get(
    "/",
    async ({ app, query }) => await ServicePost.getAll(app, query),
    defPaginatedSchema("Post", t.Object({}))
  )
  .post(
    "/",
    async ({ app, body }) => await ServicePost.create(app, body),
    {
      body: t.Object({
        title: t.String(),
        content: t.Optional(t.String()),
      }),
      audit: { action: "POST_CREATED" }, // Automatic audit logging!
    }
  );

export default RouterPost;

4. Register the Router

Finally, open src/app/Router.ts and add your new RouterPost to the main application tree.

Success! You've just created a secure, multi-tenant ready, strictly typed, and auditable REST API endpoint in under 3 minutes.