Pengantar Integrasi Nuxt 3 dan Prisma

Nuxt 3 dengan Nitro menawarkan platform fullstack modern, tetapi keberhasilan integrasi database bergantung pada pola akses yang terstruktur. Prisma menjadi pilihan ORM yang efisien untuk PostgreSQL karena tipe aman dan migrasi declarative. Tujuan artikel ini adalah menyajikan panduan langkah demi langkah: mulai setup awal, definisi schema, migrasi, hingga membuat endpoint CRUD yang aman serta mempertimbangkan deployment serverless dan connection pooling.

Panduan ini ditujukan untuk engineer yang ingin mempertahankan layer API dan data secara terpisah, memastikan query hanya dieksekusi di server, serta menjaga database tetap performa tinggi dalam production environment.

1. Menyiapkan Proyek Nuxt 3 dengan Nitro dan PostgreSQL

1.1 Inisialisasi proyek

Mulai dari folder kosong, jalankan perintah berikut:

npx nuxi init webapp
cd webapp
npm install

Folder default Nuxt akan menyertakan nuxt.config. Pastikan mode server (Nitro) diaktifkan, karena Prisma harus berjalan di server-side.

1.2 Menyiapkan PostgreSQL dan Prisma

Gunakan database PostgreSQL lokal atau layanan cloud. Setelah tersedia, simpan URL connection di .env:

DATABASE_URL="postgresql://user:password@localhost:5432/appdb?schema=public"

Pasang Prisma dan klien:

npm install prisma @prisma/client

Inisialisasi Prisma:

npx prisma init --datasource-provider postgresql

File prisma/schema.prisma dibuat otomatis, siap diisi schema data.

2. Mendefinisikan Schema dan Migrasi

2.1 Struktur schema

Contoh schema sederhana untuk entitas Article:

model Article {
  id        Int      @id @default(autoincrement())
  title     String
  body      String
  status    String   @default("draft")
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

Prisma mendukung tipe data Postgres seperti Json, Decimal, dan dukungan relasi. Pastikan nama model mencerminkan domain.

2.2 Migrasi ke database

Jalankan migrasi:

npx prisma migrate dev --name init

Perintah akan menciptakan folder prisma/migrations dan memperbarui schema. Gunakan prisma db push hanya untuk prototyping jika tidak butuh history.

3. Pola Layer API dan Akses Data

3.1 Struktur folder

Untuk menjaga pemisahan, buat struktur seperti:

  • /server/api untuk endpoint Nitro.
  • /server/db untuk inisialisasi Prisma dan fungsi akses.
  • /server/validators untuk validasi input.

Contoh file server/db/client.ts:

import { PrismaClient } from '@prisma/client'

let prisma: PrismaClient

if (process.env.NODE_ENV === 'production') {
  prisma = new PrismaClient()
} else {
  globalThis.prisma ??= new PrismaClient()
  prisma = globalThis.prisma
}

export default prisma

Pattern ini memastikan satu instance Prisma di dev server dan mencegah kesalahan instansiasi berulang.

3.2 Endpoint CRUD di Nitro

Buat endpoint server/api/articles.ts:

import prisma from '~/server/db/client'
import { defineEventHandler, getQuery, readBody } from 'h3'
import { validateArticleInput } from '~/server/validators/article'

export default defineEventHandler(async (event) => {
  const method = event.req.method
  if (method === 'GET') {
    const articles = await prisma.article.findMany({ orderBy: { createdAt: 'desc' } })
    return articles
  }

  if (method === 'POST') {
    const body = await readBody(event)
    validateArticleInput(body)
    return await prisma.article.create({ data: body })
  }

  event.res.statusCode = 405
  return { message: 'Method not allowed' }
})

Kombinasi defineEventHandler dan h3 memungkinkan pengelolaan HTTP secara manual dan mencegah data client mengakses Prisma secara langsung.

3.3 Layer validasi input

Letakkan logika validasi terpisah, misalnya:

export function validateArticleInput(body: Record) {
  if (!body.title || typeof body.title !== 'string') {
    throw createError({ statusCode: 422, statusMessage: 'Title wajib diisi' })
  }
  if (!body.body || body.body.length < 20) {
    throw createError({ statusCode: 422, statusMessage: 'Isi minimal 20 karakter' })
  }
}

Dengan validator, kita menjaga konsistensi sebelum query menembus database.

4. Connection Pooling dan Serverless Considerations

4.1 Koneksi aman dari Nitro

Nuxt Nitro memanggil Prisma hanya di sisi server. Pastikan file server/api tidak di-import langsung ke client. Use defineEventHandler agar Prisma hanya dijalankan saat event request diproses.

4.2 Connection pooling untuk PostgreSQL

Di lingkungan production, terutama serverless (Vercel, Netlify), Prisma dapat memicu terlalu banyak koneksi. Gunakan PgBouncer atau Neon Connection Pooling. Contoh konfigurasi:

  • Set environment:
    DATABASE_URL="postgresql://user:password@pool-host:5432/db"
  • Atur connection_limit rendah (10-20) tergantung worker.

Alternatif lain, gunakan PLANETSCALE style pooling (walau Postgres). Prisma sendiri tidak mengelola pool di serverless, jadi pilih layer pooling eksternal atau middleware Nitro yang menjaga PrismaClient global.

4.3 Praktik aman terhadap ekspos query

Hindari menaruh Prisma di /composables atau API yang bisa diimpor client. Semua pemanggilan Prisma harus berada di server. Untuk UI, panggil endpoint Nitro dengan fetch.

Gunakan middleware atau plugin Nitro untuk mengecek autentikasi sebelum mengakses Prisma, memastikan user hanya melihat data yang diizinkan.

5. Testing dan Debugging

5.1 Auto reload dan debugging Prisma

Set environment variable DEBUG='prisma:client' saat debugging. Pastikan mock data di venv test, dan gunakan prisma db push --preview-feature untuk snapshot state.

5.2 Common mistakes

  • Lupa menambah validator menyebabkan runtime error saat schema berubah.
  • Miss match antara schema Prisma dan actual migration (jalankan npx prisma db push --preview-feature untuk sinkron).
  • Menempatkan Prisma di folder client – menyebabkan error karena Nitro tidak dapat bundling server-specific module.

6. Deployment dan Monitoring

Setelah siap, deploy Nuxt via hosting dengan dukungan Node/Nitro. Pastikan variabel DATABASE_URL aman disimpan di Secrets manager. Gunakan monitoring seperti pg_stat_activity untuk memastikan pooling bekerja.

Untuk rollout, gunakan migration lint dan backup database sebelum migrasi besar. Selalu jalankan npx prisma migrate deploy di lingkungan production.

Kesimpulan

Integrasi Nuxt 3, Nitro, Prisma, dan PostgreSQL dapat dilakukan secara sistematis dengan pemisahan layer API dan access layer, validasi input, serta perhatian pada connection pooling. Pastikan Prisma hanya berjalan di server, gunakan pooling untuk menghindari koneksi berlebih, dan pertahankan praktik aman agar query database tidak terbuka ke client. Dengan pola ini, Anda mendapatkan backend solid yang siap untuk kebutuhan produksi.