Membangun aplikasi dengan Firebase Data Connect

1. Sebelum Memulai

Aplikasi FriendlyMovies

Dalam codelab ini, Anda akan mengintegrasikan Firebase Data Connect dengan database Cloud SQL untuk membangun aplikasi web ulasan film. Aplikasi yang telah selesai menampilkan cara Firebase Data Connect menyederhanakan proses build aplikasi yang didukung SQL. Fitur ini mencakup:

  • Autentikasi: Terapkan autentikasi kustom untuk kueri dan mutasi aplikasi Anda, sehingga memastikan hanya pengguna yang berwenang yang dapat berinteraksi dengan data Anda.
  • Skema GraphQL: Buat dan kelola struktur data Anda menggunakan skema GraphQL yang fleksibel dan disesuaikan dengan kebutuhan aplikasi web ulasan film.
  • Kueri dan Mutasi SQL: Mengambil, memperbarui, dan mengelola data di Cloud SQL menggunakan kueri dan mutasi yang didukung oleh GraphQL.
  • Penelusuran Lanjutan dengan Pencocokan String Sebagian: Gunakan filter dan opsi penelusuran untuk menemukan film berdasarkan kolom seperti judul, deskripsi, atau tag.
  • Opsional: Integrasi Penelusuran Vektor: Tambahkan fungsi penelusuran konten menggunakan penelusuran vektor Firebase Data Connect untuk memberikan pengalaman pengguna yang kaya berdasarkan input dan preferensi.

Prasyarat

Anda memerlukan pemahaman dasar tentang JavaScript.

Yang Akan Anda Pelajari

  • Siapkan Firebase Data Connect dengan emulator lokal.
  • Buat desain skema data menggunakan Data Connect dan GraphQL.
  • Menulis dan menguji berbagai kueri dan mutasi untuk aplikasi ulasan film.
  • Pelajari cara Firebase Data Connect membuat dan menggunakan SDK di aplikasi.
  • Deploy skema dan kelola database secara efisien.

Yang Anda Butuhkan

Menyiapkan Lingkungan Pengembangan Anda

Bagian ini akan memandu Anda menyiapkan lingkungan untuk mulai mem-build aplikasi ulasan film menggunakan Firebase Data Connect.

Langkah 1: Meng-clone Repositori Project

Mulailah dengan meng-clone repositori project dan menginstal dependensi yang diperlukan:

git clone https://github.com/firebaseextended/codelab-dataconnect-web
cd codelab-dataconnect-web
cd ./app && npm i
npm run dev
  1. Setelah menjalankan perintah ini, buka http://localhost:5173 di browser Anda untuk melihat aplikasi web yang berjalan secara lokal. Ini berfungsi sebagai frontend Anda untuk mem-build aplikasi ulasan film dan berinteraksi dengan fiturnya.

93f6648a2532c606.png

Langkah 2: Buka Project di Visual Studio Code

Buka folder codelab-dataconnect-web yang di-clone menggunakan Visual Studio Code. Di sinilah Anda akan menentukan skema, menulis kueri, dan menguji fungsionalitas aplikasi.

Langkah 3: Instal Ekstensi Visual Studio Firebase Data Connect

Untuk menggunakan fitur Data Connect, instal Ekstensi Visual Studio Firebase Data Connect. Atau: Instal dari Visual Studio Code Marketplace atau telusuri dalam VS Code.

  1. Atau: Instal dari Visual Studio Code Marketplace atau telusuri dalam VS Code.

b03ee38c9a81b648.pngS

Langkah 4: Buat Project Firebase

Buka Firebase Console untuk membuat project Firebase baru jika Anda belum memilikinya. Kemudian, di ekstensi VSCode Firebase Data Connect:

  • Klik tombol Login.
  • Klik Connect a Firebase Project lalu pilih project yang Anda buat di Firebase Console.

4bb2fbf8f9fac29b.png

Langkah 5: Mulai emulator Firebase

Di ekstensi VSCode Firebase Data Connect, klik Start Emulators, dan pastikan emulator sedang berjalan di terminal.

6d3d95f4cb708db1.png

2. Meninjau codebase awal

Di bagian ini, Anda akan menjelajahi area utama codebase awal aplikasi. Meskipun aplikasi tidak memiliki beberapa fungsi, sebaiknya pahami keseluruhan strukturnya.

Struktur folder dan file

Berikut ringkasan singkat tentang struktur folder dan file aplikasi:

{i>dataconnect/<i}

Berisi konfigurasi Firebase Data Connect, konektor (yang menentukan kueri dan mutasi), dan file skema.

  • schema/schema.gql: Menentukan skema GraphQL
  • connector/queries.gql: Kueri yang diperlukan di aplikasi Anda.
  • connector/mutations.gql: Mutasi yang diperlukan di aplikasi Anda.
  • connector/connector.yaml: File konfigurasi untuk pembuatan SDK

aplikasi/src/

Berisi logika aplikasi dan interaksi dengan Firebase Data Connect.

  • firebase.ts: Konfigurasi untuk terhubung ke aplikasi Firebase di konsol.
  • lib/dataconnect-sdk/: Folder ini berisi SDK yang dihasilkan. Anda dapat mengedit lokasi pembuatan SDK di file connector/connector.yaml dan SDK akan otomatis dibuat setiap kali Anda menentukan kueri atau mutasi.

3. Menentukan skema untuk Ulasan Film

Di bagian ini, Anda akan menentukan struktur dan hubungan antara entitas utama dalam aplikasi film dalam skema. Entity seperti Movie, User, Actor, dan Review dipetakan ke tabel database, dengan hubungan yang ditetapkan menggunakan Firebase Data Connect dan perintah skema GraphQL. Setelah ada, aplikasi Anda akan siap menangani semuanya mulai dari mencari film dengan peringkat teratas dan memfilter berdasarkan genre hingga membiarkan pengguna memberikan ulasan, menandai favorit, menjelajahi film serupa, atau menemukan film yang direkomendasikan berdasarkan input teks melalui penelusuran vektor.

Entitas dan Hubungan Inti

Jenis Movie menyimpan detail utama seperti judul, genre, dan tag, yang digunakan aplikasi untuk penelusuran dan profil film. Jenis User melacak interaksi pengguna, seperti ulasan dan favorit. Reviews menghubungkan pengguna ke film, sehingga aplikasi dapat menampilkan rating dan masukan yang dibuat pengguna.

Hubungan antara film, aktor, dan pengguna membuat aplikasi lebih dinamis. Tabel join MovieActor membantu menampilkan detail pemeran dan filmografi aktor. Dengan jenis FavoriteMovie, pengguna dapat memfavoritkan film, sehingga aplikasi dapat menampilkan daftar favorit yang dipersonalisasi dan menyoroti pilihan populer.

Tabel Film

Jenis Film menentukan struktur utama untuk entitas film, termasuk kolom seperti judul, genre, tahun rilis, dan rating.

Salin dan tempel cuplikan kode ke file dataconnect/schema/schema.gql Anda:

type Movie
  @table {
  id: UUID! @default(expr: "uuidV4()")
  title: String!
  imageUrl: String!
  releaseYear: Int
  genre: String
  rating: Float
  description: String
  tags: [String]
}

Poin-Poin Penting:

  • id: UUID unik untuk setiap film, yang dibuat menggunakan @default(expr: "uuidV4()").

Tabel MovieMetadata

Jenis MovieMetadata menetapkan hubungan one-to-one dengan jenis Movie. Ini mencakup data tambahan seperti sutradara film.

Salin dan tempel cuplikan kode ke file dataconnect/schema/schema.gql Anda:

type MovieMetadata
  @table {
  # @ref creates a field in the current table (MovieMetadata)
  # It is a reference that holds the primary key of the referenced type
  # In this case, @ref(fields: "movieId", references: "id") is implied
  movie: Movie! @ref
  # movieId: UUID <- this is created by the above @ref
  director: String
}

Poin-Poin Penting:

  • Film! @ref: Mereferensikan jenis Movie, yang menetapkan hubungan kunci asing.

Tabel Pelaku

Salin dan tempel cuplikan kode ke file dataconnect/schema/schema.gql Anda:

type Actor @table {
  id: UUID!
  imageUrl: String! 
  name: String! @col(name: "name", dataType: "varchar(30)")
}

Jenis Actor mewakili aktor dalam database film, dengan setiap aktor dapat menjadi bagian dari beberapa film, membentuk hubungan many-to-many.

Tabel Pelaku Film

Salin dan tempel cuplikan kode ke file dataconnect/schema/schema.gql Anda:

type MovieActor @table(key: ["movie", "actor"]) {
  # @ref creates a field in the current table (MovieActor) that holds the primary key of the referenced type
  # In this case, @ref(fields: "id") is implied
  movie: Movie!
  # movieId: UUID! <- this is created by the implied @ref, see: implicit.gql

  actor: Actor!
  # actorId: UUID! <- this is created by the implied  @ref, see: implicit.gql

  role: String! # "main" or "supporting"
}

Poin-Poin Penting:

  • movie: Mereferensikan jenis Movie, secara implisit menghasilkan kunci asing movieId: UUID!.
  • actor: Mereferensikan jenis Pelaku, secara implisit menghasilkan kunci asing actorId: UUID!.
  • role: Menentukan peran aktor dalam film (misalnya, "utama" atau "mendukung").

Tabel Pengguna

Jenis User menentukan entity pengguna yang berinteraksi dengan film dengan memberikan ulasan atau memfavoritkan film.

Salin dan tempel cuplikan kode ke file dataconnect/schema/schema.gql Anda:

type User
  @table {
  id: String! @col(name: "auth_uid")
  username: String! @col(dataType: "varchar(50)")
  # The following are generated from the @ref in the Review table
  # reviews_on_user 
  # movies_via_Review
}

Tabel FavoriteMovie

Jenis FavoriteMovie adalah tabel gabungan yang menangani hubungan many-to-many antara pengguna dan film atau aktor favorit mereka. Setiap tabel menautkan User ke Movie.

Salin dan tempel cuplikan kode ke file dataconnect/schema/schema.gql Anda:

type FavoriteMovie
  @table(name: "FavoriteMovies", singular: "favorite_movie", plural: "favorite_movies", key: ["user", "movie"]) {
  # @ref is implicit
  user: User!
  movie: Movie!
}

Poin-Poin Penting:

  • movie: Mereferensikan jenis Film, secara implisit membuat MovieId dengan kunci asing: UUID!.
  • user: Mereferensikan jenis pengguna, secara implisit membuat userId kunci asing: UUID!.

Tabel Ulasan

Jenis Ulasan mewakili entitas ulasan dan menautkan jenis Pengguna dan Film dalam hubungan many-to-many (satu pengguna dapat memberikan banyak ulasan, dan setiap film dapat memiliki banyak ulasan).

Salin dan tempel cuplikan kode ke file dataconnect/schema/schema.gql Anda:

type Review @table(name: "Reviews", key: ["movie", "user"]) {
  id: UUID! @default(expr: "uuidV4()")
  user: User!
  movie: Movie!
  rating: Int
  reviewText: String
  reviewDate: Date! @default(expr: "request.time")
}

Poin-Poin Penting:

  • user: Mereferensikan pengguna yang memberikan ulasan.
  • movie: Mereferensikan film yang sedang diulas.
  • reviewDate: Otomatis ditetapkan ke waktu saat ulasan dibuat menggunakan @default(expr: "request.time").

Kolom dan Setelan Default yang Dibuat Otomatis

Skema menggunakan ekspresi seperti @default(expr: "uuidV4()") untuk membuat ID dan stempel waktu unik secara otomatis. Misalnya, kolom ID dalam jenis Film dan Ulasan akan otomatis diisi dengan UUID saat data baru dibuat.

Setelah skema ditentukan, aplikasi film Anda memiliki fondasi yang kuat untuk struktur data dan hubungannya.

4. Mengambil Film Terpopuler dan Terbaru

Aplikasi FriendlyMovies

Di bagian ini, Anda akan menyisipkan data film tiruan ke emulator lokal, lalu menerapkan konektor (kueri) dan kode TypeScript untuk memanggil konektor ini di aplikasi web. Pada akhirnya, aplikasi Anda akan dapat mengambil dan menampilkan film dengan rating tertinggi dan terbaru secara dinamis langsung dari database.

Menyisipkan Data Film, Aktor, dan Ulasan Simulasi

  1. Di VSCode, buka dataconnect/moviedata_insert.gql. Pastikan emulator di ekstensi Firebase Data Connect sedang berjalan.
  2. Anda akan melihat tombol Run (local) di bagian atas file. Klik ini untuk menyisipkan data film tiruan ke dalam {i>database<i} Anda.

e424f75e63bf2e10.png

  1. Periksa terminal Data Connect Execution untuk mengonfirmasi bahwa data berhasil ditambahkan.

e0943d7704fb84ea.png

Mengimplementasikan Konektor

  1. Buka dataconnect/movie-connector/queries.gql. Anda akan menemukan kueri ListMovies dasar di komentar:
query ListMovies @auth(level: PUBLIC) {
  movies {
    id
    title
    imageUrl
    releaseYear
    genre
    rating
    tags
    description
  }
}

Kueri ini mengambil semua film dan detailnya (mis., id, title, releaseYear). Namun, tindakan ini tidak mengurutkan film.

  1. Ganti kueri ListMovies dengan kueri di bawah ini untuk menambahkan opsi pengurutan dan batas:
# List subset of fields for movies
query ListMovies($orderByRating: OrderDirection, $orderByReleaseYear: OrderDirection, $limit: Int) @auth(level: PUBLIC) {
  movies(
    orderBy: [
      { rating: $orderByRating },
      { releaseYear: $orderByReleaseYear }
    ]
    limit: $limit
  ) {
    id
    title
    imageUrl
    releaseYear
    genre
    rating
    tags
    description
  }
}

Klik tombol Run (local) untuk menjalankan kueri terhadap database lokal Anda. Anda juga dapat memasukkan variabel kueri di panel konfigurasi sebelum menjalankannya.

c4d947115bb11b16.pngS

Poin-Poin Penting:

  • movies(): Kolom kueri GraphQL untuk mengambil data film dari database.
  • orderByRating: Parameter untuk mengurutkan film menurut rating (naik/turun).
  • orderByReleaseYear: Parameter untuk mengurutkan film berdasarkan tahun rilis (menaik/menurun).
  • limit: Membatasi jumlah film yang ditampilkan.

Mengintegrasikan Kueri di Aplikasi Web

Di bagian ini, Anda akan menggunakan kueri yang ditentukan di bagian sebelumnya di aplikasi web Anda. Emulator Firebase Data Connect menghasilkan SDK berdasarkan informasi dalam file .gql (schema.gql, queries.gql, mutations.gql) dan connector.yaml. SDK ini dapat langsung dipanggil dalam aplikasi Anda.

  1. Di MovieService (app/src/lib/MovieService.tsx), hapus komentar pernyataan impor di bagian atas:
import { listMovies, ListMoviesData, OrderDirection } from "@movie/dataconnect";

Fungsi listMovies, jenis respons ListMoviesData, dan enum OrderDirection adalah SDK yang dihasilkan oleh emulator Firebase Data Connect berdasarkan skema dan kueri yang telah Anda tetapkan sebelumnya .

  1. Ganti fungsi handleGetTopMovies dan handleGetLatestMovies dengan kode berikut:
// Fetch top-rated movies
export const handleGetTopMovies = async (
  limit: number
): Promise<ListMoviesData["movies"] | null> => {
  try {
    const response = await listMovies({
      orderByRating: OrderDirection.DESC,
      limit,
    });
    return response.data.movies;
  } catch (error) {
    console.error("Error fetching top movies:", error);
    return null;
  }
};

// Fetch latest movies
export const handleGetLatestMovies = async (
  limit: number
): Promise<ListMoviesData["movies"] | null> => {
  try {
    const response = await listMovies({
      orderByReleaseYear: OrderDirection.DESC,
      limit,
    });
    return response.data.movies;
  } catch (error) {
    console.error("Error fetching latest movies:", error);
    return null;
  }
};

Poin-Poin Penting:

  • listMovies: Fungsi yang dibuat otomatis yang memanggil kueri listMovies untuk mengambil daftar film. Halaman ini mencakup opsi untuk mengurutkan menurut rating atau tahun rilis dan membatasi jumlah hasil.
  • ListMoviesData: Jenis hasil yang digunakan untuk menampilkan 10 film teratas dan film terbaru di halaman beranda.

Lihat Penerapannya

Muat ulang aplikasi web Anda untuk melihat cara kerja kueri. Halaman beranda kini menampilkan daftar film secara dinamis, mengambil data langsung dari database lokal Anda. Anda akan melihat film dengan rating tertinggi dan terbaru muncul dengan lancar, yang mencerminkan data yang baru saja Anda siapkan.

5. Menampilkan Detail Film dan Aktor

Di bagian ini, Anda akan mengimplementasikan fungsi untuk mengambil informasi mendetail tentang film atau aktor menggunakan ID uniknya. Hal ini tidak hanya melibatkan pengambilan data dari tabel masing-masing, tetapi juga menggabungkan tabel terkait untuk menampilkan detail yang komprehensif, seperti ulasan film dan filmografi aktor.

ac7fefa7ff779231.png

Mengimplementasikan Konektor

  1. Buka dataconnect/movie-connector/queries.gql di project Anda.
  2. Tambahkan kueri berikut untuk mengambil detail film dan aktor:
# Get movie by id
query GetMovieById($id: UUID!) @auth(level: PUBLIC) {
 movie(id: $id) {
    id
    title
    imageUrl
    releaseYear
    genre
    rating
    description
    tags
    metadata: movieMetadatas_on_movie {
      director
    }
    mainActors: actors_via_MovieActor(where: { role: { eq: "main" } }) {
      id
      name
      imageUrl
    }
    supportingActors: actors_via_MovieActor(
      where: { role: { eq: "supporting" } }
    ) {
      id
      name
      imageUrl
    }
    reviews: reviews_on_movie {
      id
      reviewText
      reviewDate
      rating
      user {
        id
        username
      }
    }
  }
 }

# Get actor by id
query GetActorById($id: UUID!) @auth(level: PUBLIC) {
  actor(id: $id) {
    id
    name
    imageUrl
    mainActors: movies_via_MovieActor(where: { role: { eq: "main" } }) {
      id
      title
      genre
      tags
      imageUrl
    }
    supportingActors: movies_via_MovieActor(
      where: { role: { eq: "supporting" } }
    ) {
      id
      title
      genre
      tags
      imageUrl
    }
  }
}
  1. Simpan perubahan dan tinjau kueri.

Poin-Poin Penting:

  • movie()/actor(): Kolom kueri GraphQL untuk mengambil satu film atau aktor dari tabel Film atau Aktor.
  • _on_: Hal ini memungkinkan akses langsung ke kolom dari jenis terkait yang memiliki hubungan kunci asing. Misalnya, reviews_on_movie mengambil semua ulasan yang terkait dengan film tertentu.
  • _via_: Digunakan untuk menavigasi hubungan many-to-many melalui tabel gabungan. Misalnya, actors_via_MovieActor mengakses jenis Aktor melalui tabel penggabungan MovieActor, dan kondisi where memfilter aktor berdasarkan perannya (mis., "utama" atau "mendukung").

Di panel eksekusi Data Connect, Anda dapat menguji kueri dengan memasukkan ID tiruan, seperti:

{"id": "550e8400-e29b-41d4-a716-446655440000"}

Klik Run (local) untuk GetMovieById guna mengambil detail tentang "Quantum Paradox" (film tiruan yang terkait dengan ID di atas).

1b08961891e44da2.png

Mengintegrasikan Kueri di Aplikasi Web

  1. Di MovieService (app/src/lib/MovieService.tsx), hapus tanda komentar impor berikut:
import { getMovieById, GetMovieByIdData } from "@movie/dataconnect";
import { GetActorByIdData, getActorById } from "@movie/dataconnect";
  1. Ganti fungsi handleGetMovieById dan handleGetActorById dengan kode berikut:
// Fetch movie details by ID
export const handleGetMovieById = async (
  movieId: string
) => {
  try {
    const response = await getMovieById({ id: movieId });
    if (response.data.movie) {
      return response.data.movie;
    }
    return null;
  } catch (error) {
    console.error("Error fetching movie:", error);
    return null;
  }
};

// Calling generated SDK for GetActorById
export const handleGetActorById = async (
  actorId: string
): Promise<GetActorByIdData["actor"] | null> => {
  try {
    const response = await getActorById({ id: actorId });
    if (response.data.actor) {
      return response.data.actor;
    }
    return null;
  } catch (error) {
    console.error("Error fetching actor:", error);
    return null;
  }
};

Poin-Poin Penting:

  • getMovieById / getActorById: Ini adalah fungsi yang dihasilkan secara otomatis yang memanggil kueri yang Anda tentukan, mengambil informasi mendetail untuk film atau aktor tertentu.
  • GetMovieByIdData / GetActorByIdData: Ini adalah jenis hasil, yang digunakan untuk menampilkan detail film dan aktor dalam aplikasi.

Lihat Penerapannya

Sekarang, buka halaman beranda aplikasi web Anda. Klik film, dan Anda akan dapat melihat semua detailnya, termasuk aktor dan ulasan—informasi yang diambil dari tabel terkait. Demikian pula, mengklik aktor akan menampilkan film yang dibintanginya.

6. Menangani Autentikasi Pengguna

Di bagian ini, Anda akan menerapkan fungsi login dan logout pengguna menggunakan Firebase Authentication. Anda juga akan menggunakan data Firebase Authentication untuk mengambil atau memperbarui data pengguna secara langsung di Firebase DataConnect, sehingga memastikan pengelolaan pengguna yang aman dalam aplikasi Anda.

9890838045d5a00e.pngS

Mengimplementasikan Konektor

  1. Buka mutations.gql di dataconnect/movie-connector/.
  2. Tambahkan mutasi berikut untuk membuat atau memperbarui pengguna terautentikasi saat ini:
# Create or update the current authenticated user
mutation UpsertUser($username: String!) @auth(level: USER) {
  user_upsert(
    data: {
      id_expr: "auth.uid"
      username: $username
    }
  )
}

Poin Penting:

  • id_expr: "auth.uid": Metode ini menggunakan auth.uid, yang disediakan langsung oleh Firebase Authentication, bukan oleh pengguna atau aplikasi, yang menambahkan lapisan keamanan ekstra dengan memastikan ID pengguna ditangani secara aman dan otomatis.

Selanjutnya, buka queries.gql di dataconnect/movie-connector/.

Tambahkan kueri berikut untuk mengambil pengguna saat ini:

# Get user by ID
query GetCurrentUser @auth(level: USER) {
  user(key: { id_expr: "auth.uid" }) {
    id
    username
    reviews: reviews_on_user {
      id
      rating
      reviewDate
      reviewText
      movie {
        id
        title
      }
    }
    favoriteMovies: favorite_movies_on_user {
      movie {
        id
        title
        genre
        imageUrl
        releaseYear
        rating
        description
        tags
        metadata: movieMetadatas_on_movie {
          director
        }
      }
    }
  }
}

Poin-Poin Penting:

  • auth.uid: Data ini diambil langsung dari Firebase Authentication, sehingga memastikan akses yang aman ke data khusus pengguna.
  • _on_ Kolom: Kolom ini mewakili tabel gabungan:
  • reviews_on_user: Mengambil semua ulasan yang terkait dengan pengguna, termasuk ID dan judul film.
  • favorite_movies_on_user: Mengambil semua film yang ditandai sebagai favorit oleh pengguna, termasuk informasi mendetail seperti genre, tahun rilis, rating, dan metadata.

Mengintegrasikan Kueri di Aplikasi Web

  1. Di MovieService (app/src/lib/MovieService.tsx), hapus tanda komentar pada impor berikut:
import { upsertUser } from "@movie/dataconnect";
import { getCurrentUser, GetCurrentUserData } from "@movie/dataconnect";
  1. Ganti fungsi handleAuthStateChange dan handleGetCurrentUser dengan kode berikut:
// Handle user authentication state changes and upsert user
export const handleAuthStateChange = (
  auth: any,
  setUser: (user: User | null) => void
) => {
  return onAuthStateChanged(auth, async (user) => {
    if (user) {
      setUser(user);
      const username = user.email?.split("@")[0] || "anon";
      await upsertUser({ username });
    } else {
      setUser(null);
    }
  });
};

// Fetch current user profile
export const handleGetCurrentUser = async (): Promise<
  GetCurrentUserData["user"] | null
> => {
  try {
    const response = await getCurrentUser();
    return response.data.user;
  } catch (error) {
    console.error("Error fetching user profile:", error);
    return null;
  }
};

Poin-Poin Penting:

  • handleAuthStateChange: Fungsi ini memproses perubahan status autentikasi. Saat pengguna login, fungsi ini menetapkan data pengguna dan memanggil mutasi upsertUser untuk membuat atau memperbarui informasi pengguna di database.
  • handleGetCurrentUser: Mengambil profil pengguna saat ini menggunakan kueri getCurrentUser, yang mengambil ulasan dan film favorit pengguna.

Lihat Penerapannya

Sekarang, klik tombol "Login dengan Google" di menu navigasi. Anda dapat login menggunakan emulator Firebase Auth. Setelah login, klik "Profil Saya". Untuk saat ini, tabel ini akan kosong, tetapi Anda telah menyiapkan dasar untuk penanganan data khusus pengguna di aplikasi.

7. Mengimplementasikan Interaksi Pengguna

Di bagian ini, Anda akan menerapkan interaksi pengguna di aplikasi ulasan film, yang memungkinkan pengguna mengelola film favorit mereka dan memberikan atau menghapus ulasan.

b3d0ac1e181c9de9.pngS

Mengimplementasikan Konektor

  1. Buka mutations.gql di dataconnect/movie-connector/.
  2. Tambahkan mutasi berikut untuk menangani film favorit:
# Add a movie to the user's favorites list
mutation AddFavoritedMovie($movieId: UUID!) @auth(level: USER) {
  favorite_movie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId })
}

# Remove a movie from the user's favorites list
mutation DeleteFavoritedMovie($movieId: UUID!) @auth(level: USER) {
  favorite_movie_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
}

Poin-Poin Penting:

  • userId_expr: "auth.uid": Menggunakan auth.uid, yang disediakan langsung oleh Firebase Authentication, memastikan bahwa hanya data pengguna terautentikasi yang diakses atau diubah.
  1. Selanjutnya, buka queries.gql di dataconnect/movie-connector/.
  2. Tambahkan kueri berikut untuk memeriksa apakah film difavoritkan:
query GetIfFavoritedMovie($movieId: UUID!) @auth(level: USER) {
  favorite_movie(key: { userId_expr: "auth.uid", movieId: $movieId }) {
    movieId
  }
}

Poin-Poin Penting:

  • auth.uid: Memastikan akses aman ke data khusus pengguna menggunakan Firebase Authentication.
  • favorite_movie: Memeriksa tabel join favorite_movies untuk melihat apakah film tertentu ditandai sebagai favorit oleh pengguna saat ini.

Mengintegrasikan Kueri di Aplikasi Web

  1. Di MovieService (app/src/lib/MovieService.tsx), hapus tanda komentar impor berikut:
import { addFavoritedMovie, deleteFavoritedMovie, getIfFavoritedMovie } from "@movie/dataconnect";
  1. Ganti fungsi handleAddFavoritedMovie, handleDeleteFavoritedMovie, dan handleGetIfFavoritedMovie dengan kode berikut:
// Add a movie to user's favorites
export const handleAddFavoritedMovie = async (
  movieId: string
): Promise<void> => {
  try {
    await addFavoritedMovie({ movieId });
  } catch (error) {
    console.error("Error adding movie to favorites:", error);
    throw error;
  }
};

// Remove a movie from user's favorites
export const handleDeleteFavoritedMovie = async (
  movieId: string
): Promise<void> => {
  try {
    await deleteFavoritedMovie({ movieId });
  } catch (error) {
    console.error("Error removing movie from favorites:", error);
    throw error;
  }
};

// Check if the movie is favorited by the user
export const handleGetIfFavoritedMovie = async (
  movieId: string
): Promise<boolean> => {
  try {
    const response = await getIfFavoritedMovie({ movieId });
    return !!response.data.favorite_movie;
  } catch (error) {
    console.error("Error checking if movie is favorited:", error);
    return false;
  }
};

Poin-Poin Penting:

  • handleAddFavoritedMovie dan handleDeleteFavoritedMovie: Gunakan mutasi untuk menambahkan atau menghapus film dari favorit pengguna dengan aman.
  • handleGetIfFavoritedMovie: Menggunakan kueri getIfFavoritedMovie untuk memeriksa apakah film ditandai sebagai favorit oleh pengguna.

Lihat Penerapannya

Sekarang, Anda dapat memfavoritkan atau membatalkan favorit film dengan mengklik ikon hati di kartu film dan halaman detail film. Selain itu, Anda dapat melihat film favorit di halaman profil.

Menerapkan Ulasan Pengguna

Berikutnya, Anda akan menerapkan bagian untuk mengelola ulasan pengguna di aplikasi.

Mengimplementasikan Konektor

  1. Di mutations.gql (dataconnect/movie-connector/mutations.gql): Tambahkan mutasi berikut:
# Add a review for a movie
mutation AddReview($movieId: UUID!, $rating: Int!, $reviewText: String!)
@auth(level: USER) {
  review_insert(
    data: {
      userId_expr: "auth.uid"
      movieId: $movieId
      rating: $rating
      reviewText: $reviewText
      reviewDate_date: { today: true }
    }
  )
}

# Delete a user's review for a movie
mutation DeleteReview($movieId: UUID!) @auth(level: USER) {
  review_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
}

Poin-Poin Penting:

  • userId_expr: "auth.uid": Memastikan ulasan dikaitkan dengan pengguna yang diautentikasi.
  • reviewDate_date: { today: true }: Otomatis membuat tanggal saat ini untuk peninjauan menggunakan DataConnect, sehingga Anda tidak perlu memasukkan data secara manual.

Mengintegrasikan Kueri di Aplikasi Web

  1. Di MovieService (app/src/lib/MovieService.tsx), hapus tanda komentar impor berikut:
import { addReview, deleteReview } from "@movie/dataconnect";
  1. Ganti fungsi handleAddReview dan handleDeleteReview dengan kode berikut:
// Add a review to a movie
export const handleAddReview = async (
  movieId: string,
  rating: number,
  reviewText: string
): Promise<void> => {
  try {
    await addReview({ movieId, rating, reviewText });
  } catch (error) {
    console.error("Error adding review:", error);
    throw error;
  }
};

// Delete a review from a movie
export const handleDeleteReview = async (movieId: string): Promise<void> => {
  try {
    await deleteReview({ movieId });
  } catch (error) {
    console.error("Error deleting review:", error);
    throw error;
  }
};

Poin-Poin Penting:

  • handleAddReview: Memanggil mutasi addReview untuk menambahkan ulasan film yang ditentukan, menautkannya dengan aman ke pengguna yang diautentikasi.
  • handleDeleteReview: Menggunakan mutasi deleteReview untuk menghapus ulasan film oleh pengguna terautentikasi.

Lihat Penerapannya

Pengguna kini dapat memberikan ulasan untuk film di halaman detail film. Mereka juga dapat melihat dan menghapus ulasan mereka di halaman profil, sehingga mereka memiliki kontrol penuh atas interaksi mereka dengan aplikasi.

8. Filter Lanjutan dan Pencocokan Teks Sebagian

Di bagian ini, Anda akan menerapkan kemampuan penelusuran lanjutan, yang memungkinkan pengguna menelusuri film berdasarkan rentang rating dan tahun rilis, memfilter menurut genre dan tag, melakukan pencocokan teks sebagian dalam judul atau deskripsi, dan bahkan menggabungkan beberapa filter untuk hasil yang lebih akurat.

ece70ee0ab964e28.png

Mengimplementasikan Konektor

  1. Buka queries.gql di dataconnect/movie-connector/.
  2. Tambahkan kueri berikut untuk mendukung berbagai kemampuan penelusuran:
# Search for movies, actors, and reviews
query SearchAll(
  $input: String
  $minYear: Int!
  $maxYear: Int!
  $minRating: Float!
  $maxRating: Float!
  $genre: String!
) @auth(level: PUBLIC) {
  moviesMatchingTitle: movies(
    where: {
      _and: [
        { releaseYear: { ge: $minYear } }
        { releaseYear: { le: $maxYear } }
        { rating: { ge: $minRating } }
        { rating: { le: $maxRating } }
        { genre: { contains: $genre } }
        { title: { contains: $input } }
      ]
    }
  ) {
    id
    title
    genre
    rating
    imageUrl
  }
  moviesMatchingDescription: movies(
    where: {
      _and: [
        { releaseYear: { ge: $minYear } }
        { releaseYear: { le: $maxYear } }
        { rating: { ge: $minRating } }
        { rating: { le: $maxRating } }
        { genre: { contains: $genre } }
        { description: { contains: $input } }
      ]
    }
  ) {
    id
    title
    genre
    rating
    imageUrl
  }
  actorsMatchingName: actors(where: { name: { contains: $input } }) {
    id
    name
    imageUrl
  }
  reviewsMatchingText: reviews(where: { reviewText: { contains: $input } }) {
    id
    rating
    reviewText
    reviewDate
    movie {
      id
      title
    }
    user {
      id
      username
    }
  }
}

Poin-Poin Penting:

  • Operator _and: Menggabungkan beberapa kondisi dalam satu kueri, sehingga penelusuran dapat difilter menurut beberapa kolom seperti releaseYear, rating, dan genre.
  • Operator contains: Menelusuri kecocokan teks sebagian dalam kolom. Dalam kueri ini, kueri akan mencari kecocokan dalam title, description, name, atau reviewText.
  • Klausa where: Menentukan kondisi untuk memfilter data. Setiap bagian (film, aktor, ulasan) menggunakan klausa where untuk menentukan kriteria tertentu untuk penelusuran.

Mengintegrasikan Kueri di Aplikasi Web

  1. Di MovieService (app/src/lib/MovieService.tsx), hapus tanda komentar impor berikut:
import { searchAll, SearchAllData } from "@movie/dataconnect";
  1. Ganti fungsi handleSearchAll dengan kode berikut:
// Function to perform the search using the query and filters
export const handleSearchAll = async (
  searchQuery: string,
  minYear: number,
  maxYear: number,
  minRating: number,
  maxRating: number,
  genre: string
): Promise<SearchAllData | null> => {
  try {
    const response = await searchAll({
      input: searchQuery,
      minYear,
      maxYear,
      minRating,
      maxRating,
      genre,
    });

    return response.data;
  } catch (error) {
    console.error("Error performing search:", error);
    return null;
  }
};

Poin-Poin Penting:

  • handleSearchAll: Fungsi ini menggunakan kueri searchAll untuk melakukan penelusuran berdasarkan input pengguna, memfilter hasil berdasarkan parameter seperti tahun, rating, genre, dan kecocokan teks sebagian.

Lihat Penerapannya

Buka "Penelusuran Lanjutan" dari {i>navigationbar<i} di aplikasi web. Kini Anda dapat menelusuri film, aktor, dan ulasan menggunakan berbagai filter dan input, sehingga Anda mendapatkan hasil penelusuran yang disesuaikan dan mendetail.

9. Opsional: Men-deploy ke Cloud (Penagihan Wajib)

Setelah Anda menyelesaikan iterasi pengembangan lokal, kini saatnya untuk men-deploy skema, data, dan kueri Anda ke server. Hal ini dapat dilakukan menggunakan ekstensi Firebase Data Connect VS Code atau Firebase CLI.

Menambahkan Aplikasi Web di Firebase Console

  1. Buat Aplikasi Web di Firebase Console dan catat ID Aplikasi Anda

7030822793e4d75b.png

  1. Siapkan aplikasi web di Firebase Console dengan mengklik "Add App". Untuk saat ini, Anda dapat mengabaikan penyiapan SDK dan penyiapan konfigurasi dengan aman, tetapi perhatikan objek firebaseConfig yang dihasilkan.
  2. Ganti firebaseConfig di app/src/lib/firebase.tsx:
const firebaseConfig = {
  apiKey: "API_KEY",
  authDomain: "PROJECT_ID.firebaseapp.com",
  projectId: "PROJECT_ID",
  storageBucket: "PROJECT_ID.appspot.com",
  messagingSenderId: "SENDER_ID",
  appId: "APP_ID"
};
  1. Mem-build Aplikasi Web: Di folder app, gunakan Vite untuk mem-build aplikasi web untuk deployment hosting:
cd app
npm run build

Menyiapkan Firebase Authentication di Console

  1. Menyiapkan Firebase Auth dengan Login dengan Google

62af2f225e790ef6.png

  1. (Opsional) Izinkan domain untuk (Firebase Auth) [https://firebase.google.com/docs/auth/web/hosting] di konsol project Anda (mis., http://127.0.0.1):

c255098f12549886.pngS

Men-deploy dengan Firebase CLI

  1. Di dataconnect/dataconnect.yaml, pastikan ID instance, database, dan layanan Anda cocok dengan project Anda:
specVersion: "v1alpha"
serviceId: "your-service-id"
location: "us-central1"
schema:
  source: "./schema"
  datasource:
    postgresql:
      database: "your-database-id"
      cloudSql:
        instanceId: "your-instance-id"
connectorDirs: ["./movie-connector"]
  1. Pastikan Anda telah menyiapkan Firebase CLI dengan project Anda
npm i -g firebase-tools
firebase login --reauth
firebase use --add
  1. Di terminal Anda, jalankan perintah berikut untuk men-deploy:
firebase deploy --only dataconnect,hosting
  1. Jalankan perintah ini untuk membandingkan perubahan skema Anda:
firebase dataconnect:sql:diff
  1. Jika perubahan tersebut dapat diterima, terapkan dengan:
firebase dataconnect:sql:migrate

Instance Cloud SQL untuk PostgreSQL Anda akan diperbarui dengan skema dan data akhir yang di-deploy. Anda dapat memantau statusnya di Firebase Console.

Sekarang Anda dapat melihat aplikasi yang aktif di your-project.web.app/. Selain itu, Anda dapat mengklik Run (Production) di panel Firebase Data Connect, seperti yang Anda lakukan dengan emulator lokal, untuk menambahkan data ke lingkungan produksi.

10. Opsional: Penelusuran Vektor dengan Firebase Data Connect

Di bagian ini, Anda akan mengaktifkan penelusuran vektor di aplikasi ulasan film menggunakan Firebase Data Connect. Fitur ini memungkinkan penelusuran berbasis konten, seperti menemukan film dengan deskripsi yang mirip menggunakan embedding vektor.

4b5aca5a447d2feb.pngS

Memperbarui Skema untuk Menyertakan Embedding untuk Kolom

  1. Di dataconnect/schema/schema.gql, tambahkan kolom descriptionEmbedding ke tabel Movie:
type Movie
  # The below parameter values are generated by default with @table, and can be edited manually.
  @table {
  # implicitly calls @col to generates a column name. ex: @col(name: "movie_id")
  id: UUID! @default(expr: "uuidV4()")
  title: String!
  imageUrl: String!
  releaseYear: Int
  genre: String
  rating: Float
  description: String
  tags: [String]
  descriptionEmbedding: Vector @col(size:768) # Enables vector search
}

Poin Penting:

  • descriptionEmbedding: Vector @col(size:768): Kolom ini menyimpan penyematan semantik deskripsi film, yang memungkinkan penelusuran konten berbasis vektor di aplikasi Anda.

Mengaktifkan Vertex AI

  1. Ikuti panduan prasyarat untuk menyiapkan Vertex AI API dengan Google Cloud. Langkah ini penting untuk mendukung fungsi pembuatan penyematan dan penelusuran vektor.
  2. Deploy ulang skema Anda untuk mengaktifkan pgvector dan penelusuran vektor dengan mengklik Deploy to Production menggunakan ekstensi VSCode Firebase Data Connect.

Mengisi Database dengan Penyematan

  1. Buka folder dataconnect di VSCode dan klik Run(local) di optional_vector_embed.gql untuk mengisi database dengan penyematan untuk film.

b858da780f6ec103.pngS

Menambahkan Kueri Penelusuran Vektor

  1. Di dataconnect/movie-connector/queries.gql, tambahkan kueri berikut untuk melakukan penelusuran vektor:
# Search movie descriptions using L2 similarity with Vertex AI
query SearchMovieDescriptionUsingL2Similarity($query: String!)
@auth(level: PUBLIC) {
  movies_descriptionEmbedding_similarity(
    compare_embed: { model: "textembedding-gecko@003", text: $query }
    method: L2
    within: 2
    limit: 5
  ) {
    id
    title
    description
    tags
    rating
    imageUrl
  }
}

Poin-Poin Penting:

  • compare_embed: Menentukan model penyematan (textembedding-gecko@003) dan teks input ($query) untuk perbandingan.
  • method: Menentukan metode kemiripan (L2), yang mewakili jarak Euclidean.
  • within: Membatasi penelusuran pada film dengan jarak L2 2 atau kurang, dengan fokus pada kecocokan konten yang dekat.
  • limit: Membatasi jumlah hasil yang ditampilkan, yaitu 5.

Mengimplementasikan Fungsi Penelusuran Vektor di Aplikasi

  1. Di app/src/lib/MovieService.ts, hapus tanda komentar pada impor berikut:

Mengimplementasikan Vector Search Function dalam aplikasi

Setelah skema dan kueri disiapkan, integrasikan penelusuran vektor ke dalam lapisan layanan aplikasi Anda. Langkah ini memungkinkan Anda memanggil kueri penelusuran dari aplikasi web.

Di app/src/lib/ MovieService.ts, hapus tanda komentar impor berikut dari SDK, ini akan berfungsi seperti kueri lainnya.

import {
  searchMovieDescriptionUsingL2similarity,
  SearchMovieDescriptionUsingL2similarityData,
} from "@movie/dataconnect";

Tambahkan fungsi berikut untuk mengintegrasikan penelusuran berbasis vektor ke dalam aplikasi:

// Perform vector-based search for movies based on description
export const searchMoviesByDescription = async (
  query: string
): Promise<
  | SearchMovieDescriptionUsingL2similarityData["movies_descriptionEmbedding_similarity"]
  | null
> => {
  try {
    const response = await searchMovieDescriptionUsingL2similarity({ query });
    return response.data.movies_descriptionEmbedding_similarity;
  } catch (error) {
    console.error("Error fetching movie descriptions:", error);
    return null;
  }
};


Poin-Poin Penting:

  • searchMoviesByDescription: Fungsi ini memanggil kueri searchMovieDescriptionUsingL2similarity, yang meneruskan teks input untuk melakukan penelusuran konten berbasis vektor.

Lihat Penerapannya

Navigasikan ke "Penelusuran Vektor" di menu navigasi dan ketik frasa seperti "romantis dan modern". Anda akan melihat daftar film yang cocok dengan konten yang Anda telusuri, atau, buka halaman detail film dari film mana pun, dan lihat bagian film serupa di bagian bawah halaman.

7b71f1c75633c1be.png

11. Kesimpulan

Selamat, Anda seharusnya dapat menggunakan aplikasi web. Jika Anda ingin menggunakan data film Anda sendiri, jangan khawatir, masukkan data Anda sendiri menggunakan ekstensi FDC dengan meniru file _insert.gql, atau tambahkan melalui panel Eksekusi Data Connect.

Pelajari lebih lanjut