From 72d47da4539084141d837bd453cb5eb172112f8c Mon Sep 17 00:00:00 2001 From: luciano Date: Wed, 29 Apr 2026 12:38:04 +0200 Subject: [PATCH] feat(api): integrate Prisma client with /db/health endpoint - Add @ketopath/db and fastify-plugin to apps/api - prismaPlugin decorates the Fastify instance with prisma and disconnects on app close, with FastifyInstance type augmented in src/types/fastify.d.ts - DATABASE_URL is now required by env validation - New module modules/db with GET /db/health running SELECT 1 via Prisma - dev script switched to tsx --env-file=.env for env loading Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/api/.env.example | 3 +-- apps/api/package.json | 4 +++- apps/api/src/app.ts | 4 ++++ apps/api/src/config/env.ts | 1 + apps/api/src/modules/db/db.routes.ts | 13 +++++++++++++ apps/api/src/plugins/prisma.ts | 11 +++++++++++ apps/api/src/types/fastify.d.ts | 7 +++++++ pnpm-lock.yaml | Bin 203185 -> 203349 bytes 8 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 apps/api/src/modules/db/db.routes.ts create mode 100644 apps/api/src/plugins/prisma.ts create mode 100644 apps/api/src/types/fastify.d.ts diff --git a/apps/api/.env.example b/apps/api/.env.example index 8789db7..5e4cc4a 100644 --- a/apps/api/.env.example +++ b/apps/api/.env.example @@ -6,5 +6,4 @@ LOG_LEVEL=info # CORS — origini consentite (separate da virgola) CORS_ORIGINS=http://localhost:3000 -# Database (configurato in step successivo con Prisma) -# DATABASE_URL=postgresql://user:password@localhost:5432/ketopath +DATABASE_URL=postgresql://luciano:luciano%40@localhost:5432/ketopath?schema=public diff --git a/apps/api/package.json b/apps/api/package.json index fb34133..acb69d1 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "scripts": { - "dev": "tsx watch src/server.ts", + "dev": "tsx watch --env-file=.env src/server.ts", "build": "tsc", "start": "node dist/server.js", "typecheck": "tsc --noEmit", @@ -15,8 +15,10 @@ "@fastify/helmet": "^11.1.1", "@fastify/rate-limit": "^9.1.0", "@fastify/sensible": "^5.6.0", + "@ketopath/db": "workspace:*", "@ketopath/shared": "workspace:*", "fastify": "^4.28.1", + "fastify-plugin": "^4.5.1", "zod": "^3.23.8" }, "devDependencies": { diff --git a/apps/api/src/app.ts b/apps/api/src/app.ts index 61dd6f5..adbea94 100644 --- a/apps/api/src/app.ts +++ b/apps/api/src/app.ts @@ -5,7 +5,9 @@ import sensible from '@fastify/sensible'; import Fastify, { type FastifyInstance } from 'fastify'; import { env } from './config/env.js'; +import { dbRoutes } from './modules/db/db.routes.js'; import { healthRoutes } from './modules/health/health.routes.js'; +import { prismaPlugin } from './plugins/prisma.js'; export async function buildApp(): Promise { const app = Fastify({ @@ -33,8 +35,10 @@ export async function buildApp(): Promise { timeWindow: '1 minute', }); await app.register(sensible); + await app.register(prismaPlugin); await app.register(healthRoutes); + await app.register(dbRoutes); return app; } diff --git a/apps/api/src/config/env.ts b/apps/api/src/config/env.ts index f496234..7abd932 100644 --- a/apps/api/src/config/env.ts +++ b/apps/api/src/config/env.ts @@ -14,6 +14,7 @@ const envSchema = z.object({ .map((origin) => origin.trim()) .filter(Boolean), ), + DATABASE_URL: z.string().url(), }); export type Env = z.infer; diff --git a/apps/api/src/modules/db/db.routes.ts b/apps/api/src/modules/db/db.routes.ts new file mode 100644 index 0000000..12b33ca --- /dev/null +++ b/apps/api/src/modules/db/db.routes.ts @@ -0,0 +1,13 @@ +import type { FastifyPluginAsync } from 'fastify'; + +export const dbRoutes: FastifyPluginAsync = async (fastify) => { + fastify.get('/db/health', async (_request, reply) => { + try { + await fastify.prisma.$queryRaw`SELECT 1`; + return { status: 'ok', database: 'reachable' }; + } catch (err) { + fastify.log.error({ err }, 'database health check failed'); + return reply.code(503).send({ status: 'error', database: 'unreachable' }); + } + }); +}; diff --git a/apps/api/src/plugins/prisma.ts b/apps/api/src/plugins/prisma.ts new file mode 100644 index 0000000..fb0c190 --- /dev/null +++ b/apps/api/src/plugins/prisma.ts @@ -0,0 +1,11 @@ +import { prisma } from '@ketopath/db'; +import fp from 'fastify-plugin'; + +export const prismaPlugin = fp(async (app) => { + await prisma.$connect(); + app.decorate('prisma', prisma); + + app.addHook('onClose', async () => { + await prisma.$disconnect(); + }); +}); diff --git a/apps/api/src/types/fastify.d.ts b/apps/api/src/types/fastify.d.ts new file mode 100644 index 0000000..85efb5a --- /dev/null +++ b/apps/api/src/types/fastify.d.ts @@ -0,0 +1,7 @@ +import type { prisma } from '@ketopath/db'; + +declare module 'fastify' { + interface FastifyInstance { + prisma: typeof prisma; + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6046057d4e6ac44bdf1f8ca3c353d306e313aba2..116cec01f65d803271025f45024f0bb3a85d4202 100644 GIT binary patch delta 65 zcmdnEndj;jo()XwOesl|4+>jP&g9|&F+Z@ao4!MyiGQ*Yizu^+p6TR|tRf(~c`AGR QRCY!nX4*cLomoZ*0OJ4@Q~&?~ delta 30 kcmcb*g=gbto()XwljGUvG&^y$J8>`qG1GP@4rXB?0IOOE?*IS*