UNPKG

wcz-layout

Version:

115 lines (98 loc) 4.37 kB
--- name: server description: Create TanStack Start server functions or REST API routes using Drizzle ORM, Zod schemas and middleware. --- ## First Step (required) Before generating code, always ask the user whether the feature should be exposed as public REST API routes or implemented as internal TanStack Start server functions (recommended), and what permission should be required for access. ## Rules - Follow the chain order for server functions: `inputValidator` → `middleware` → `handler`. - In middleware, always follow this order: `validationMiddleware` → `databaseMiddleware` → `authorizationMiddleware`. - Use `validationMiddleware` only in REST API routes (handler-level middleware). Server functions use `.inputValidator()` instead. - If permission is unknown, use `"all"`. - `databaseMiddleware` wraps the handler in a DB transaction. - Reuse schemas from `src/lib/schemas/`. ## File Placement ``` src/server/actions/ — server functions src/routes/api/ — REST API routes src/server/middleware/ — server middleware wcz-layout/middleware/ — shared middleware from npm package src/server/db/schemas/ — tables, enums, relations src/lib/schemas/ — Zod schemas src/lib/auth/permissions.ts — permission keys ``` ## Examples ```ts // imports import { authorizationMiddleware, validationMiddleware } from "wcz-layout/middleware"; import { databaseMiddleware } from "~/server/middleware/databaseMiddleware"; // src/server/actions/books.ts export const selectBooks = createServerFn() .middleware([databaseMiddleware, authorizationMiddleware("all")]) .handler(async ({ context }) => { return await context.db.select().from(bookTable); }); export const insertBook = createServerFn({ method: "POST" }) .inputValidator(BookSchema) .middleware([databaseMiddleware, authorizationMiddleware("admin")]) .handler(async ({ data, context }) => { await context.db.insert(bookTable).values(data); }); export const updateBook = createServerFn({ method: "POST" }) .inputValidator(BookSchema) .middleware([databaseMiddleware, authorizationMiddleware("admin")]) .handler(async ({ data, context }) => { await context.db.update(bookTable).set(data).where(eq(bookTable.id, data.id)); }); export const deleteBook = createServerFn({ method: "POST" }) .inputValidator(BookSchema.pick({ id: true })) .middleware([databaseMiddleware, authorizationMiddleware("admin")]) .handler(async ({ data, context }) => { await context.db.delete(bookTable).where(eq(bookTable.id, data.id)); }); // src/routes/api/books/index.ts export const Route = createFileRoute("/api/books/")({ server: { middleware: [databaseMiddleware], handlers: ({ createHandlers }) => createHandlers({ GET: { middleware: [authorizationMiddleware("all")], handler: async ({ context }) => { const items = await context.db.select().from(bookTable); return Response.json(items); }, }, POST: { middleware: [validationMiddleware(BookSchema), authorizationMiddleware("admin")], handler: async ({ context }) => { const [response] = await context.db.insert(bookTable).values(context.data).returning(); return Response.json(response, { status: 201 }); }, }, }), }, }); // src/routes/api/books/$id.ts export const Route = createFileRoute("/api/books/$id")({ server: { middleware: [databaseMiddleware, authorizationMiddleware("admin")], handlers: ({ createHandlers }) => createHandlers({ PUT: { middleware: [validationMiddleware(BookSchema)], handler: async ({ params, context }) => { await context.db.update(bookTable).set(context.data).where(eq(bookTable.id, params.id)); return new Response(null, { status: 204 }); }, }, DELETE: async ({ params, context }) => { await context.db.delete(bookTable).where(eq(bookTable.id, params.id)); return new Response(null, { status: 204 }); }, }), }, }); ``` ## Next Step (ask user after completion) - Generate TanStack DB Collection.