Cursor rule
.cursor/rules/api.mdcGuidelines for creating typesafe apis on hono restful API.
Cursor rules
Quality
86/100
Scores the file, not the repository.Length
1,053 words
14 headings · 6 code blocksRepository
1
— · pushed 306 days agoLast changed
3 days ago
First indexed 3 days ago.123456# Backend API Architecture and Development Guidelines78You are an expert TypeScript backend engineer specializing in building modern, type-safe APIs. Your expertise covers Hono for HTTP routing, Drizzle ORM for database operations, and React Query for frontend integration.910<core_architecture>1112<tech_stack>13- **Server & Routing**: Hono14- **Database ORM**: Drizzle with PostgreSQL15- **Frontend Integration**: React Query16- **Authentication**: Clerk17- **Validation**: Zod with zValidator18</tech_stack>1920<project_structure>21apps/22 ├── api/23 │ ├── src/24 │ │ ├── modules/ # Feature-based modules25 │ │ │ ├── [module]/ # e.g., posts, webhooks26 │ │ │ │ ├── [module].routes.ts # Route definitions27 │ │ │ │ └── [module].service.ts # Business logic & DB operations28 │ │ ├── pkg/ # Shared utilities and middleware29 │ │ └── index.ts # Main application setup30 └── web/31 └── src/32 └── api/33 └── [module].api.ts # React Query hooks3435packages/36 └── db/37 ├── src/38 │ ├── schema.ts # Database schema definitions39 │ ├── types.ts # Shared TypeScript types40 │ ├── index.ts # Main exports41 │ └── util/ # Database utilities42</project_structure>4344<module_development_guidelines>45### 1. Database layer46- If the request needs a new column or addition database fields start by creating and updating schema.ts47- Leverage types.ts inside packages/db to create new zod schemas for the newly created tables or columns and eg:48```49export type Post = InferSelectModel<typeof schema.posts>;50export type NewPost = InferInsertModel<typeof schema.posts>;5152export const postInsertSchema = createInsertSchema(schema.posts).omit({ userId: true });53export const postSelectSchema = createSelectSchema(schema.posts);54```555657### 2. Service Layer ([module].service.ts)58- Implement business logic59- Handle database operations using Drizzle60- Return strongly typed responses61- Keep services focused and modular62- Import db from the `packages/db`6364Example service implementation:65```ts66`[module].service.ts`67import { db, eq, items} from "@repo/db"6869export const moduleService = {70 async getItems() {71 return db.select().from(items);72 },7374 async createItem(data: NewItem) {75 return db.insert(items).values(data).returning();76 }77};78```798081### 3. Route Layer ([module].routes.ts)82- Define endpoints using Hono router83- Implement request validation using zValidator. You can leverage the created zod schemas from drizzle zod.84- Apply authentication middleware where needed85- Structure routes logically by resource86- Return consistent HTTP responses8788Example route implementation:89```ts90const moduleRoutes = new Hono()91 .use(auth(),requireAuth)92 .get("/", async (c) => {93 const items = await moduleService.getItems();94 return c.json(items);95 })96 .post("/", zValidator("json", insertSchema), async (c) => {97 const data = c.req.valid("json");98 const userId = getUserId(c);99 const result = await moduleService.createItem({ ...data, userId });100 return c.json(result);101 });102```103104After the route is created, you must add it to the `apps/api/src/index.ts` route so its accessable by the frontend.105106</module_development_guidelines>107108<frontend_integration>109When fetching data from the backend api on the client, use the following guidelines110`post.api.ts`111```ts112import { apiRpc, getApiClient, InferRequestType } from "./client";113114const $createPost = apiRpc.posts.$post;115// Simple get116export async function getPosts() {117 const client = await getApiClient();118119 const response = await client.posts.$get();120 return response.json();121}122// Safely leverage the typed params elsewhere within the nextjs application123export type CreatePostParams = InferRequestType<typeof $createPost>["json"];124export async function createPost(params: CreatePostParams) {125 const client = await getApiClient();126127 const response = await client.posts.$post({ json: params });128 return response.json();129}130```131</frontend_integration>132<package_management>133134- Use `pnpm` as the primary package manager for the project135- Install dependencies using `pnpm add [package-name]`136- Install dev dependencies using `pnpm add -D [package-name]`137- Install workspace dependencies using `pnpm add -w [package-name]`138</package_management>139140<development_guidelines>141### Running Scripts142- Use `bun` as the runtime environment and script runner143- Execute scripts defined in package.json using `bun run [script-name]`144- Run TypeScript files directly using `bun [file.ts]`145146### Monorepo147The project use turbo repo. To run everything, use the `turbo dev` script from the root folder.148149### Type Safety150- Use Drizzle schemas for database types151- Share types between frontend and backend using a shared package152- Leverage zod for runtime validation153154### Error Handling155- Implement consistent error handlers156- Use proper HTTP status codes157- Return structured error responses158- Handle edge cases appropriately159- Use the logger from the package @repo/logger160161### Authentication & Authorization162- Use Clerk middleware for authentication163- Implement role-based access control where needed164- Validate user permissions at the route level165- Keep authentication logic in middleware166167### API Design Principles168- Follow RESTful conventions169- Use consistent naming patterns170- Implement proper request validation171- Structure endpoints by resource/module172- Keep routes clean and delegate logic to services173174### Database Operations175- Use Drizzle for all database interactions176- Implement proper migrations177- Handle transactions when needed178- Write efficient queries179- Use appropriate indexes180</development_guidelines>181182<dev_workflow>183### Creating a New Module for different buisness logic1841. Create module directory in api/src/modules/[module]1852. Define routes in [module].routes.ts1863. Implement service logic in [module].service.ts1874. Add route to main application in index.ts1885. Create frontend integration in web/src/api/[module].api.ts189</dev_workflow>190191### Testing Requirements192- If needed use vitest to create testing files inside of the modules, [module].test.ts193-194### Code Quality195- For methods with more than one argument, use object destructuring: `function myMethod({ param1, param2 }: MyMethodParams) {...}`.196</best_practices>197198199<example_api_workflow>200Here's a complete example of a typical module:201202(if required) create new schemas.203// packages/db/schema.ts204.. new schema files205206Then:207```ts208// posts.service.ts209import { db, posts, type NewPost } from "@repo/db";210211export const postService = {212 async getPosts() {213 return db.select().from(posts);214 },215216 async createPost(post: NewPost) {217 return db.insert(posts).values(post).returning();218 }219};220221// posts.routes.ts222import { Hono } from "hono";223import { auth, requireAuth, getUserId } from "@/pkg/middleware/clerk-auth";224import { postService } from "./post.service";225import { zValidator } from "@/pkg/util/validator-wrapper";226import { postInsertSchema } from "@repo/db";227228export const postRoutes = new Hono()229 .use(auth(),requireAuth)230 .get("/", async (c) => {231 const posts = await postService.getPosts();232 return c.json(posts);233 })234 .post("/", zValidator("json", postInsertSchema), async (c) => {235 const data = c.req.valid("json");236 const userId = getUserId(c);237 const post = await postService.createPost({ ...data, userId });238 return c.json(post);239 });240```241242- Use the RPC-style API client for type-safe API calls243- Leverage `InferRequestType` for parameter typing244- Export plain async functions for API operations245- Optionally create React Query hooks when needed246```ts247// posts.api.ts (Frontend)248import { apiRpc, getApiClient, InferRequestType } from "./client";249250const $createPost = apiRpc.posts.$post;251252export async function getPosts() {253 const client = await getApiClient();254 const response = await client.posts.$get();255 return response.json();256}257258export async function createPost(params: InferRequestType<typeof $createPost>["json"]) {259 const client = await getApiClient();260 const response = await client.posts.$post({ json: params });261 return response.json();262}263```264</example_api_workflow>265266267
Also in deifos/clipmira-subtitles
Diff this repo’s formatsOne repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| deifos/clipmira-subtitles.cursor/rules/db.mdc · 1 | Cursor rules | no sections | 44/100 | 3 days ago | |
| deifos/clipmira-subtitles.cursor/rules/frontend.mdc · 1 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago |
Similar configs
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| hiromaily/go-crypto-wallet.cursor/rules/typescript.mdc · 126 | Cursor rules | setupbuildtestlint-format+6 | 100/100 | 3 days ago | |
| TechSquidTV/Hermes.cursor/rules/10-hermes-api.mdc · 45 | Cursor rules | testlint-formatstylearch+5 | 100/100 | 3 days ago | |
| markstev/mark-starter.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+6 | 99/100 | 3 days ago | |
| Allymahmoud/case-intake-platform.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| dodgecfr/combatfilms-webapp.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| deifos/clipmira-subtitles.cursor/rules/frontend.mdc · 1 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| langflow-ai/langflow.cursor/rules/docs_development.mdc · 153k | Cursor rules | setupbuildtestlint-format+7 | 97/100 | 3 days ago | |
| TechSquidTV/Hermes.cursor/rules/20-hermes-api-tests.mdc · 45 | Cursor rules | teststyletesting-strategysecurity+3 | 97/100 | 3 days ago |
