Skip to content

Conversation

bibblebabl
Copy link
Contributor

@bibblebabl bibblebabl commented Sep 17, 2025

Added a checkDatabaseHealth function to the server routes for Elysia, Express, Fastify, Hono, and Next.js templates. This enhances the root endpoint to return the database health status, improving error handling and response accuracy.

Summary by CodeRabbit

  • New Features
    • Root endpoint ("/") now returns live health status as JSON with HTTP 200 or 500 based on health, replacing the previous static "OK".
    • Adds a reusable database health check that reports connected/disconnected and optional error details; supports projects without a database.
    • Applied consistently across Elysia, Express, Fastify, Hono, and Next.js server templates to improve monitoring and readiness probes.

Added a `checkDatabaseHealth` function to the server routes for Elysia, Express, Fastify, Hono, and Next.js templates. This enhances the root endpoint to return the database health status, improving error handling and response accuracy.
Copy link
Contributor

coderabbitai bot commented Sep 17, 2025

Walkthrough

Root endpoints in multiple server templates now call a new async checkDatabaseHealth utility and return its JSON result; HTTP status is set to 500 when the health object contains an error. Two ORM-aware health-check template modules were added (server-base and Next.js).

Changes

Cohort / File(s) Summary of changes
Root health endpoint integration
apps/cli/templates/backend/server/elysia/src/index.ts.hbs, apps/cli/templates/backend/server/express/src/index.ts.hbs, apps/cli/templates/backend/server/fastify/src/index.ts.hbs, apps/cli/templates/backend/server/hono/src/index.ts.hbs, apps/cli/templates/backend/server/next/src/app/route.ts
Import checkDatabaseHealth and replace static root response with an async handler that awaits checkDatabaseHealth(), derives status (500 if health.error truthy else 200), and returns the health object as JSON/payload.
Health-check templates
apps/cli/templates/backend/server/server-base/src/lib/health.ts.hbs, apps/cli/templates/backend/server/next/src/lib/health.ts.hbs
Add checkDatabaseHealth() template implementing ORM-aware probes (drizzle/prisma/mongoose) or a no-ORM fallback. Returns `{ status: "OK", database: "connected"

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor C as Client
  participant S as Server (Elysia/Express/Fastify/Hono/Next)
  participant H as Health Module
  participant D as DB/ORM

  C->>S: GET /
  S->>H: checkDatabaseHealth()
  alt ORM configured
    H->>D: Lightweight ping (SELECT 1 / $queryRaw / admin().ping())
    D-->>H: OK / Error
    H-->>S: {status:"OK", database:"connected"|"disconnected", error?}
  else No ORM
    H-->>S: {status:"OK", database:"none"}
  end
  alt health.error truthy
    S-->>C: 500 JSON(health)
  else
    S-->>C: 200 JSON(health)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

I thump my paw and give a check,
A tiny ping across the neck.
If roots are tangled, flags I wave,
Else burrows safe and tunnels brave.
Health is known — hop on, behave! 🐇

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "integrate database health check in server" succinctly and accurately captures the primary change in the PR — adding a checkDatabaseHealth helper and wiring it into the root endpoints across server templates (Elysia, Express, Fastify, Hono, Next.js), which matches the PR objectives and file summaries.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b29192a and 8c15319.

📒 Files selected for processing (1)
  • apps/cli/templates/backend/server/elysia/src/index.ts.hbs (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{hbs,handlebars}

📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)

In Handlebars templates, avoid generic if/else blocks; write explicit conditions (e.g., if (eq orm "prisma") and else if (eq orm "drizzle")).

Files:

  • apps/cli/templates/backend/server/elysia/src/index.ts.hbs
🔇 Additional comments (2)
apps/cli/templates/backend/server/elysia/src/index.ts.hbs (2)

115-119: Root GET returns DB health and sets 500 on error — LGTM.

Handler correctly awaits the health check and sets status when health.error is truthy. This aligns with the PR objective and prior guidance.

Confirm checkDatabaseHealth() never throws and always returns a shaped object with an error field when unhealthy; otherwise consider wrapping the call in try/catch to ensure 500 is consistently returned.


28-28: Import added — confirm module presence and named export.

Verify that apps/cli/templates/backend/server/elysia/src/lib/health.ts.hbs exists and exports a named function checkDatabaseHealth used by apps/cli/templates/backend/server/elysia/src/index.ts.hbs (line 28).

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (9)
apps/cli/templates/backend/server/express/src/index.ts.hbs (1)

116-119: Prevent caching of health responses.

Add a no‑store header to avoid stale health data from proxies/CDNs.

 app.get("/", async (_req, res) => {
   const health = await checkDatabaseHealth();
   const status = health.error ? 500 : 200;
-  res.status(status).json(health);
+  res.set("Cache-Control", "no-store").status(status).json(health);
 });
apps/cli/templates/backend/server/fastify/src/index.ts.hbs (1)

173-179: Make health responses non-cacheable.

Set a Cache-Control: no-store header.

 fastify.get('/', async (request, reply) => {
   const health = await checkDatabaseHealth();
   if (health.error) {
     reply.status(500);
   }
-  return health;
+  reply.header('Cache-Control', 'no-store');
+  return health;
 });
apps/cli/templates/backend/server/hono/src/index.ts.hbs (1)

149-152: Disable caching of health responses.

Add Cache-Control: no-store to avoid stale results.

 app.get("/", async (c) => {
   const health = await checkDatabaseHealth();
   const status = health.error ? 500 : 200;
-  return c.json(health, status);
+  c.header("Cache-Control", "no-store");
+  return c.json(health, status);
 });
apps/cli/templates/backend/server/server-base/src/lib/health.ts.hbs (3)

12-12: Avoid explicit return types per guidelines.

Let TS infer the Promise type; keeps the template cleaner.

-export async function checkDatabaseHealth(): Promise<{ status: string; database: string; error?: string }> {
+export async function checkDatabaseHealth() {

27-35: Report a non-OK status on failure.

Returning status: "OK" with database: "disconnected" is misleading. Use an error status.

-    return { 
-      status: "OK", 
+    return { 
+      status: "ERROR", 
       database: "disconnected", 
       error: error instanceof Error ? error.message : String(error) 
     };

38-40: Avoid explicit return types in the no‑ORM branch.

Let inference handle it.

-export async function checkDatabaseHealth(): Promise<{ status: string; database: string }> {
+export async function checkDatabaseHealth() {
   return { status: "OK", database: "none" };
 }
apps/cli/templates/backend/server/next/src/app/route.ts (1)

2-7: Named import is correct; optionally add no-store cache header to the health response

apps/cli/templates/backend/server/next/src/lib/health.ts.hbs exports checkDatabaseHealth as a named function (lines 12 & 38), so the current named import is correct.

File: apps/cli/templates/backend/server/next/src/app/route.ts

@@
-  return NextResponse.json(health, { status });
+  return NextResponse.json(health, { status, headers: { "Cache-Control": "no-store" } });
apps/cli/templates/backend/server/next/src/lib/health.ts.hbs (2)

38-40: Unify the return type across variants for simpler consumers.

The no‑ORM branch omits error?: string, creating two shapes. Keep a consistent type (even if error is absent).

Apply this diff:

-export async function checkDatabaseHealth(): Promise<{ status: string; database: string }> {
+export async function checkDatabaseHealth(): Promise<{ status: string; database: string; error?: string }> {
   return { status: "OK", database: "none" };
 }

28-29: Consider avoiding raw error logs in production.

Use a structured logger and suppress PII. At minimum, gate verbose errors behind NODE_ENV !== "production".

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bd866b3 and b29192a.

📒 Files selected for processing (7)
  • apps/cli/templates/backend/server/elysia/src/index.ts.hbs (2 hunks)
  • apps/cli/templates/backend/server/express/src/index.ts.hbs (2 hunks)
  • apps/cli/templates/backend/server/fastify/src/index.ts.hbs (2 hunks)
  • apps/cli/templates/backend/server/hono/src/index.ts.hbs (2 hunks)
  • apps/cli/templates/backend/server/next/src/app/route.ts (1 hunks)
  • apps/cli/templates/backend/server/next/src/lib/health.ts.hbs (1 hunks)
  • apps/cli/templates/backend/server/server-base/src/lib/health.ts.hbs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/convex_rules.mdc)

**/*.{ts,tsx}: Use Id from './_generated/dataModel' to type document ids (e.g., Id<'users'>)
Ensure Record key/value types align with validators (e.g., v.record(v.id('users'), v.string()) => Record<Id<'users'>, string>)
Be strict with types for document ids; prefer Id<'table'> over string
Use 'as const' for string literals in discriminated unions
When using Array and Record types, declare with explicit generic types (e.g., const arr: Array = ...)

**/*.{ts,tsx}: Use TypeScript type aliases instead of interface declarations.
Do not use explicit return types in TypeScript.

Files:

  • apps/cli/templates/backend/server/next/src/app/route.ts
**/*.{js,jsx,ts,tsx,mjs,cjs}

📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)

**/*.{js,jsx,ts,tsx,mjs,cjs}: Do not use dotenv; Bun auto-loads .env
Use Bun.serve() for HTTP/WebSockets; do not use express
Use bun:sqlite for SQLite; do not use better-sqlite3
Use Bun.redis for Redis; do not use ioredis
Use Bun.sql for Postgres; do not use pg or postgres.js
Use built-in WebSocket; do not use ws
Prefer Bun.file over node:fs readFile/writeFile
Use Bun.$ instead of execa for shelling out

Files:

  • apps/cli/templates/backend/server/next/src/app/route.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)

Define functions using the standard function declaration syntax, not arrow functions.

Files:

  • apps/cli/templates/backend/server/next/src/app/route.ts
**/*.{hbs,handlebars}

📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)

In Handlebars templates, avoid generic if/else blocks; write explicit conditions (e.g., if (eq orm "prisma") and else if (eq orm "drizzle")).

Files:

  • apps/cli/templates/backend/server/elysia/src/index.ts.hbs
  • apps/cli/templates/backend/server/express/src/index.ts.hbs
  • apps/cli/templates/backend/server/server-base/src/lib/health.ts.hbs
  • apps/cli/templates/backend/server/next/src/lib/health.ts.hbs
  • apps/cli/templates/backend/server/fastify/src/index.ts.hbs
  • apps/cli/templates/backend/server/hono/src/index.ts.hbs
🔇 Additional comments (9)
apps/cli/templates/backend/server/express/src/index.ts.hbs (1)

28-28: LGTM on importing the health helper.

apps/cli/templates/backend/server/fastify/src/index.ts.hbs (1)

33-33: LGTM on importing the health helper.

apps/cli/templates/backend/server/hono/src/index.ts.hbs (1)

24-24: LGTM on importing the health helper.

apps/cli/templates/backend/server/elysia/src/index.ts.hbs (1)

28-28: Add/generate ./lib/health export for Elysia (checkDatabaseHealth)

apps/cli/templates/backend/server/elysia/src/index.ts.hbs imports the named export checkDatabaseHealth from "./lib/health" (line 28) but there is no elysia src/lib/health.ts.hbs; implementations exist at apps/cli/templates/backend/server/next/src/lib/health.ts.hbs and apps/cli/templates/backend/server/server-base/src/lib/health.ts.hbs — add a lib/health that exports checkDatabaseHealth or update the import to match.

apps/cli/templates/backend/server/server-base/src/lib/health.ts.hbs (2)

15-21: Confirm Drizzle dialect methods; prefer sql-tagged queries.

Could not locate the Drizzle db factory in the repo — manually verify whether the sqlite client exposes db.get. If it does not, apply the change below.

-    {{#if (eq database "sqlite")}}
-    await db.get("SELECT 1");
+    {{#if (eq database "sqlite")}}
+    await db.execute(sql`SELECT 1`);
 {{#if (eq orm "drizzle")}}
 import { db } from "../db";
+import { sql } from "drizzle-orm";
 {{/if}}

24-26: Validate the Mongo/Mongoose ping path.

health.ts.hbs (server-base & next) imports { client } from "../db" and calls await client.admin().ping() — that matches the native MongoClient API. Mongoose health checks should use mongoose.connection.db.admin().ping() or mongoose.connection.db.command({ ping: 1 }), unless ../db actually exports a MongoClient instance named client. I couldn't locate the ../db export in the templates; confirm what the Mongoose template exports. Then either (a) update the health check to use mongoose.connection.db... or (b) have ../db export a MongoClient client so client.admin().ping() is valid.

apps/cli/templates/backend/server/next/src/lib/health.ts.hbs (3)

27-35: Return a non-OK status on DB check failure.

Returning { status: "OK", database: "disconnected" } misleads downstream health handlers. Use "ERROR" (or "DEGRADED" if you prefer) when the ping fails.

[ suggest_recommended_refactor ]

Apply this diff:

-    return { 
-      status: "OK", 
-      database: "disconnected", 
-      error: error instanceof Error ? error.message : String(error) 
-    };
+    return {
+      status: "ERROR",
+      database: "disconnected",
+      error: error instanceof Error ? error.message : String(error)
+    };

25-25: Verify what client is in the Mongoose template.

File: apps/cli/templates/backend/server/next/src/lib/health.ts.hbs (around line 25) currently uses:

await client.admin().ping();

If client is a MongoDB MongoClient, use:

  • await client.db().command({ ping: 1 }) (or await client.db().admin().ping()).

If client is a Mongoose connection, use:

  • await mongoose.connection.db.command({ ping: 1 }) (or await mongoose.connection.db.admin().ping()).

Repository search returned no results for the DB template export — confirm which object client refers to (or paste the DB template/export) so this can be verified.


15-21: ```shell
#!/bin/bash
set -euo pipefail

echo "PWD: $(pwd)"
echo "---- find health.ts.hbs ----"
rg -n --hidden -S 'health.ts.hbs' || true

TEMPLATE="apps/cli/templates/backend/server/next/src/lib/health.ts.hbs"
if [ -f "$TEMPLATE" ]; then
echo "---- $TEMPLATE ----"
sed -n '1,240p' "$TEMPLATE"
else
echo "$TEMPLATE not found; searching for any health..hbs under apps/cli..."
rg -n --hidden -S 'health.
.hbs' apps/cli || true
fi

echo
echo "---- occurrences of 'database' in apps/cli ----"
rg -n --hidden -S --glob 'apps/cli/**' '\bdatabase\b' -C2 || true

echo
echo "---- occurrences of sqlite/postgres/mysql/postgresql/libsql in apps/cli ----"
rg -n --hidden -S --glob 'apps/cli/**' 'sqlite|postgresql|postgres|mysql|libsql' -C2 || true

echo
echo "---- ProjectConfig / type definitions in apps/cli ----"
rg -n --hidden -S --glob 'apps/cli/**' 'type ProjectConfig|interface ProjectConfig|export type ProjectConfig' -C3 || true

echo
echo "---- templates using 'eq database' ----"
rg -n --hidden -S --glob 'apps/cli/templates/**' 'eq database' -C2 || true

echo
echo "---- templates referencing drizzle/sql/db.get/db.execute ----"
rg -n --hidden -S --glob 'apps/cli/templates/**' 'drizzle|drizzle-orm|sql`|db.get|db.execute' -C2 || true

echo
echo "---- done ----"


</blockquote></details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment on lines +1 to +2
{{#if orm}}
{{#if (eq orm "drizzle")}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Replace the top-level generic Handlebars if with explicit eq branches to avoid false “connected” on unknown ORMs.

As written, any truthy orm value enters the main branch; if it’s an unsupported value, none of the inner checks run, yet the function still returns { status: "OK", database: "connected" }. Also, coding guidelines discourage generic if/else in templates.

Refactor to an explicit eq chain and unify the function/type shape across variants.

Apply this diff:

-{{#if orm}}
-{{#if (eq orm "drizzle")}}
-import { db } from "../../db";
-{{/if}}
-{{#if (eq orm "prisma")}}
-import prisma from "../../db";
-{{/if}}
-{{#if (eq orm "mongoose")}}
-import { client } from "../../db";
-{{/if}}
-
-export async function checkDatabaseHealth(): Promise<{ status: string; database: string; error?: string }> {
-  try {
-    {{#if (eq orm "drizzle")}}
-    {{#if (eq database "sqlite")}}
-    await db.get("SELECT 1");
-    {{else if (eq database "postgres")}}
-    await db.execute("SELECT 1");
-    {{else if (eq database "mysql")}}
-    await db.execute("SELECT 1");
-    {{/if}}
-    {{else if (eq orm "prisma")}}
-    await prisma.$queryRaw`SELECT 1`;
-    {{else if (eq orm "mongoose")}}
-    await client.admin().ping();
-    {{/if}}
-    return { status: "OK", database: "connected" };
-  } catch (error) {
-    console.error("Database connection error:", error);
-    return { 
-      status: "OK", 
-      database: "disconnected", 
-      error: error instanceof Error ? error.message : String(error) 
-    };
-  }
-}
-{{else}}
-export async function checkDatabaseHealth(): Promise<{ status: string; database: string }> {
-  return { status: "OK", database: "none" };
-}
-{{/if}}
+{{!-- Keep a consistent shape across all variants --}}
+type Health = {
+  status: "OK" | "ERROR";
+  database: "connected" | "disconnected" | "none";
+  error?: string;
+};
+
+{{#if (eq orm "drizzle")}}
+import { db } from "../../db";
+import { sql } from "drizzle-orm";
+
+export async function checkDatabaseHealth(): Promise<Health> {
+  try {
+    {{#if (eq database "sqlite")}}
+    await db.get(sql`SELECT 1`);
+    {{else if (eq database "postgres")}}
+    await db.execute(sql`SELECT 1`);
+    {{else if (eq database "mysql")}}
+    await db.execute(sql`SELECT 1`);
+    {{/if}}
+    return { status: "OK", database: "connected" };
+  } catch (error) {
+    console.error("Database connection error:", error);
+    return {
+      status: "ERROR",
+      database: "disconnected",
+      error: error instanceof Error ? error.message : String(error),
+    };
+  }
+}
+{{else if (eq orm "prisma")}}
+import prisma from "../../db";
+
+export async function checkDatabaseHealth(): Promise<Health> {
+  try {
+    await prisma.$queryRaw`SELECT 1`;
+    return { status: "OK", database: "connected" };
+  } catch (error) {
+    console.error("Database connection error:", error);
+    return {
+      status: "ERROR",
+      database: "disconnected",
+      error: error instanceof Error ? error.message : String(error),
+    };
+  }
+}
+{{else if (eq orm "mongoose")}}
+import { client } from "../../db";
+
+export async function checkDatabaseHealth(): Promise<Health> {
+  try {
+    await client.admin().ping();
+    return { status: "OK", database: "connected" };
+  } catch (error) {
+    console.error("Database connection error:", error);
+    return {
+      status: "ERROR",
+      database: "disconnected",
+      error: error instanceof Error ? error.message : String(error),
+    };
+  }
+}
+{{else}}
+export async function checkDatabaseHealth(): Promise<Health> {
+  return { status: "OK", database: "none" };
+}
+{{/if}}

Also applies to: 37-41

🤖 Prompt for AI Agents
In apps/cli/templates/backend/server/next/src/lib/health.ts.hbs around lines 1-2
and 37-41, the template uses a top-level generic Handlebars {{#if orm}} which
allows any truthy orm value (including unsupported ones) to enter the branch and
produce a misleading `{ status: "OK", database: "connected" }`; replace the
generic if with explicit equality branches (e.g., {{#if (eq orm "drizzle")}}
{{else if (eq orm "prisma")}} ... {{else}}) so each supported ORM has its own
branch and the fallback returns a consistent shape indicating unknown/disabled
DB, and ensure the exported function/type shape is unified across all branches
(same return object keys) to avoid mismatches.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant