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 mem-build aplikasi web ulasan film. Aplikasi yang telah selesai menunjukkan cara Firebase Data Connect menyederhanakan proses pembuatan aplikasi yang didukung SQL. Fitur ini mencakup:

  • Autentikasi: Terapkan autentikasi kustom untuk kueri dan mutasi aplikasi Anda, sehingga memastikan hanya pengguna yang diotorisasi 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: Ambil, perbarui, dan kelola 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.

Hal yang akan Anda pelajari

  • Menyiapkan 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.
  • Men-deploy skema dan mengelola database secara efisien.

Hal yang akan Anda perlukan

2. Menyiapkan lingkungan pengembangan

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

  1. Clone repositori project dan instal dependensi yang diperlukan:
    git clone https://github.com/firebaseextended/codelab-dataconnect-web
    cd codelab-dataconnect-web
    cd ./app && npm i
    npm run dev
    
  2. 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
  3. Buka folder codelab-dataconnect-web yang di-clone menggunakan Visual Studio Code. Di sinilah Anda akan menentukan skema, menulis kueri, dan menguji fungsi aplikasi.
  4. Untuk menggunakan fitur Data Connect, instal Ekstensi Visual Studio Firebase Data Connect.
    Atau, Anda dapat menginstal ekstensi dari Visual Studio Code Marketplace atau menelusurinya dalam VS Code.b03ee38c9a81b648.png
  5. Buka atau buat project Firebase baru di Firebase console.
  6. Hubungkan project Firebase Anda ke ekstensi VSCode Firebase Data Connect. Di ekstensi, lakukan hal berikut:
    1. Klik tombol Login.
    2. Klik Connect a Firebase Project dan pilih project Firebase Anda.
    4bb2fbf8f9fac29b.png
  7. Mulai emulator Firebase menggunakan ekstensi VS Code Firebase Data Connect:
    Klik Start Emulators, lalu pastikan emulator berjalan di terminal.6d3d95f4cb708db1.png

3. Meninjau codebase awal

Di bagian ini, Anda akan mempelajari area utama codebase awal aplikasi. Meskipun aplikasi ini tidak memiliki beberapa fungsi, sebaiknya pahami struktur keseluruhannya.

Struktur folder dan file

Subbagian berikut memberikan ringkasan struktur folder dan file aplikasi.

Direktori dataconnect/

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

Direktori app/src/

Berisi logika aplikasi dan interaksi dengan Firebase Data Connect.

  • firebase.ts: Konfigurasi untuk terhubung ke Aplikasi Firebase di project Firebase Anda.
  • lib/dataconnect-sdk/: 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.

4. 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 dibuat menggunakan Firebase Data Connect dan perintah skema GraphQL. Setelah diterapkan, aplikasi Anda akan siap menangani segala hal, mulai dari menelusuri film dengan rating teratas dan memfilter menurut genre hingga memungkinkan 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. Jenis FavoriteMovie memungkinkan pengguna memfavoritkan film, sehingga aplikasi dapat menampilkan daftar favorit yang dipersonalisasi dan menyoroti pilihan populer.

Menyiapkan tabel Movie

Jenis Movie menentukan struktur utama untuk entity film, termasuk kolom seperti title, genre, releaseYear, 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()").

Menyiapkan tabel MovieMetadata

Jenis MovieMetadata menetapkan hubungan satu-ke-satu dengan jenis Movie. Data 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.

Menyiapkan tabel Actor

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, sehingga membentuk hubungan many-to-many.

Menyiapkan tabel MovieActor

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 "pendukung").

Menyiapkan tabel User

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
}

Menyiapkan tabel FavoriteMovie

Jenis FavoriteMovie adalah tabel join yang menangani hubungan many-to-many antara pengguna dan film 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 Movie, secara implisit menghasilkan kunci asing movieId: UUID!.
  • user: Mereferensikan jenis pengguna, secara implisit menghasilkan kunci asing userId: UUID!.

Menyiapkan tabel Review

Jenis Review mewakili entity ulasan dan menautkan jenis User dan Movie 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 ditinjau.
  • reviewDate: Otomatis ditetapkan ke waktu saat ulasan dibuat menggunakan @default(expr: "request.time").

Kolom dan 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 Movie dan Review akan otomatis diisi dengan UUID saat data baru dibuat.

Setelah skema ditentukan, aplikasi film Anda memiliki dasar yang kuat untuk struktur dan hubungan datanya.

5. Mengambil film teratas 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 tiruan

  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 database Anda.
    e424f75e63bf2e10.png
  3. Periksa terminal Data Connect Execution untuk mengonfirmasi bahwa data berhasil ditambahkan.
    e0943d7704fb84ea.png

Menerapkan 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 (misalnya, id, title, releaseYear). Namun, kueri ini tidak mengurutkan film.
  2. Ganti kueri ListMovies yang ada dengan kueri berikut 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
      }
    }
    
  3. Klik tombol Run (local) untuk menjalankan kueri terhadap database lokal Anda. Anda juga dapat memasukkan variabel kueri di panel konfigurasi sebelum menjalankannya.
    c4d947115bb11b16.png

Poin-Poin Penting:

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

Mengintegrasikan kueri di aplikasi web

Di bagian codelab 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 (khususnya, schema.gql, queries.gql, mutations.gql) dan file connector.yaml. SDK ini dapat langsung dipanggil di 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 semua SDK yang dihasilkan oleh emulator Firebase Data Connect berdasarkan skema dan kueri yang telah Anda tentukan sebelumnya .
  2. 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 terbaru di halaman beranda aplikasi.

Lihat cara kerjanya

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.

6. Menampilkan detail film dan aktor

Di bagian ini, Anda akan menerapkan 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

Menerapkan 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
        }
      }
    }
    
  3. Simpan perubahan dan tinjau kueri.

Poin-Poin Penting:

  • movie()/actor(): Kolom kueri GraphQL untuk mengambil satu film atau aktor dari tabel Movies atau Actors.
  • _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 banyak-ke-banyak melalui tabel join. Misalnya, actors_via_MovieActor mengakses jenis Actor melalui tabel join MovieActor, dan kondisi where memfilter aktor berdasarkan perannya (misalnya, "utama" atau "pendukung").

Menguji kueri dengan memasukkan data tiruan

  1. Di panel eksekusi Data Connect, Anda dapat menguji kueri dengan memasukkan ID tiruan, seperti:
    {"id": "550e8400-e29b-41d4-a716-446655440000"}
    
  2. 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";
    
  2. 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 dibuat 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 di aplikasi.

Lihat cara kerjanya

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.

7. 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.png

Menerapkan 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-Poin Penting:

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

Mengambil pengguna saat ini

  1. Buka queries.gql di dataconnect/movie-connector/.
  2. 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.
  • Kolom _on_: Kolom ini mewakili tabel join:
    • reviews_on_user: Mengambil semua ulasan yang terkait dengan pengguna, termasuk id dan title film.
    • favorite_movies_on_user: Mengambil semua film yang ditandai sebagai favorit oleh pengguna, termasuk informasi mendetail seperti genre, releaseYear, 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";
    
  2. 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, tindakan ini akan 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 cara kerjanya

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

8. Mengimplementasikan interaksi pengguna

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

b3d0ac1e181c9de9.png

Memungkinkan pengguna memfavoritkan film

Di bagian ini, Anda akan menyiapkan database untuk memungkinkan pengguna memfavoritkan film.

Menerapkan 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, untuk memastikan bahwa hanya data pengguna yang diautentikasi yang diakses atau diubah.

Memeriksa apakah film difavoritkan

  1. 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 yang 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";
    
  2. 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 cara kerjanya

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.

Mengizinkan pengguna memberikan atau menghapus ulasan

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

Menerapkan konektor

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 bahwa 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";
    
  2. 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, dengan menautkan ulasan tersebut ke pengguna yang diautentikasi dengan aman.
  • handleDeleteReview: Menggunakan mutasi deleteReview untuk menghapus ulasan film oleh pengguna yang diautentikasi.

Lihat cara kerjanya

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.

9. 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

Menerapkan 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";
    
  2. 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 cara kerjanya

Buka halaman "Penelusuran Lanjutan" dari menu navigasi di aplikasi web. Sekarang Anda dapat menelusuri film, aktor, dan ulasan menggunakan berbagai filter dan input, sehingga mendapatkan hasil penelusuran yang mendetail dan disesuaikan.

10. Opsional: Men-deploy ke Cloud (penagihan diperlukan)

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

Mengupgrade paket harga Firebase

Untuk mengintegrasikan Firebase Data Connect dengan Cloud SQL untuk PostgreSQL, project Firebase Anda harus menggunakan paket harga bayar sesuai penggunaan (Blaze), yang berarti project tersebut ditautkan ke akun Penagihan Cloud.

  • Akun Penagihan Cloud memerlukan metode pembayaran, seperti kartu kredit.
  • Jika Anda baru menggunakan Firebase dan Google Cloud, periksa apakah Anda memenuhi syarat untuk mendapatkan kredit sebesar$300 dan akun Penagihan Cloud Uji Coba Gratis.
  • Jika Anda melakukan codelab ini sebagai bagian dari acara, tanyakan kepada penyelenggara apakah ada kredit Cloud yang tersedia.

Untuk mengupgrade project Anda ke paket Blaze, ikuti langkah-langkah berikut:

  1. Di Firebase console, pilih upgrade your plan.
  2. Pilih paket Blaze. Ikuti petunjuk di layar untuk menautkan akun Penagihan Cloud ke project Anda.
    Jika perlu membuat akun Penagihan Cloud sebagai bagian dari upgrade ini, Anda mungkin perlu kembali ke alur upgrade di Firebase console untuk menyelesaikan upgrade.

Menghubungkan aplikasi web ke project Firebase

  1. Daftarkan aplikasi web Anda di project Firebase menggunakan Firebase console:
    1. Buka project Anda, lalu klik Tambahkan Aplikasi.
    2. Abaikan penyiapan SDK dan penyiapan konfigurasi untuk saat ini, tetapi pastikan untuk menyalin objek firebaseConfig yang dihasilkan.
    7030822793e4d75b.png
  2. Ganti firebaseConfig yang ada di app/src/lib/firebase.tsx dengan konfigurasi yang baru saja Anda salin dari Firebase console.
    const firebaseConfig = {
      apiKey: "API_KEY",
      authDomain: "PROJECT_ID.firebaseapp.com",
      projectId: "PROJECT_ID",
      storageBucket: "PROJECT_ID.firebasestorage.app",
      messagingSenderId: "SENDER_ID",
      appId: "APP_ID"
    };
    
  3. Mem-build aplikasi web: Kembali ke VS Code, di folder app, gunakan Vite untuk mem-build aplikasi web untuk deployment hosting:
    cd app
    npm run build
    

Menyiapkan Firebase Authentication di project Firebase Anda

  1. Siapkan Firebase Authentication dengan Login dengan Google.62af2f225e790ef6.png
  2. (Opsional) Izinkan domain untuk Firebase Authentication menggunakan Firebase console (misalnya, http://127.0.0.1).
    1. Di setelan Authentication, buka Authorized Domains.
    2. Klik "Tambahkan Domain" dan sertakan domain lokal Anda dalam daftar.

c255098f12549886.png

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"]
    
  2. Pastikan Anda telah menyiapkan Firebase CLI dengan project Anda:
    npm i -g firebase-tools
    firebase login --reauth
    firebase use --add
    
  3. Di terminal, jalankan perintah berikut untuk men-deploy:
    firebase deploy --only dataconnect,hosting
    
  4. Jalankan perintah ini untuk membandingkan perubahan skema Anda:
    firebase dataconnect:sql:diff
    
  5. 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.

11. Opsional: Penelusuran vektor dengan Firebase Data Connect (penagihan diperlukan)

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 serupa menggunakan penyematan vektor.

Langkah ini mengharuskan Anda menyelesaikan langkah terakhir codelab ini untuk men-deploy ke Google Cloud.

4b5aca5a447d2feb.png

Memperbarui skema untuk menyertakan penyematan untuk kolom

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-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 dari 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 VS Code Firebase Data Connect.

Mengisi database dengan penyematan

  1. Buka folder dataconnect di VS Code.
  2. Klik Run(local) di optional_vector_embed.gql untuk mengisi database Anda dengan penyematan untuk film.

b858da780f6ec103.png

Menambahkan kueri penelusuran vektor

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 kesamaan (L2), yang mewakili jarak Euclidean.
  • within: Membatasi penelusuran ke film dengan jarak L2 2 atau kurang, yang berfokus pada kecocokan konten yang dekat.
  • limit: Membatasi jumlah hasil yang ditampilkan menjadi 5.

Mengimplementasikan fungsi penelusuran vektor di aplikasi Anda

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

  1. 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";
    
  2. 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 cara kerjanya

Buka bagian "Vector Search" di menu navigasi samping, lalu 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

12. Kesimpulan

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

Pelajari lebih lanjut