Conversation
WalkthroughAdds a self-contained Hono + Prisma Postgres REST API example under orm/hono: project scaffold, Prisma schema and seed, Prisma middleware using the Accelerate extension, a Hono server with CRUD endpoints and feed, a .env example, README, and a CI test/run script. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Client
participant Server as Hono App
participant MW as withPrisma
participant PC as PrismaClient
participant DB as PostgreSQL
Client->>Server: HTTP request (e.g., GET /feed)
Server->>MW: enter middleware
MW->>PC: init or reuse PrismaClient (reads DATABASE_URL, attach Accelerate)
MW-->>Server: next()
Server->>PC: execute query (e.g., post.findMany)
PC->>DB: SQL/query
DB-->>PC: result
PC-->>Server: data
Server-->>Client: 200 JSON
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
We can also include a .env.example with the DATABASE_URL, right? All the other templates have it too. 🤔 The dotenv() call should be in src/lib/prisma.ts where the database URL is used. Otherwise, I’m getting a 'DATABASE_URL not found' error. |
|
updated @AmanVarshney01 |
There was a problem hiding this comment.
Actionable comments posted: 4
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (8)
orm/hono/.env.example(1 hunks)orm/hono/README.md(1 hunks)orm/hono/package.json(1 hunks)orm/hono/prisma/schema.prisma(1 hunks)orm/hono/prisma/seed.ts(1 hunks)orm/hono/src/index.ts(1 hunks)orm/hono/src/lib/prisma.ts(1 hunks)orm/hono/tsconfig.json(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-22T12:12:43.161Z
Learnt from: FGoessler
PR: prisma/prisma-examples#8260
File: generator-prisma-client/nextjs-starter-turbopack/components/quotes.tsx:1-1
Timestamp: 2025-08-22T12:12:43.161Z
Learning: In Next.js applications using Prisma, the connection() function from 'next/server' serves a different purpose than 'export const dynamic = force-dynamic'. The connection() function ensures proper database connection context and request isolation, while dynamic = 'force-dynamic' only controls rendering strategy. Both should be used together and are not redundant.
Applied to files:
orm/hono/src/lib/prisma.ts
🪛 dotenv-linter (3.3.0)
orm/hono/.env.example
[warning] 2-2: [QuoteCharacter] The value has quote characters (', ")
(QuoteCharacter)
🪛 markdownlint-cli2 (0.18.1)
orm/hono/README.md
11-11: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
17-17: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
25-25: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
31-31: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
132-132: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: test (orm/nest-graphql-sdl-first)
- GitHub Check: test (orm/betterauth-nextjs)
- GitHub Check: test (orm/nest-graphql)
- GitHub Check: test (orm/grpc)
- GitHub Check: test (orm/nest)
- GitHub Check: test (orm/nuxt)
- GitHub Check: test (orm/solid-start)
🔇 Additional comments (5)
orm/hono/tsconfig.json (1)
1-16: LGTM!The TypeScript configuration is appropriate for a Hono + Node.js project with strict type checking and proper JSX handling for Hono's JSX runtime.
orm/hono/package.json (1)
1-25: LGTM!The package configuration is well-structured with appropriate dependencies, matching Prisma versions in dependencies and devDependencies, and proper script setup for development, build, and start workflows.
orm/hono/src/index.ts (1)
1-30: LGTM!The server implementation is well-structured with proper TypeScript typing for the Prisma-enhanced context, correct middleware usage, and clean route definitions. The Hono app correctly applies the
withPrismamiddleware to inject the Prisma Client into the request context.orm/hono/src/lib/prisma.ts (1)
5-6: Verify the DATABASE_URL loading works correctly.Based on the PR comment by AmanVarshney01, the current placement of
dotenv.config()reportedly causes a "DATABASE_URL not found" error. The placement here at the top of the module should work correctly, as it loads environment variables before line 8 readsprocess.env.DATABASE_URL.Please confirm:
- Does a
.envfile exist in the project root withDATABASE_URLset?- Is the error occurring during
npm run devornpm run build?- What is the exact error message?
If the issue persists, try moving the dotenv import and config to the very top of
src/index.tsbefore any other imports to ensure environment variables are loaded before any module initialization.orm/hono/prisma/schema.prisma (1)
1-32: LGTM!The Prisma schema is well-designed with proper model relationships, appropriate constraints (unique email, autoincrement IDs), sensible defaults, and a custom output path for the generated client that aligns with the project structure.
There was a problem hiding this comment.
Actionable comments posted: 7
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
.github/tests/orm/hono/run.sh(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: test (orm/grpc)
- GitHub Check: test (orm/nest-graphql-sdl-first)
- GitHub Check: test (orm/nuxt)
- GitHub Check: test (orm/nest-graphql)
- GitHub Check: test (orm/solid-start)
There was a problem hiding this comment.
Actionable comments posted: 11
♻️ Duplicate comments (8)
orm/hono/prisma/seed.ts (1)
51-57: Add error handling and ensure proper cleanup.The seed script still lacks error handling and doesn't disconnect the Prisma Client, which can leave database connections open.
.github/tests/orm/hono/run.sh (7)
3-3: Harden shell: add pipefail and trap-based cleanup to avoid masked errors/orphans.The script still uses
set -euwithout handling pipeline failures or ensuring background process cleanup.
17-18: Use npm ci for reproducible CI installs.The script still uses
npm installinstead ofnpm cifor CI environments.
49-51: Do not print DATABASE_URL (secret) to logs.The script still echoes the full DATABASE_URL which leaks credentials in CI logs.
56-56: Migration strategy: prefer idempotent apply for CI.The script still uses
migrate devwhich may prompt and isn't ideal for CI.
59-62: Fix message and set PORT explicitly.The message still says "Starting Hono app" but could benefit from explicit PORT setting.
64-68: Replace static sleep with readiness probe.The script still uses a 20-second sleep instead of actively waiting for the server to be ready.
71-74: Make cleanup resilient; don't fail if processes already exited.The cleanup logic doesn't handle cases where processes have already exited.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (11)
.github/get-ppg-dev/ppg-dev-url.logis excluded by!**/*.logorm/hono/src/generated/prisma/browser.tsis excluded by!**/generated/**orm/hono/src/generated/prisma/client.tsis excluded by!**/generated/**orm/hono/src/generated/prisma/commonInputTypes.tsis excluded by!**/generated/**orm/hono/src/generated/prisma/enums.tsis excluded by!**/generated/**orm/hono/src/generated/prisma/internal/class.tsis excluded by!**/generated/**orm/hono/src/generated/prisma/internal/prismaNamespace.tsis excluded by!**/generated/**orm/hono/src/generated/prisma/internal/prismaNamespaceBrowser.tsis excluded by!**/generated/**orm/hono/src/generated/prisma/models.tsis excluded by!**/generated/**orm/hono/src/generated/prisma/models/Post.tsis excluded by!**/generated/**orm/hono/src/generated/prisma/models/User.tsis excluded by!**/generated/**
📒 Files selected for processing (3)
.github/tests/orm/hono/run.sh(1 hunks)orm/hono/prisma/seed.ts(1 hunks)orm/hono/src/index.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-22T12:12:24.602Z
Learnt from: FGoessler
PR: prisma/prisma-examples#8260
File: generator-prisma-client/nextjs-starter-webpack-turborepo/packages/database/package.json:13-13
Timestamp: 2025-08-22T12:12:24.602Z
Learning: When analyzing changes from package.json seed scripts to "prisma db seed", always verify the actual content of prisma.config.ts rather than relying solely on regex patterns, as the configuration may be properly defined but in a format that doesn't match overly restrictive search patterns.
Applied to files:
orm/hono/prisma/seed.ts
🧬 Code graph analysis (2)
orm/hono/prisma/seed.ts (3)
orm/hono/src/generated/prisma/client.ts (3)
PrismaClient(37-37)PrismaClient(38-38)Prisma(39-39)orm/hono/src/generated/prisma/internal/class.ts (1)
PrismaClient(115-222)orm/hono/src/generated/prisma/models/User.ts (1)
UserCreateInput(242-246)
orm/hono/src/index.ts (3)
orm/hono/src/generated/prisma/client.ts (3)
PrismaClient(37-37)PrismaClient(38-38)Prisma(39-39)orm/hono/src/generated/prisma/models/Post.ts (1)
PostCreateInput(270-275)orm/hono/src/generated/prisma/internal/prismaNamespace.ts (2)
SortOrder(619-622)SortOrder(624-624)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: test (orm/nest)
- GitHub Check: test (orm/grpc)
- GitHub Check: test (orm/astro)
- GitHub Check: test (orm/nest-graphql-sdl-first)
- GitHub Check: test (orm/nextjs-graphql)
- GitHub Check: test (orm/nuxt)
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (8)
orm/hono/src/index.ts (8)
65-83: Fix HTTP status code for update operation.The endpoint returns
201 Created, but updates should return200 OK.Apply this diff:
const post = await prisma.post.update({ where: { id }, data: { viewCount: { increment: 1 } }, }); - return c.json(post, 201); + return c.json(post, 200);
189-191: Make server port configurable via environment variable.The port is hardcoded to 3000, which limits deployment flexibility.
Apply this diff:
-serve({ fetch: app.fetch, port: 3000 }, (info) => { +const port = Number(process.env.PORT) || 3000; +serve({ fetch: app.fetch, port }, (info) => { console.log(`Server is running on http://localhost:${info.port}`); });
132-138: Consider adding pagination to prevent unbounded result sets.Fetching all users without limits could cause performance issues as data grows.
Apply this diff to add pagination:
app.get('/users', withPrisma, async (c) => { const prisma = c.get('prisma'); + const { skip, take } = c.req.query(); const users = await prisma.user.findMany({ include: { posts: true }, + skip: skip ? Number(skip) : undefined, + take: take ? Number(take) : undefined, }); return c.json(users); });
152-161: Add 404 handling for missing posts.The endpoint returns
nullwhen a post doesn't exist instead of a proper 404 response.Apply this diff:
app.get('/post/:id', withPrisma, async (c) => { const prisma = c.get('prisma'); const id = Number(c.req.param('id')); const post = await prisma.post.findUnique({ where: { id, }, }); - return c.json(post); + if (!post) { + return c.json({ error: `Post with ID ${id} not found` }, 404); + } + return c.json(post); });
17-42: Add input validation and error handling for database constraints.The endpoint lacks validation and doesn't handle Prisma errors such as duplicate email violations (P2002).
Apply this diff to add validation and error handling:
app.post('/signup', withPrisma, async (c) => { const prisma = c.get('prisma'); const { name, email, posts } = await c.req.json<{ name: string; email: string; posts: Array<PostCreateInput>; }>(); + if (!email || typeof email !== 'string') { + return c.json({ error: 'Valid email is required' }, 400); + } + const postData = posts ? posts.map((post: Prisma.PostCreateInput) => { return { title: post.title, content: post.content || undefined }; }) : []; - const newUser = await prisma.user.create({ - data: { - name, - email, - posts: { - create: postData, - }, - }, - }); - - return c.json(newUser, 201); + try { + const newUser = await prisma.user.create({ + data: { + name, + email, + posts: { + create: postData, + }, + }, + }); + return c.json(newUser, 201); + } catch (error: any) { + if (error.code === 'P2002') { + return c.json({ error: 'Email already exists' }, 409); + } + throw error; + } });
85-108: Fix status code and optimize database operations.Two issues:
- Wrong HTTP status code: updates should return
200, not201.- Unnecessary
findUnique: the query can be eliminated by handling the error fromupdate.Apply this diff to optimize:
app.put('/publish/:id', withPrisma, async (c) => { const prisma = c.get('prisma'); const id = Number(c.req.param('id')); - const postToUpdate = await prisma.post.findUnique({ - where: { id }, - }); - - if (!postToUpdate) { - c.status(404); - return c.json({ - error: `Post with ID ${id} does not exist in the database`, - }); - } - - const updatedPost = await prisma.post.update({ - where: { - id, - }, - data: { - published: !postToUpdate.published, - }, - }); - return c.json(updatedPost, 201); + + try { + const post = await prisma.post.findUnique({ where: { id } }); + if (!post) { + return c.json({ error: `Post with ID ${id} does not exist in the database` }, 404); + } + const updatedPost = await prisma.post.update({ + where: { id }, + data: { published: !post.published }, + }); + return c.json(updatedPost, 200); + } catch { + return c.json({ error: `Post with ID ${id} does not exist in the database` }, 404); + } });
44-63: Add input validation and handle missing author.The endpoint lacks validation and doesn't handle the case where the author email doesn't exist in the database.
Apply this diff to add validation and error handling:
app.post('/post', withPrisma, async (c) => { const prisma = c.get('prisma'); const { title, content, authorEmail: email, } = await c.req.json<{ title: string; content: string; authorEmail: string; }>(); + + if (!title || typeof title !== 'string') { + return c.json({ error: 'Title is required' }, 400); + } + if (!email || typeof email !== 'string') { + return c.json({ error: 'Author email is required' }, 400); + } + - const newPost = await prisma.post.create({ - data: { - title, - content, - author: { connect: { email } }, - }, - }); - return c.json(newPost, 201); + try { + const newPost = await prisma.post.create({ + data: { + title, + content, + author: { connect: { email } }, + }, + }); + return c.json(newPost, 201); + } catch (error: any) { + if (error.code === 'P2025') { + return c.json({ error: 'Author not found' }, 404); + } + throw error; + } });
163-183: Improve search functionality with case-insensitive matching.The current search is case-sensitive, which may not match user expectations for text search.
Apply this diff to make search case-insensitive:
const or = searchString ? { OR: [ - { title: { contains: searchString as string } }, - { content: { contains: searchString as string } }, + { title: { contains: searchString as string, mode: 'insensitive' } }, + { content: { contains: searchString as string, mode: 'insensitive' } }, ], } : {};
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
orm/hono/prisma/schema.prisma(1 hunks)orm/hono/src/index.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
orm/hono/src/index.ts (1)
orm/graphql/src/schema/post.ts (1)
PostCreateInput(18-23)
🔇 Additional comments (1)
orm/hono/prisma/schema.prisma (1)
1-35: Schema is well-structured.The Prisma schema is correctly configured with:
- Proper generator and datasource setup
- Well-defined User and Post models with appropriate relations
- Sensible defaults (published: false, viewCount: 0)
- Required constraints (email unique)
The
viewCountfield at line 32 properly supports the view tracking endpoint in the API.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (17)
orm/hono/.env.example (1)
2-2: Remove unnecessary quotes from the placeholder value.The empty string quotes are unnecessary and flagged by dotenv-linter. An empty value without quotes is clearer and avoids potential parsing issues.
Apply this diff:
-DATABASE_URL="" +DATABASE_URL=orm/hono/prisma/seed.ts (1)
51-57: Add error handling and ensure proper cleanup.The seed script lacks error handling and doesn't disconnect the Prisma Client, which can leave database connections open. This is especially important for seed scripts that run and exit.
Apply this diff to add proper error handling and cleanup:
-export async function main() { - for (const u of userData) { - await prisma.user.create({ data: u }); - } -} - -main(); +export async function main() { + try { + for (const u of userData) { + await prisma.user.create({ data: u }); + } + } catch (error) { + console.error('Error seeding database:', error); + throw error; + } finally { + await prisma.$disconnect(); + } +} + +main();orm/hono/src/lib/prisma.ts (1)
9-21: Critical: Use a singleton PrismaClient instead of per-context instantiation.The current implementation creates a new
PrismaClientfor each request context that doesn't already have one cached, which is inefficient and can lead to connection pool exhaustion. Thec.set('prisma', prisma)caches the client on the current request context, but each new request will create a new client.PrismaClient should be instantiated once at the module level and reused across all requests. This is the recommended pattern for serverless and long-running server environments.
Apply this diff to implement the singleton pattern:
import type { Context, Next } from 'hono' import { PrismaClient } from '../generated/prisma/client.js' import { withAccelerate } from '@prisma/extension-accelerate' import * as dotenv from 'dotenv' dotenv.config() const databaseUrl = process.env.DATABASE_URL + +if (!databaseUrl) { + throw new Error('DATABASE_URL is not set') +} + +// Create a singleton PrismaClient instance +const prisma = new PrismaClient({ datasourceUrl: databaseUrl }).$extends( + withAccelerate(), +) + function withPrisma(c: Context, next: Next) { - if (!c.get('prisma')) { - if (!databaseUrl) { - throw new Error('DATABASE_URL is not set') - } - const prisma = new PrismaClient({ datasourceUrl: databaseUrl }).$extends( - withAccelerate(), - ) - - c.set('prisma', prisma) - } + c.set('prisma', prisma) return next() } + export default withPrismaorm/hono/README.md (1)
11-11: Add language specifiers to code blocks.Several code blocks are missing language identifiers, which prevents proper syntax highlighting and reduces accessibility.
Apply these changes:
Line 11:
-``` +```bash npx try-prisma@latest --template orm/hono --install npm --name honoLine 17: ```diff -``` +```bash cd honoLine 25: ```diff -``` +```bash git clone git@github.com:prisma/prisma-examples.git --depth=1Line 31: ```diff -``` +```bash cd prisma-examples/orm/hono npm installLine 132: ```diff -``` +```bash npm run devAlso applies to: 17-17, 25-25, 31-31, 132-132 </blockquote></details> <details> <summary>.github/tests/orm/hono/run.sh (7)</summary><blockquote> `3-3`: **Harden shell: add pipefail and trap-based cleanup to avoid masked errors/orphans.** Prevents pipeline errors from being ignored and ensures background processes are cleaned up on failures. Apply this diff: ```diff -set -eu +set -euo pipefail + +# Cleanup background processes on exit +cleanup() { + set +e + if [[ -n "${pid:-}" ]]; then + kill "$pid" 2>/dev/null || true + wait "$pid" 2>/dev/null || true + fi + if [[ -n "${NODE_PID:-}" ]]; then + kill "$NODE_PID" 2>/dev/null || true + wait "$NODE_PID" 2>/dev/null || true + fi +} +trap cleanup EXIT
17-19: Use npm ci for reproducible CI installs.Locks deps to lockfile and speeds up installs.
Apply this diff (ensure package-lock.json exists in both dirs):
-npm install +npm ciAlso applies to: 23-23
49-52: Do not print DATABASE_URL (secret) to logs.This leaks credentials in CI logs. Redact or remove.
Apply this diff:
export DATABASE_URL="$DB_URL" -echo "✅ DATABASE_URL: $DATABASE_URL" +echo "✅ Received DATABASE_URL"
56-57: Migration strategy: prefer idempotent apply for CI.
migrate devcreates migrations and may prompt; in CI examples,db push(no migrations) ormigrate deploy(with checked-in migrations) is typical.Pick one based on the example:
- If no migrations are committed:
-npx prisma migrate dev --name init +npx prisma db push
- If migrations are committed:
-npx prisma migrate dev --name init +npx prisma migrate deploy
59-63: Fix message and set PORT explicitly.Ensure consistent naming and stable port for tests.
Apply this diff:
-# Start the app -echo "🚀 Starting Hapi app..." -npm run dev & +# Start the app +echo "🚀 Starting Hono app..." +export PORT="${PORT:-3000}" +npm run dev &
64-69: Replace static sleep with readiness probe.Avoid flaky timing; wait until the server is actually up before running tests.
Apply this diff:
-sleep 15 - -# Check frontend -echo "🔎 Verifying root frontend route..." -curl --fail 'http://localhost:3000/' +# Wait for app readiness +echo "⏳ Waiting for Hono app to be ready on :${PORT:-3000}..." +MAX_WAIT_APP=60 +WAITED_APP=0 +until curl -sf "http://127.0.0.1:${PORT:-3000}/" >/dev/null; do + sleep 1 + WAITED_APP=$((WAITED_APP + 1)) + if [ "$WAITED_APP" -ge "$MAX_WAIT_APP" ]; then + echo "❌ App did not become ready on :${PORT:-3000}" + exit 1 + fi +done + +# Check frontend +echo "🔎 Verifying root frontend route..." +curl --fail 'http://localhost:3000/'
71-74: Make cleanup resilient; don't fail if processes already exited.Add guards and wait for both PIDs.
Apply this diff (if you didn't add the trap above):
-echo "🛑 Shutting down Hono app (PID $pid) and Prisma Dev (PID $NODE_PID)..." -kill "$pid" -kill "$NODE_PID" -wait "$NODE_PID" || true +echo "🛑 Shutting down Hono app (PID ${pid:-}) and Prisma Dev (PID ${NODE_PID:-})..." +kill "${pid:-}" 2>/dev/null || true +kill "${NODE_PID:-}" 2>/dev/null || true +wait "${pid:-}" 2>/dev/null || true +wait "${NODE_PID:-}" 2>/dev/null || trueIf you added the trap-based cleanup, you can simply rely on it and remove this explicit block.
orm/hono/src/index.ts (6)
17-41: Handle signup validation and duplicate email errorsLine 19 allows
name,poststo be missing or of the wrong type, so Prisma throws a 500. Duplicate emails also surface as raw P2002 errors. Validate the payload up front (return 400/422) and map the unique constraint to a 409 before calling Prisma.app.post('/signup', withPrisma, async (c) => { const prisma = c.get('prisma'); - const { name, email, posts } = await c.req.json<{ - name: string; - email: string; - posts: Array<PostCreateInput>; - }>(); + const body = await c.req.json<{ + name?: string; + email?: string; + posts?: unknown; + }>(); + const { name, email, posts } = body; + + if (!name || typeof name !== 'string' || !name.trim()) { + return c.json({ error: 'Name is required' }, 400); + } + if (!email || typeof email !== 'string' || !email.trim()) { + return c.json({ error: 'Valid email is required' }, 400); + } + if (posts && !Array.isArray(posts)) { + return c.json({ error: 'Posts must be an array' }, 400); + } const postData = posts ? posts.map((post: Prisma.PostCreateInput) => { return { title: post.title, content: post.content || undefined }; }) : []; - const newUser = await prisma.user.create({ - data: { - name, - email, - posts: { - create: postData, - }, - }, - }); - - return c.json(newUser, 201); + try { + const newUser = await prisma.user.create({ + data: { + name, + email, + posts: { + create: postData, + }, + }, + }); + return c.json(newUser, 201); + } catch (error) { + if ( + error instanceof Prisma.PrismaClientKnownRequestError && + error.code === 'P2002' + ) { + return c.json({ error: 'Email already exists' }, 409); + } + throw error; + } });
44-63: Validate/postpayload and return 404 when author is missingLine 46 trusts the request body, so missing/invalid
title/authorEmailvalues explode as 500s. If the author email doesn’t exist, Prisma throwsP2025; currently that bubbles as 500 instead of 404. Validate inputs and catchP2025.app.post('/post', withPrisma, async (c) => { const prisma = c.get('prisma'); - const { - title, - content, - authorEmail: email, - } = await c.req.json<{ - title: string; - content: string; - authorEmail: string; - }>(); - const newPost = await prisma.post.create({ - data: { - title, - content, - author: { connect: { email } }, - }, - }); - return c.json(newPost, 201); + const body = await c.req.json<{ + title?: string; + content?: string; + authorEmail?: string; + }>(); + const { title, content, authorEmail } = body; + + if (!title || typeof title !== 'string' || !title.trim()) { + return c.json({ error: 'Title is required' }, 400); + } + if (!authorEmail || typeof authorEmail !== 'string' || !authorEmail.trim()) { + return c.json({ error: 'Author email is required' }, 400); + } + + try { + const newPost = await prisma.post.create({ + data: { + title, + content, + author: { connect: { email: authorEmail } }, + }, + }); + return c.json(newPost, 201); + } catch (error) { + if ( + error instanceof Prisma.PrismaClientKnownRequestError && + error.code === 'P2025' + ) { + return c.json({ error: 'Author not found' }, 404); + } + throw error; + } });
65-75: Return 200 for updates and narrow error handlingLine 74 sends 201 (Created) even though the endpoint only updates an existing record. Also, the bare
catchreturns 404 for every failure, masking real server errors. Return 200 on success and only translate Prisma’s “record not found” into 404.try { const post = await prisma.post.update({ where: { id }, data: { viewCount: { increment: 1 } }, }); - return c.json(post, 201); - } catch { - return c.json( - { - error: `Post with ID ${id} does not exist in the database`, - }, - 404, - ); + return c.json(post, 200); + } catch (error) { + if ( + error instanceof Prisma.PrismaClientKnownRequestError && + error.code === 'P2025' + ) { + return c.json( + { error: `Post with ID ${id} does not exist in the database` }, + 404, + ); + } + throw error; }
85-108: Use a single update with proper error handling and statusLine 107 returns 201 for an update, and the separate
findUnique+updatestill throws a 500 if the record disappears between calls. Perform oneupdateinside a try/catch, return 200, and translate Prisma’sP2025into 404.app.put('/publish/:id', withPrisma, async (c) => { const prisma = c.get('prisma'); const id = Number(c.req.param('id')); - const postToUpdate = await prisma.post.findUnique({ - where: { id }, - }); - - if (!postToUpdate) { - c.status(404); - return c.json({ - error: `Post with ID ${id} does not exist in the database`, - }); - } - - const updatedPost = await prisma.post.update({ - where: { - id, - }, - data: { - published: !postToUpdate.published, - }, - }); - return c.json(updatedPost, 201); + try { + const post = await prisma.post.update({ + where: { id }, + data: { published: { not: undefined } }, + }); + return c.json({ ...post, published: !post.published }, 200); + } catch (error) { + if ( + error instanceof Prisma.PrismaClientKnownRequestError && + error.code === 'P2025' + ) { + return c.json( + { error: `Post with ID ${id} does not exist in the database` }, + 404, + ); + } + throw error; + } });
110-129: Don’t turn every delete failure into 404The current
catchtreats any exception as “not found.” That hides real DB errors (e.g., connectivity issues) and sends clients the wrong status. Only map Prisma’sP2025“record not found” to 404 and rethrow (or 500) everything else.- try { + try { const deletedPost = await prisma.post.delete({ where: { id, }, }); return c.json(deletedPost); - } catch { - return c.json( - { - error: `Post with ID ${id} does not exist in the database`, - }, - 404, - ); + } catch (error) { + if ( + error instanceof Prisma.PrismaClientKnownRequestError && + error.code === 'P2025' + ) { + return c.json( + { error: `Post with ID ${id} does not exist in the database` }, + 404, + ); + } + throw error; }
152-160: Return 404 when a post isn’t found
findUniquereturnsnullfor missing posts, but Line 160 still answers 200 withnull, forcing clients to guess. Respond with 404 in that case.const post = await prisma.post.findUnique({ where: { id, }, }); - return c.json(post); + if (!post) { + return c.json({ error: `Post with ID ${id} not found` }, 404); + } + return c.json(post, 200);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (9)
.github/tests/orm/hono/run.sh(1 hunks)orm/hono/.env.example(1 hunks)orm/hono/README.md(1 hunks)orm/hono/package.json(1 hunks)orm/hono/prisma/schema.prisma(1 hunks)orm/hono/prisma/seed.ts(1 hunks)orm/hono/src/index.ts(1 hunks)orm/hono/src/lib/prisma.ts(1 hunks)orm/hono/tsconfig.json(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-22T12:12:43.161Z
Learnt from: FGoessler
PR: prisma/prisma-examples#8260
File: generator-prisma-client/nextjs-starter-turbopack/components/quotes.tsx:1-1
Timestamp: 2025-08-22T12:12:43.161Z
Learning: In Next.js applications using Prisma, the connection() function from 'next/server' serves a different purpose than 'export const dynamic = force-dynamic'. The connection() function ensures proper database connection context and request isolation, while dynamic = 'force-dynamic' only controls rendering strategy. Both should be used together and are not redundant.
Applied to files:
orm/hono/src/lib/prisma.ts
📚 Learning: 2025-08-22T12:12:24.602Z
Learnt from: FGoessler
PR: prisma/prisma-examples#8260
File: generator-prisma-client/nextjs-starter-webpack-turborepo/packages/database/package.json:13-13
Timestamp: 2025-08-22T12:12:24.602Z
Learning: When analyzing changes from package.json seed scripts to "prisma db seed", always verify the actual content of prisma.config.ts rather than relying solely on regex patterns, as the configuration may be properly defined but in a format that doesn't match overly restrictive search patterns.
Applied to files:
orm/hono/prisma/seed.ts
🧬 Code graph analysis (2)
orm/hono/prisma/seed.ts (2)
orm/sveltekit/prisma/seed.ts (1)
main(39-43)orm/express/prisma/seed.ts (1)
main(52-61)
orm/hono/src/index.ts (1)
orm/graphql/src/schema/post.ts (1)
PostCreateInput(18-23)
🪛 dotenv-linter (3.3.0)
orm/hono/.env.example
[warning] 2-2: [QuoteCharacter] The value has quote characters (', ")
(QuoteCharacter)
🪛 markdownlint-cli2 (0.18.1)
orm/hono/README.md
11-11: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
17-17: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
25-25: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
31-31: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
132-132: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
- GitHub Check: test (orm/betterauth-nextjs)
- GitHub Check: test (orm/graphql-sdl-first)
- GitHub Check: test (orm/express)
- GitHub Check: test (orm/ai-sdk-nextjs)
- GitHub Check: test (orm/grpc)
- GitHub Check: test (orm/authjs-nextjs)
- GitHub Check: test (orm/nest)
- GitHub Check: test (orm/nest-graphql-sdl-first)
- GitHub Check: test (orm/nest-graphql)
- GitHub Check: test (orm/nuxt)
🔇 Additional comments (2)
orm/hono/prisma/schema.prisma (1)
1-35: LGTM! Schema is well-structured.The Prisma schema is correctly configured with:
- Custom client output path for better organization
- Proper PostgreSQL datasource setup
- Standard User/Post models with appropriate relations and constraints
orm/hono/tsconfig.json (1)
1-16: LGTM! TypeScript configuration is modern and appropriate.The tsconfig properly sets up:
- ESNext/NodeNext for modern module resolution
- Strict type checking
- Hono JSX runtime integration
- Appropriate compiler options for the stack
| { | ||
| "name": "my-app", | ||
| "type": "module", | ||
| "scripts": { | ||
| "dev": "tsx watch src/index.ts", | ||
| "build": "tsc", | ||
| "start": "node dist/index.js" | ||
| }, | ||
| "prisma": { | ||
| "seed": "tsx prisma/seed.ts" | ||
| }, | ||
| "dependencies": { | ||
| "@hono/node-server": "^1.19.5", | ||
| "@prisma/client": "^6.16.3", | ||
| "@prisma/extension-accelerate": "^2.0.2", | ||
| "dotenv": "^17.2.3", | ||
| "hono": "^4.9.9" | ||
| }, | ||
| "devDependencies": { | ||
| "@types/node": "^20.11.17", | ||
| "prisma": "^6.16.3", | ||
| "tsx": "^4.20.6", | ||
| "typescript": "^5.8.3" | ||
| } | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
LGTM! Dependencies are current and properly configured.
The package configuration correctly sets up:
- ESM module type for modern JavaScript
- Appropriate build and dev scripts using tsx
- Prisma seed script integration
- Current stable versions of Hono, Prisma, and related packages
Optionally, consider updating Hono from 4.9.9 to 4.9.10 to get the latest fixes (based on learnings).
- "hono": "^4.9.9"
+ "hono": "^4.9.10"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| { | |
| "name": "my-app", | |
| "type": "module", | |
| "scripts": { | |
| "dev": "tsx watch src/index.ts", | |
| "build": "tsc", | |
| "start": "node dist/index.js" | |
| }, | |
| "prisma": { | |
| "seed": "tsx prisma/seed.ts" | |
| }, | |
| "dependencies": { | |
| "@hono/node-server": "^1.19.5", | |
| "@prisma/client": "^6.16.3", | |
| "@prisma/extension-accelerate": "^2.0.2", | |
| "dotenv": "^17.2.3", | |
| "hono": "^4.9.9" | |
| }, | |
| "devDependencies": { | |
| "@types/node": "^20.11.17", | |
| "prisma": "^6.16.3", | |
| "tsx": "^4.20.6", | |
| "typescript": "^5.8.3" | |
| } | |
| } | |
| "dependencies": { | |
| "@hono/node-server": "^1.19.5", | |
| "@prisma/client": "^6.16.3", | |
| "@prisma/extension-accelerate": "^2.0.2", | |
| "dotenv": "^17.2.3", | |
| "hono": "^4.9.10" | |
| }, |
🤖 Prompt for AI Agents
In orm/hono/package.json around lines 1 to 25, update the hono dependency from
"^4.9.9" to "^4.9.10" to pick up the latest fixes; after editing the version run
your package manager (npm/yarn/pnpm install) to update lockfile and then run
build/test/seed scripts to verify nothing broke.
Summary by CodeRabbit
New Features
Documentation
Chores
Tests