Topics

Supabase × Prisma: Verbindung zur Datenbank herstellen (mit Gemini CLI, na klar!)

  • column

Shō und Hasshie und andere nutzen Supabase für allerlei spannende Entwicklungsprojekte. Anders als bei der klassischen Wasserfall-Entwicklung hört man dabei von der UI bis zur Definition der Funktionsanforderungen allerlei. Da will ich mich natürlich nicht lumpen lassen!

Deshalb fasse ich in diesem Beitrag als Gedächtnisstütze zusammen, wie man eine einfache Notiz-App erstellt und Supabase mit Prisma verbindet, um Daten in der Datenbank zu speichern. Gemini CLI kommt natürlich auch zum Einsatz!

Umgebung: Next.js

Da wir Auth, Realtime und RLS von Supabase nicht verwenden und die Datenbankfunktionen über die API nutzen, setzen wir auf Prisma. Tabellen lassen sich damit wie JavaScript- bzw. TypeScript-Objekte behandeln, was für Frontend-Engineers vermutlich vertraut wirkt.

Prisma

Prisma ORM ist eine ORM-Bibliothek (Object-Relational Mapping), die in TypeScript und JavaScript verwendet werden kann.

Vereinfacht gesagt handelt es sich um ein Werkzeug, mit dem sich Datenbankoperationen über Methoden in der Programmiersprache durchführen lassen, ganz ohne SQL zu schreiben.

Außerdem generiert Prisma aus dem Datenbankschema automatisch Typen. Versucht man daher, auf eine nicht vorhandene Spalte oder auf Daten mit falschem Typ zuzugreifen, fällt dies bereits beim Kompilieren als Fehler auf!

Supabase

Supabase ist ein Full-Stack-Backend-Service, der als Open-Source-Alternative zu Firebase zunehmend Beachtung findet.

  • Hohe Skalierbarkeit und Zuverlässigkeit auf Basis einer PostgreSQL-Datenbank
  • Automatische Benachrichtigungen bei Datenänderungen über die Echtzeit-Datenbankfunktion
  • Unterstützt vielfältige Authentifizierungsmethoden (E-Mail/Passwort, Social Login, Telefonverifizierung usw.)
  • Effiziente Verwaltung großer Dateien mit der Dateispeicherfunktion
  • Schnelle Entwicklung durch die automatische Generierung einer RESTful API und einer GraphQL API
  • Umfangreiche Entwicklerwerkzeuge und SDKs stehen zur Verfügung, wodurch Einrichtung und Einführung einfach sind

Da mir die Anbindung an Supabase besonders wichtig ist, lasse ich die Optik mit Gemini CLI erstellen. Das ist ein unglaublich praktisches Werkzeug! Gut, dass unser Unternehmen Google Workspace nutzt!

Ich möchte eine Notizfunktion mit Supabase und Prisma erstellen. Erstelle bitte zunächst eine page.tsx.

Okay, dann bau bitte so, dass der Inhalt aus dem Textarea beim Klick auf den Save-Memo-Button als Liste unter Your Memos hinzugefügt wird.

So sieht das Ganze optisch aus. Die eingegebenen Inhalte werden nun in der Liste unten hinzugefügt. Da dies lediglich über JavaScript-Ereignisse umgesetzt ist, verschwindet die Liste beim Neuladen der Seite.

Um die eingegebenen Inhalte dauerhaft zu speichern, verwenden wir eine Datenbank!

Zuerst erstellen wir ein neues Projekt in Supabase.

Erstellen Sie es über die Schaltfläche "New Project". Bewahren Sie das Database password gut auf, da es beim Verbinden mit Prisma benötigt wird.

Als Nächstes binden wir Prisma ein.

npm install prisma --save-dev

npx prisma init

Mit diesen Befehlen wird Prisma installiert und ein prisma-Ordner erstellt.

Ersetzen Sie in der Datei .env den Wert von DATABASE_URL durch die Verbindungs-URL von Supabase. Ersetzen Sie dabei den Platzhalter [YOUR-PASSWORD] durch das Database password, das Sie zuvor in Supabase festgelegt haben.

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

Anschließend beschreiben Sie in /prisma/schema.prisma das Schema (die Strukturdefinition der Datenbank).

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())
}

model ○○ können Sie frei benennen.

Nachdem Sie das Schema geschrieben haben, führen Sie die Migration durch.

npx prisma migrate dev --name init

Die Datei migration.sql wird generiert, und die Datentabellen werden auf der Supabase-Seite erstellt.

Erstellung einer API zur Verbindung mit Supabase

Zum Speichern der eingegebenen Werte in Supabase wird eine API für die Verbindung erstellt.

Prisma Client im Projekt installieren.

npm install @prisma/client

Verbindung zu 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();
  }
};

Die GET-Funktion ist eine API, die alle Datensätze aus der Datenbank abruft. Mit der Methode findMany() werden alle Datensätze abgerufen, die der Bedingung entsprechen. Bei Prisma.memo.findMany() ist „memo“ der Schemaname.

Die POST-Funktion ist eine API, mit der Datensätze zur Datenbank hinzugefügt werden. Sie werden mit create() erstellt.

Darüber hinaus gibt es weitere Methoden zum Löschen, Aktualisieren und so weiter. Auch ohne SQL-Kenntnisse lassen sich diese intuitiv wie JavaScript bedienen.

Damit sind die grundlegenden Vorbereitungen abgeschlossen.

Anschließend muss nur noch die zuvor geschriebene API in die page.tsx übernommen und eingebunden werden.

'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>
  );
}

Das ist in Supabase gespeichert!

Diesmal habe ich mich größtenteils auf Gemini verlassen und die Anwendung grob erstellt. Wenn wir jedoch eine Datenbank nutzen, um Werte zu speichern, eröffnen sich deutlich mehr Möglichkeiten für Funktionen und Apps!

Ich hatte das Gefühl, Backend-Entwicklung wäre schwierig ... Aber mit dem GUI-Tool lässt sich die Datenbank übersichtlich verwalten, und die Anbindung an eine Datenbank ist dadurch viel einfacher geworden!

Yes!

Über den Autor

Ich entwickle Frontend-Lösungen mit Schwerpunkt auf Markup sowie mit JavaScript, React und Next.js. Es freut mich besonders, wenn Websites, an denen ich mitgearbeitet habe, erfolgreich online gehen! In meiner Freizeit spiele ich gern Gitarre. Katzen und Süßkartoffeln mag ich sehr 🐱🍠

Hirattchi

Frontend-Entwickler / Eintritt 2022

Artikel dieses Teammitglieds ansehen

Verlässliches Team und schnelle Reaktionsfähigkeit sind unsere Stärken

Bei Liberogic werden wir von unseren Kunden hoch geschätzt, da unsere erfahrenen Mitarbeiter Projekte proaktiv vorantreiben.
Wir achten darauf, Projektmanager und Direktoren gezielt einzusetzen, damit das gesamte Projekt reibungslos verläuft. Um unnötige Kostensteigerungen durch Vollzeitbindung zu vermeiden, verteilen wir Ressourcen passgenau. Zudem sind wir für unsere Geschwindigkeit bekannt, vom Verständnis der Anforderungen bis zur Erstellung und Einreichung von Angeboten.

Hinweis: Wir bieten keine SES-typischen Vor-Ort-Einsätze an. Wir bitten um Ihr Verständnis.

Sie können nahezu alle gängigen Tools für Projektmanagement und Chat nutzen, darunter Slack, Teams, Redmine, Backlog, Asana, Jira, Notion, Google Workspace, Zoom, Webex und viele weitere.

Stehen Sie bei großen Projekten mit SES oder Offshore-Teams vor technischen Herausforderungen oder Fragen zum Vorgehen?

Fallstudien