Setup Supabase Client (JS/TS)

Setup Supabase Client (JS/TS)

Saatnya hubungkan frontend Next.js-mu dengan backend Supabase! Pelajari cara menginstal package `@supabase/supabase-js` dan menginisialisasi Supabase client menggunakan Project URL dan Anon Key dengan aman.

"Telepon" ke Dapur Supabase: Nyambungin Proyek Next.js Pake Supabase Client!

Udah punya proyek Supabase yang keren di cloud dan udah ngintip isi dashboard-nya? Mantap! Sekarang, gimana caranya biar aplikasi Next.js (atau aplikasi JavaScript/TypeScript lainnya) yang ada di komputer kita bisa "ngobrol" atau "nelpon" ke "dapur" Supabase itu buat minta data, nyimpen data, atau ngurusin login pengguna?

Jawabannya adalah pake Supabase JS Client Library (@supabase/supabase-js)! Ini adalah library JavaScript resmi dari Supabase yang ngebantu kita berinteraksi sama semua fitur Supabase (Database, Auth, Storage, dll.) dengan cara yang gampang dan modern.

Langkah 1: Instal Package @supabase/supabase-js

Pertama, kita perlu nambahin library ini ke proyek Next.js kita sebagai dependensi.

  1. Buka Terminal di direktori root proyek Next.js-mu (tempat package.json berada).

  2. Jalanin perintah instalasi pake npm atau yarn:

    • Kalau pake npm:
      bashbash
      npm install @supabase/supabase-js
    • Kalau pake yarn:
      bashbash
      yarn add @supabase/supabase-js

    Ini bakal nge-download package @supabase/supabase-js dan nambahinnya ke dependencies di package.json-mu.

Langkah 2: Simpan Kunci API dan URL Proyek dengan Aman (Environment Variables)

Inget kan, pas bikin proyek di Supabase, kita dapet Project URL dan anon (public) key? Dua info ini yang kita butuhin buat nginisialisasi Supabase Client.

Praktik terbaik dan paling aman buat nyimpen info ini di proyek Next.js adalah pake Environment Variables. Di Next.js, kita bisa pake file .env.local.

  1. Di direktori root proyek Next.js-mu (sejajar dengan package.json), buat file baru bernama .env.local (kalau belum ada).

  2. Buka file .env.local dan masukin URL serta anon key dari proyek Supabase-mu. GANTI NILAI CONTOH DI BAWAH DENGAN INFO DARI DASHBOARD SUPABASE PROYEKMU YANG SEBENARNYA!

    envenv
    # File: .env.local (di root proyek Next.js)
     
    NEXT_PUBLIC_SUPABASE_URL=URL_PROYEK_SUPABASE_ANDA_DI_SINI
    NEXT_PUBLIC_SUPABASE_ANON_KEY=KUNCI_ANON_PUBLIK_ANDA_DI_SINI

    Penjelasan Penting:

    • NEXT_PUBLIC_: Awalan ini WAJIB di Next.js kalau kamu mau variabel lingkungan ini bisa diakses dari kode frontend (yang jalan di browser). Tanpa prefix NEXT_PUBLIC_, variabelnya cuma bakal tersedia di sisi server (misalnya, saat build atau di API Routes jika dikonfigurasi khusus). Karena Supabase Client seringkali diinisialisasi dan digunakan baik di client maupun server (tergantung arsitektur Next.js-mu), menggunakan NEXT_PUBLIC_ memastikan ketersediaannya.
    • Keamanan anon key: anon key (anonymous public key) memang dirancang untuk bisa diekspos di sisi klien. Keamanan datamu di Supabase akan lebih banyak diatur oleh Row Level Security (RLS) di database dan policies di Storage. Jangan pernah mengekspos service_role key di frontend!
    • .gitignore: Pastikan file .env.local ini sudah tercantum di dalam file .gitignore-mu. Ini penting biar file yang berisi kunci API-mu gak ikut ke-commit dan ke-push ke repository Git publik (seperti GitHub). Biasanya, create-next-app udah otomatis nambahin *.local (termasuk .env.local) ke .gitignore.

Langkah 3: Membuat File Inisialisasi Supabase Client (Singleton Pattern)

Biar gampang dipake di mana-mana di aplikasi kita dan kita cuma punya satu instance client (ini bagus buat performa dan manajemen koneksi), kita bikin satu file khusus buat nginisialisasi Supabase Client.

  1. Di dalem folder src/ proyekmu, bikin folder baru, misalnya lib (singkatan dari library) jika belum ada.
  2. Di dalem src/lib/, bikin file baru bernama supabase-client.ts.

File src/lib/supabase-client.ts:

typescripttypescript
// src/lib/supabase-client.ts
import { createClient, SupabaseClient } from '@supabase/supabase-js';
 
// Ambil URL dan Anon Key dari environment variables yang sudah di-prefix NEXT_PUBLIC_
const supabaseUrl: string = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const supabaseAnonKey: string = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
 
// Validasi apakah variabel lingkungan sudah diset dengan benar saat aplikasi berjalan
// (Pengecekan ini lebih efektif saat runtime di mana process.env sudah terisi)
if (!supabaseUrl) {
  throw new Error(
    "Supabase URL tidak ditemukan. Pastikan NEXT_PUBLIC_SUPABASE_URL sudah diset dengan benar di file .env.local Anda."
  );
}
if (!supabaseAnonKey) {
  throw new Error(
    "Supabase Anon Key tidak ditemukan. Pastikan NEXT_PUBLIC_SUPABASE_ANON_KEY sudah diset dengan benar di file .env.local Anda."
  );
}
 
// Buat dan ekspor satu instance Supabase client
// Memberikan tipe SupabaseClient secara eksplisit membantu dengan type-safety
// Jika Anda telah men-generate tipe dari skema database Supabase Anda (misalnya, menggunakan `supabase gen types typescript`),
// Anda bisa menggunakannya di sini untuk client yang lebih type-safe lagi:
// import { Database } from '../types/supabase'; // Sesuaikan path ke tipe Database Anda
// export const supabase: SupabaseClient<Database> = createClient<Database>(supabaseUrl, supabaseAnonKey);
 
export const supabase: SupabaseClient = createClient(supabaseUrl, supabaseAnonKey);
 
// Komentar untuk pengingat jika ingin menggunakan tipe database spesifik:
// Untuk menggunakan client dengan tipe database spesifik dari Supabase (hasil generate `supabase gen types typescript --project-id <ref> --schema public > types/supabase.ts`):
// 1. Pastikan Anda sudah generate file `types/supabase.ts`.
// 2. Ubah dua baris di atas (export const supabase) menjadi:
//    import { Database } from '@/types/supabase'; // Sesuaikan path jika perlu, @/ biasanya ke src/
//    export const supabase = createClient<Database>(supabaseUrl, supabaseAnonKey);
// Ini akan memberikan auto-completion dan type-checking yang lebih baik untuk nama tabel dan kolom Anda.

Bedah supabase-client.ts:

  • import { createClient, SupabaseClient } from '@supabase/supabase-js';: Impor fungsi createClient dan tipe SupabaseClient.
  • process.env.NEXT_PUBLIC_SUPABASE_URL!: Kita akses environment variable. Tanda seru ! di akhir (Non-null Assertion Operator) memberitahu TypeScript bahwa kita yakin variabel ini pasti ada nilainya saat runtime. Namun, validasi eksplisit seperti blok if di bawahnya adalah praktik yang lebih aman.
  • Validasi di Awal: Blok if ditambahkan untuk melempar error jika variabel lingkungan tidak ditemukan saat modul ini di-load. Ini membantu menangkap kesalahan konfigurasi lebih awal.
  • createClient(supabaseUrl, supabaseAnonKey): Membuat instance client.
  • export const supabase: Mengekspor instance agar bisa diimpor di bagian lain aplikasi.
  • Komentar tentang Tipe Database (<Database>): Diberikan catatan bagaimana cara menggunakan Supabase Client dengan tipe database yang lebih spesifik jika pengguna telah men-generate tipe dari Supabase CLI. Ini sangat penting untuk pengalaman TypeScript yang optimal.

PENTING Setelah Mengubah .env.local atau Variabel Lingkungan Lainnya: Setiap kali kamu mengubah isi file .env.local (atau variabel lingkungan lainnya yang dibaca saat build), kamu perlu me-restart development server Next.js-mu (npm run dev) agar perubahan tersebut terbaca oleh Next.js.

Langkah 4: Menggunakan Supabase Client di Komponen atau API Route

Sekarang, kamu bisa impor supabase dari supabase-client.ts tadi di komponen React (Client atau Server Component, tergantung kebutuhan) atau di API Routes (Route Handlers) untuk mulai berinteraksi dengan Supabase.

Contoh di Client Component ("use client";):

tsxtsx
// src/app/contoh-pengguna/page.tsx
"use client"; 
 
import React, { useState, useEffect } from 'react';
import { supabase } from '@/lib/supabase-client.ts'; // Impor client kita
 
interface UserProfile { // Contoh interface
  id: string;
  username: string;
}
 
export default function HalamanProfilPengguna() {
  const [profil, setProfil] = useState<UserProfile | null>(null);
  // ... (sisa kode komponen sama seperti draf sebelumnya) ...
 
  useEffect(() => {
    async function ambilProfil() {
      const { data: { user } } = await supabase.auth.getUser();
      if (user) {
        const { data, error } = await supabase
          .from('profiles') 
          .select('*')
          .eq('id', user.id) 
          .single();
 
        if (error) console.error("Error ambil profil:", error);
        else setProfil(data as UserProfile); // Type assertion jika perlu
      }
      // ... setLoading(false) ...
    }
    ambilProfil();
  }, []);
 
  // ... (return JSX) ...
  if (!profil) return <p>Profil tidak ditemukan atau Anda belum login.</p>;
  return <div><h1>Profil {profil.username}</h1></div>;
}

Contoh di Server Component (misalnya, mengambil daftar produk):

tsxtsx
// src/app/produk/page.tsx (Server Component)
import { supabase } from '@/lib/supabase-client.ts'; // Impor client kita
// import { Kue } from '@/data/kue'; // Asumsi tipe Kue sudah ada
 
async function getProdukKue() {
  // Saat menggunakan Supabase client di Server Components, 
  // untuk operasi yang memerlukan autentikasi user atau RLS berdasarkan user,
  // Anda perlu menggunakan Supabase client yang diinisialisasi khusus untuk server-side
  // dengan cookies (misalnya menggunakan helper dari `@supabase/ssr`).
  // Untuk data publik yang RLS-nya memperbolehkan akses anonim, client yang di-init dengan anon key bisa bekerja.
  // Untuk contoh ini, kita asumsikan tabel 'kue' bisa dibaca publik.
  const { data, error } = await supabase
    .from('kue') // Nama tabel kue Anda
    .select('*')
    .order('created_at', { ascending: false });
 
  if (error) {
    console.error("Error ambil produk kue:", error);
    return [];
  }
  return data || []; 
}
 
export default async function HalamanProduk() {
  const daftarProduk = await getProdukKue();
 
  return (
    <div>
      <h1>Daftar Produk Kue</h1>
      <ul>
        {daftarProduk.map((produk: any) => ( // Ganti 'any' dengan tipe Kue
          <li key={produk.id}>{produk.nama} - Rp {produk.harga}</li>
        ))}
      </ul>
    </div>
  );
}

Catatan Penting untuk Server Components & Supabase Client:

  • Saat menggunakan Supabase JS Client di Server Components untuk operasi yang memerlukan konteks pengguna yang sudah login (misalnya, RLS yang bergantung pada auth.uid()), Anda perlu cara untuk membuat instance Supabase client yang "sadar" akan sesi pengguna di sisi server. Ini biasanya melibatkan penggunaan helper seperti @supabase/ssr yang membantu mengelola cookies dan sesi dengan benar. Untuk panduan dasar ini, kita mungkin tetap menggunakan satu client yang diinisialisasi dengan anonKey untuk kesederhanaan saat mengakses data publik, dengan asumsi RLS sudah diatur dengan tepat. Jika operasi memerlukan service_role key, itu harus dilakukan di API Route atau Edge Function yang aman.

Sip! Dengan Supabase Client yang udah ke-setup dengan aman menggunakan environment variables, aplikasi Next.js-mu sekarang punya "saluran telepon" langsung ke "dapur" backend Supabase! Kamu jadi bisa ngambil data, nyimpen data, ngurusin login, dan banyak lagi, semuanya dari kode JavaScript/TypeScript-mu.

Di bagian berikutnya, kita bakal fokus ke ngedefinisiin tabel-tabel buat Toko Kue kita di database Supabase.

Uji Pemahamanmu!

Memeriksa status login...