Topics

Conectar a una base de datos con Supabase×Prisma (¡Y también usaremos Gemini CLI!)

  • column

Shou y Hashi, entre otros, están desarrollando algo interesante usando Supabase. A diferencia del desarrollo tradicional en cascada, se oye hablar de definir los requisitos funcionales a partir de la interfaz de usuario, y yo tampoco me quiero quedar atrás.

Así que, en esta ocasión, he creado una aplicación sencilla de notas y voy a documentar, a modo de recordatorio, los pasos para conectar Supabase y Prisma y guardar datos en la base de datos. ¡También usaremos Gemini CLI!

Entorno: Next.js

No usaremos Auth, Realtime ni RLS de Supabase, sino que accederemos a las funciones de base de datos a través de la API, por lo que elegimos Prisma. Como permite tratar las tablas de la base de datos como objetos de JavaScript o TypeScript, creemos que resulta una forma de escribir código familiar para los ingenieros de frontend.

Prisma

Prisma ORM es una biblioteca ORM (Object-Relational Mapping) que puede utilizarse con TypeScript y JavaScript.

Dicho de forma sencilla, es una herramienta que permite operar con la base de datos mediante métodos definidos en objetos del lenguaje de programación, sin necesidad de escribir SQL.

Además, Prisma genera automáticamente tipos a partir del esquema de la base de datos, así que si intentas manipular una columna inexistente o datos de un tipo distinto, ¡te darás cuenta gracias a un error de compilación!

Supabase

Supabase es un servicio de backend full-stack que está ganando atención como alternativa de código abierto a Firebase.

  • Alta escalabilidad y fiabilidad, basadas en una base de datos PostgreSQL
  • Notificación automática de cambios en los datos mediante la función de base de datos en tiempo real
  • Compatibilidad con diversos métodos de autenticación (correo electrónico/contraseña, inicio de sesión con redes sociales, autenticación por teléfono, entre otros)
  • Gestión eficiente de archivos de gran tamaño mediante la función de almacenamiento de archivos
  • Desarrollo rápido gracias a la generación automática de APIs RESTful y APIs GraphQL
  • Amplia oferta de herramientas y SDKs para desarrolladores, con configuración e implementación sencillas

Como queremos dar prioridad a los pasos de integración con Supabase, dejaremos que Gemini CLI cree la parte visual. Es increíblemente útil. ¡Menos mal que la empresa usa Google Workspace!

Quiero crear una función de notas con Supabase y Prisma. Por ahora, por favor, crea el archivo page.tsx.

Vale, entonces, quiero que al pulsar el botón Save Memo, el contenido introducido en el textarea se añada como una lista en Your Memos.

El aspecto se ve bien así. El contenido que introduces ahora se añade a la lista de abajo. Sin embargo, como solo se maneja con JavaScript, al recargar la página la lista desaparecerá.

Para conservar el contenido introducido, utilizaremos una base de datos.

Primero, crea un nuevo proyecto en Supabase.

Crea el proyecto desde el botón "New Project". Anota la Database password, ya que será necesaria para conectar Prisma a la base de datos.

A continuación, integra Prisma.

npm install prisma --save-dev

npx prisma init

Al ejecutar estos comandos, se instalará Prisma y aparecerá la carpeta prisma.

En el archivo .env, reemplaza DATABASE_URL por la URL de conexión de Supabase. En [YOUR-PASSWORD], introduce la Database password que configuraste anteriormente en Supabase.

DATABASE_URL="postgresql://postgres.odoaingwnxkhkeujwhtp:[YOUR-PASSWORD]@aws-1-ap-northeast-1.pooler.supabase.com:5432/postgres"

Después, escribe el esquema (la definición de la estructura de la base de datos) en /prisma/schema.prisma.

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model Memo {
  id        Int      @id @default(autoincrement())
  content   String
  createdAt DateTime @default(now())
}

El nombre de model ○○ puede elegirse libremente.

Una vez escrito el esquema, ejecuta la migración.

npx prisma migrate dev --name init

Se generará el archivo migration.sql y se creará la tabla de datos en Supabase.

Creación de una API para conectar con Supabase

Se creará una API de conexión para guardar en Supabase los valores introducidos.

Instala Prisma Client en el proyecto.

npm install @prisma/client

Conexión con Supabase

/libs/prisma.ts

import { PrismaClient } from "@prisma/client"; 

const Prisma = new PrismaClient(); //インスタンス化

export const main = async () => {
  try {
    await Prisma.$connect();
  } catch (error) {
    return Error("DB接続に失敗しました");
  }
};

API

/api/memos/route.ts

import { NextResponse } from "next/server";
import { prisma } from '@/lib/prisma';

export const GET = async (req: Request, res: NextResponse) => {
  try {
    await main();             
    const memos = await Prisma.memo.findMany(); 
    return NextResponse.json(memos);
  } catch (error) {
    return NextResponse.json("エラーが発生しました");
  } finally {  
    await Prisma.$disconnect();
  }
};

export const POST = async (req: Request, res: NextResponse) => {
  const { content } = await req.json(); 
  try {
    await main();
    const memos = await Prisma.memo.**create**({
      data: {
        content: content,
      },
    });
    return NextResponse.json(memos);
  } catch (error) {
    return NextResponse.json("エラーが発生しました");
  } finally {
    await Prisma.$disconnect();
  }
};

La función GET es una API que obtiene todos los registros de la base de datos. El método findMany() recupera todos los registros que coinciden con la condición. En Prisma.memo.findMany(), "memo" es el nombre del esquema.

La función POST es una API que añade registros a la base de datos, y se crean con create().

También hay otros métodos para eliminar o actualizar datos. Aunque no sepas escribir sentencias SQL, puedes manejarlos de forma similar a JavaScript.

Con esto, la preparación básica ya está lista.

Ahora solo tienes que trasladar la API que escribiste antes a page.tsx e integrarla.

'use client';

import React, { useState, useEffect } from 'react';

interface Memo {
  id: number;
  content: string;
  createdAt: string;
}

export default function MemoApp() {
  const [memos, setMemos] = useState<Memo[]>([]);
  const [newMemo, setNewMemo] = useState('');

  const fetchMemos = async () => {
    const response = await fetch('/api/memos');
    const data = await response.json();
    setMemos(data);
  };

  useEffect(() => {
    fetchMemos();
  }, []);

  const handleSaveMemo = async (e: React.FormEvent) => {
    e.preventDefault();
    if (newMemo.trim() !== '') {
      await fetch('/api/memos', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ content: newMemo }),
      });
      setNewMemo('');
      fetchMemos();
    }
  };

  return (
    <div className="bg-white min-h-screen">
      <div className="max-w-2xl mx-auto px-4 py-16">
        <header className="text-center mb-12">
          <h1 className="text-5xl font-extrabold text-gray-900">Memo</h1>
        </header>

        <main>
          <div className="mb-12">
            <form onSubmit={handleSaveMemo}>
              <textarea
                className="w-full p-4 text-gray-800 bg-gray-100 rounded-lg border-2 border-gray-200 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:border-transparent transition"
                placeholder="Create a new memo..."
                rows={3}
                value={newMemo}
                onChange={(e) => setNewMemo(e.target.value)}
              ></textarea>
              <div className="flex justify-end mt-4">
                <button
                  type="submit"
                  className="px-6 py-2 bg-gray-800 text-white font-semibold rounded-lg hover:bg-gray-900 transition"
                >
                  Save Memo
                </button>
              </div>
            </form>
          </div>

          <section>
            <h2 className="text-3xl font-bold text-gray-800 mb-6">Your Memos</h2>
            <div className="space-y-4">
              {memos.length > 0 ? (
                memos.map((memo) => (
                  <div key={memo.id} className="bg-gray-50 p-6 rounded-lg shadow-sm">
                    <p className="text-gray-700">{memo.content}</p>
                  </div>
                ))
              ) : (
                <div className="text-center text-gray-500">
                  <p>No memos yet. Add one above!</p>
                </div>
              )}
            </div>
          </section>
        </main>
      </div>
    </div>
  );
}

¡Se guarda en Supabase!

Esta vez nos apoyamos en Gemini para crear la base a grandes rasgos, pero si usamos una base de datos para guardar valores, se amplía también el abanico de funciones y aplicaciones que podemos crear.

Al principio pensaba que el backend parecía algo difícil, pero con una herramienta GUI puedo gestionar la base de datos de forma clara, y la barrera para conectarla se ha reducido mucho.

¡Genial!

Autor de este artículo

Me dedico principalmente al maquetado y al desarrollo frontend con JavaScript, React y Next.js. Me alegra mucho cuando los sitios en los que participo se publican con éxito. Mi afición es tocar la guitarra. Me gustan los gatos y las batatas asadas 🐱🍠

Hirocchi

Ingeniero/a de frontend / Se unió en 2022

Ver los artículos de este miembro del equipo

Equipo de confianza y una respuesta ágil son nuestras fortalezas

En Liberogic, nuestro personal veterano impulsa los proyectos de forma proactiva, por lo que nuestros clientes nos valoran muy positivamente.
Nos esforzamos por asignar de manera adecuada a un gestor de proyectos y a un director, para que el proyecto avance sin contratiempos en su conjunto. Nuestro estilo consiste en distribuir los recursos de forma adecuada a cada tarea, evitando el aumento de costes por dedicaciones completas innecesarias. También somos reconocidos por la rapidez con la que comprendemos el alcance del trabajo y preparamos y presentamos los presupuestos.

Nota: Ten en cuenta que Liberogic no se dedica activamente a los servicios de desarrollo en las instalaciones del cliente (tipo SES).

Puede utilizar prácticamente todas las principales herramientas de gestión de proyectos y de chat, como Slack, Teams, Redmine, Backlog, Asana, Jira, Notion, Google Workspace, Zoom, Webex y más.

En proyectos de gran escala que utilizan SES o externalización offshore, ¿tiene dudas sobre los desafíos técnicos o el enfoque de trabajo?

Casos de Estudio