Cara Membuat Aplikasi Real-Time Dengan Langganan GraphQL Di Postgres

Diterbitkan: 2022-03-10
Ringkasan cepat Membangun aplikasi waktu nyata itu sulit. Namun, GraphQL dengan cepat mengubah status quo ini. Mari kita telusuri apa itu GraphQL, lalu mencobanya dengan membangun aplikasi polling di mana pengguna dapat memilih dan hasil agregat di layar diperbarui secara real time.

Dalam artikel ini, kita akan melihat tantangan yang terlibat dalam membangun aplikasi real-time dan bagaimana perkakas yang muncul menanganinya dengan solusi elegan yang mudah untuk dipikirkan. Untuk melakukan ini, kami akan membangun aplikasi polling waktu nyata (seperti polling Twitter dengan statistik keseluruhan waktu nyata) hanya dengan menggunakan Postgres, GraphQL, React, dan tanpa kode backend!

Fokus utama adalah pada pengaturan backend (menyebarkan alat siap pakai, pemodelan skema), dan aspek integrasi frontend dengan GraphQL dan lebih sedikit pada UI/UX dari frontend (beberapa pengetahuan tentang ReactJS akan membantu). Bagian tutorial akan mengambil pendekatan paint-by-numbers, jadi kami hanya akan mengkloning repo GitHub untuk pemodelan skema, dan UI dan mengubahnya, alih-alih membangun seluruh aplikasi dari awal.

Semua Hal GraphQL

Apakah Anda tahu semua yang perlu Anda ketahui tentang GraphQL? Jika Anda ragu, Eric Baer telah memberikan Anda panduan terperinci tentang asal-usulnya, kekurangannya, dan dasar-dasar cara bekerja dengannya. Baca artikel terkait →

Sebelum Anda melanjutkan membaca artikel ini, saya ingin menyebutkan bahwa pengetahuan tentang teknologi berikut (atau penggantinya) bermanfaat:

  • ReactJS
    Ini dapat diganti dengan kerangka kerja frontend apa pun, Android atau iOS dengan mengikuti dokumentasi pustaka klien.
  • Postgres
    Anda dapat bekerja dengan database lain tetapi dengan alat yang berbeda, prinsip-prinsip yang diuraikan dalam posting ini akan tetap berlaku.

Anda juga dapat menyesuaikan konteks tutorial ini untuk aplikasi waktu nyata lainnya dengan sangat mudah.

Demonstrasi fitur dalam aplikasi polling yang dibuat dalam tutorial ini
Demonstrasi fitur dalam aplikasi polling yang akan kami buat. (Pratinjau besar)

Seperti yang diilustrasikan oleh muatan GraphQL yang menyertai di bagian bawah, ada tiga fitur utama yang perlu kita terapkan:

  1. Ambil pertanyaan polling dan daftar opsi (kiri atas).
  2. Izinkan pengguna untuk memilih pertanyaan jajak pendapat yang diberikan (tombol "Pilih").
  3. Ambil hasil jajak pendapat secara real-time dan tampilkan dalam grafik batang (kanan atas; kita dapat mengabaikan fitur untuk mengambil daftar pengguna online saat ini karena ini adalah replika yang tepat dari kasus penggunaan ini).
Lebih banyak setelah melompat! Lanjutkan membaca di bawah ini

Tantangan Dengan Membangun Aplikasi Real-Time

Membangun aplikasi real-time (terutama sebagai pengembang frontend atau seseorang yang baru saja melakukan transisi untuk menjadi pengembang fullstack), adalah masalah rekayasa yang sulit untuk dipecahkan. Ini umumnya cara kerja aplikasi real-time kontemporer (dalam konteks aplikasi contoh kami):

  1. Frontend memperbarui database dengan beberapa informasi; Suara pengguna dikirim ke backend, yaitu polling/opsi dan informasi pengguna ( user_id , option_id ).
  2. Pembaruan pertama memicu layanan lain yang menggabungkan data polling untuk membuat output yang diteruskan kembali ke aplikasi secara real-time (setiap kali voting baru diberikan oleh siapa pun; jika ini dilakukan secara efisien, hanya data polling yang diperbarui yang diproses dan hanya klien yang telah berlangganan polling ini yang diperbarui):
    • Data suara pertama kali diproses oleh layanan register_vote (anggap bahwa beberapa validasi terjadi di sini) yang memicu layanan poll_results .
    • Data polling agregat real-time disampaikan oleh layanan poll_results ke frontend untuk menampilkan statistik keseluruhan.
Desain tradisional untuk aplikasi polling waktu nyata
Aplikasi polling yang dirancang secara tradisional

Model ini diturunkan dari pendekatan pembuatan API tradisional, dan akibatnya memiliki masalah serupa:

  1. Salah satu langkah berurutan bisa salah, membiarkan UX menggantung dan memengaruhi operasi independen lainnya.
  2. Memerlukan banyak upaya pada lapisan API karena merupakan titik kontak tunggal untuk aplikasi frontend, yang berinteraksi dengan beberapa layanan. Itu juga perlu menerapkan API real-time berbasis soket web — tidak ada standar universal untuk ini dan karena itu melihat dukungan terbatas untuk otomatisasi dalam alat.
  3. Aplikasi frontend diperlukan untuk menambahkan pipa yang diperlukan untuk menggunakan API real-time dan mungkin juga harus memecahkan masalah konsistensi data yang biasanya terlihat di aplikasi real-time (kurang penting dalam contoh yang kami pilih, tetapi penting dalam memesan pesan secara real-time). -waktu aplikasi obrolan).
  4. Banyak implementasi menggunakan basis data non-relasional tambahan di sisi server (Firebase, dll.) untuk dukungan API real-time yang mudah.

Mari kita lihat bagaimana GraphQL dan perkakas terkait mengatasi tantangan ini.

Apa itu GraphQL?

GraphQL adalah spesifikasi bahasa kueri untuk API, dan runtime sisi server untuk mengeksekusi kueri. Spesifikasi ini dikembangkan oleh Facebook untuk mempercepat pengembangan aplikasi dan menyediakan format akses data agnostik database yang terstandarisasi. Setiap server GraphQL yang sesuai spesifikasi harus mendukung yang berikut ini:

  1. Pertanyaan untuk dibaca
    Jenis permintaan untuk meminta data bersarang dari sumber data (yang dapat berupa salah satu atau kombinasi database, REST API, atau skema/server GraphQL lainnya).
  2. Mutasi untuk menulis
    Jenis permintaan untuk menulis/menyampaikan data ke sumber data yang disebutkan di atas.
  3. Berlangganan untuk pertanyaan langsung
    Jenis permintaan bagi klien untuk berlangganan pembaruan waktu nyata.

GraphQL juga menggunakan skema yang diketik. Ekosistem ini memiliki banyak alat yang membantu Anda mengidentifikasi kesalahan pada waktu pengembangan/kompilasi yang menghasilkan lebih sedikit bug runtime.

Inilah mengapa GraphQL sangat bagus untuk aplikasi waktu nyata:

  • Kueri langsung (langganan) adalah bagian implisit dari spesifikasi GraphQL. Setiap sistem GraphQL harus memiliki kemampuan API real-time asli.
  • Spesifikasi standar untuk kueri waktu nyata telah mengkonsolidasikan upaya komunitas seputar perkakas sisi klien, menghasilkan cara integrasi yang sangat intuitif dengan GraphQL API.

GraphQL dan kombinasi alat open-source untuk kejadian database dan fungsi tanpa server/cloud menawarkan substrat yang bagus untuk membangun aplikasi cloud-native dengan logika bisnis asinkron dan fitur real-time yang mudah dibuat dan dikelola. Paradigma baru ini juga menghasilkan pengalaman pengguna dan pengembang yang luar biasa.

Di sisa artikel ini, saya akan menggunakan alat sumber terbuka untuk membangun aplikasi berdasarkan diagram arsitektur ini:

Desain berbasis GraphQL untuk aplikasi polling waktu nyata
Aplikasi polling yang dirancang dengan GraphQL

Membangun Aplikasi Jajak Pendapat/Voting Waktu Nyata

Dengan pengenalan GraphQL itu, mari kembali membangun aplikasi polling seperti yang dijelaskan di bagian pertama.

Tiga fitur (atau cerita yang disorot) telah dipilih untuk mendemonstrasikan berbagai jenis permintaan GraphQL yang akan dibuat oleh aplikasi kita:

  1. Pertanyaan
    Ambil pertanyaan polling dan opsinya.
  2. Mutasi
    Biarkan pengguna memberikan suara.
  3. Berlangganan
    Menampilkan dasbor waktu nyata untuk hasil polling.
Elemen GraphQL di aplikasi polling
Jenis permintaan GraphQL di aplikasi polling (Pratinjau besar)

Prasyarat

  • Akun Heroku (gunakan tingkat gratis, tidak perlu kartu kredit)
    Untuk menerapkan backend GraphQL (lihat poin berikutnya di bawah) dan instance Postgres.
  • Hasura GraphQL Engine (gratis, sumber terbuka)
    Server GraphQL yang siap digunakan di Postgres.
  • Klien Apollo (SDK sumber terbuka gratis)
    Untuk mengintegrasikan aplikasi klien dengan server GraphQL dengan mudah.
  • npm (pengelola paket sumber terbuka gratis)
    Untuk menjalankan aplikasi React kami.

Menyebarkan Database Dan Backend GraphQL

Kami akan menerapkan masing-masing instance Postgres dan GraphQL Engine di tingkat gratis Heroku. Kita dapat menggunakan tombol Heroku yang bagus untuk melakukan ini dengan satu klik.

Tombol Heroku
Tombol Heroku

Catatan: Anda juga dapat mengikuti tautan ini atau mencari dokumentasi penyebaran Hasura GraphQL untuk Heroku (atau platform lain).

Menyebarkan backend aplikasi ke tingkat gratis Heroku
Menyebarkan Postgres dan GraphQL Engine ke tingkat gratis Heroku (Pratinjau besar)

Anda tidak memerlukan konfigurasi tambahan, dan Anda cukup mengeklik tombol “Deploy app”. Setelah penerapan selesai, catat URL aplikasi:

 <app-name>.herokuapp.com

Misalnya, pada tangkapan layar di atas, itu akan menjadi:

 hge-realtime-app-tutorial.herokuapp.com

Apa yang telah kami lakukan sejauh ini adalah menerapkan instance Postgres (sebagai add-on dalam bahasa Heroku) dan instance GraphQL Engine yang dikonfigurasi untuk menggunakan instance Postgres ini. Sebagai hasil dari melakukannya, kami sekarang memiliki GraphQL API yang siap digunakan tetapi, karena kami tidak memiliki tabel atau data dalam database kami, ini belum berguna. Jadi, mari kita atasi ini segera.

Memodelkan skema database

Diagram skema berikut menangkap skema database relasional sederhana untuk aplikasi polling kami:

Desain skema untuk aplikasi polling
Desain skema untuk aplikasi polling. (Pratinjau besar)

Seperti yang Anda lihat, skemanya sederhana, dinormalisasi yang memanfaatkan batasan kunci asing. Batasan inilah yang ditafsirkan oleh Mesin GraphQL sebagai hubungan 1:1 atau 1: banyak (misalnya poll:options adalah hubungan 1: banyak karena setiap poll akan memiliki lebih dari 1 opsi yang dihubungkan oleh batasan kunci asing antara kolom id dari tabel poll dan kolom poll_id di tabel option ). Data terkait dapat dimodelkan sebagai grafik dan dengan demikian dapat memberi daya pada GraphQL API. Inilah tepatnya yang dilakukan GraphQL Engine.

Berdasarkan hal di atas, kita harus membuat tabel dan batasan berikut untuk memodelkan skema kita:

  1. Poll
    Tabel untuk menangkap pertanyaan polling.
  2. Option
    Pilihan untuk setiap jajak pendapat.
  3. Vote
    Untuk merekam suara pengguna.
  4. Batasan kunci asing antara bidang berikut ( table : column ):
    • option : poll_id → poll : id
    • vote : poll_id → poll : id
    • vote : created_by_user_id → user : id

Sekarang setelah kita memiliki desain skema, mari kita implementasikan di database Postgres kita. Untuk memunculkan skema ini secara instan, inilah yang akan kita lakukan:

  1. Unduh CLI Mesin GraphQL.
  2. Kloning repo ini:
     $ git clone clone https://github.com/hasura/graphql-engine $ cd graphql-engine/community/examples/realtime-poll
  3. Pergi ke hasura/ dan edit config.yaml :
     endpoint: https://<app-name>.herokuapp.com
  4. Terapkan migrasi menggunakan CLI, dari dalam direktori proyek (yang baru saja Anda unduh dengan kloning):
     $ hasura migrate apply

Itu saja untuk backendnya. Anda sekarang dapat membuka konsol GraphQL Engine dan memeriksa apakah semua tabel ada (konsol tersedia di https://<app-name>.herokuapp.com/console ).

Catatan: Anda juga bisa menggunakan konsol untuk mengimplementasikan skema dengan membuat tabel individual lalu menambahkan batasan menggunakan UI. Menggunakan dukungan bawaan untuk migrasi di GraphQL Engine hanyalah opsi praktis yang tersedia karena repo sampel kami memiliki migrasi untuk memunculkan tabel yang diperlukan dan mengonfigurasi hubungan/batasan (ini juga sangat disarankan terlepas dari apakah Anda sedang membangun hobi atau tidak. proyek atau aplikasi siap produksi).

Mengintegrasikan Aplikasi React Frontend Dengan Backend GraphQL

Tampilan depan dalam tutorial ini adalah aplikasi sederhana yang menampilkan pertanyaan polling, opsi untuk memilih, dan hasil polling gabungan di satu tempat. Seperti yang saya sebutkan sebelumnya, pertama-tama kami akan fokus menjalankan aplikasi ini sehingga Anda mendapatkan kepuasan instan menggunakan GraphQL API kami yang baru-baru ini digunakan, lihat bagaimana konsep GraphQL yang kami lihat sebelumnya dalam artikel ini mendukung berbagai kasus penggunaan aplikasi semacam itu , lalu jelajahi cara kerja integrasi GraphQL.

CATATAN: Jika Anda baru mengenal ReactJS, Anda mungkin ingin membaca beberapa artikel ini. Kami tidak akan membahas detail bagian React dari aplikasi, dan sebaliknya, akan lebih fokus pada aspek GraphQL dari aplikasi. Anda dapat merujuk ke kode sumber di repo untuk detail apa pun tentang bagaimana aplikasi React dibangun .

Mengonfigurasi Aplikasi Frontend

  1. Di repo yang dikloning di bagian sebelumnya, edit HASURA_GRAPHQL_ENGINE_HOSTNAME di file src/apollo.js (di dalam folder /community/examples/realtime-poll ) dan setel ke URL aplikasi Heroku dari atas:
     export const HASURA_GRAPHQL_ENGINE_HOSTNAME = 'random-string-123.herokuapp.com';
  2. Buka root repositori/folder aplikasi ( /realtime-poll/ ) dan gunakan npm untuk menginstal modul psyarat dan kemudian jalankan aplikasi:
     $ npm install $ npm start 
Tangkapan layar aplikasi polling langsung
Tangkapan layar aplikasi polling langsung (Pratinjau besar)

Anda seharusnya dapat bermain-main dengan aplikasi sekarang. Silakan dan pilih sebanyak yang Anda inginkan, Anda akan melihat hasilnya berubah secara real time. Bahkan, jika Anda menyiapkan instance lain dari UI ini dan mengarahkannya ke backend yang sama, Anda akan dapat melihat hasil yang dikumpulkan di semua instance.

Jadi, bagaimana aplikasi ini menggunakan GraphQL? Baca terus.

Di Balik Layar: GraphQL

Di bagian ini, kita akan menjelajahi fitur GraphQL yang mendukung aplikasi, diikuti dengan demonstrasi kemudahan integrasi di bagian berikutnya.

Komponen Poll Dan Grafik Hasil Gabungan

Komponen poll di kiri atas yang mengambil polling dengan semua opsinya dan menangkap suara pengguna di database. Kedua operasi ini dilakukan menggunakan GraphQL API. Untuk mengambil detail jajak pendapat, kami membuat kueri (ingat ini dari pengantar GraphQL?):

 query { poll { id question options { id text } } }

Dengan menggunakan komponen Mutation dari react-apollo , kita dapat menghubungkan mutasi ke formulir HTML sehingga mutasi dijalankan menggunakan variabel optionId dan userId saat formulir dikirimkan:

 mutation vote($optionId: uuid!, $userId: uuid!) { insert_vote(objects: [{option_id: $optionId, created_by_user_id: $userId}]) { returning { id } } }

Untuk menampilkan hasil polling, kita perlu menurunkan jumlah suara per opsi dari data di tabel suara. Kita dapat membuat Tampilan Postgres dan melacaknya menggunakan GraphQL Engine untuk membuat data turunan ini tersedia melalui GraphQL.

 CREATE VIEW poll_results AS SELECT poll.id AS poll_id, o.option_id, count(*) AS votes FROM (( SELECT vote.option_id, option.poll_id, option.text FROM ( vote LEFT JOIN public.option ON ((option.id = vote.option_id)))) o LEFT JOIN poll ON ((poll.id = o.poll_id))) GROUP BY poll.question, o.option_id, poll.id;

Tampilan poll_results menggabungkan data dari tabel pemungutan vote dan poll untuk memberikan penghitungan agregat jumlah suara per setiap opsi.

Menggunakan GraphQL Subscriptions pada tampilan ini, react-google-charts dan komponen langganan dari react-apollo , kami dapat memasang diagram reaktif yang diperbarui secara realtime ketika pemungutan suara baru terjadi dari klien mana pun.

 subscription getResult($pollId: uuid!) { poll_results(where: {poll_id: {_eq: $pollId}}) { option { id text } votes } }

Integrasi API GraphQL

Seperti yang saya sebutkan sebelumnya, saya menggunakan Apollo Client, SDK open-source untuk mengintegrasikan aplikasi ReactJS dengan backend GraphQL. Apollo Client analog dengan pustaka klien HTTP apa pun seperti permintaan untuk python, modul http standar untuk JavaScript, dan sebagainya. Ini merangkum detail pembuatan permintaan HTTP (dalam hal ini permintaan POST). Ia menggunakan konfigurasi (ditentukan dalam src/apollo.js ) untuk membuat permintaan/mutasi/langganan permintaan (ditentukan dalam src/GraphQL.jsx dengan opsi untuk menggunakan variabel yang dapat diganti secara dinamis dalam kode JavaScript dari aplikasi REACT Anda) untuk titik akhir GraphQL. Itu juga memanfaatkan skema yang diketik di belakang titik akhir GraphQL untuk memberikan validasi waktu kompilasi/pengembangan untuk permintaan yang disebutkan di atas. Mari kita lihat betapa mudahnya aplikasi klien membuat permintaan langsung (langganan) ke GraphQL API.

Mengonfigurasi SDK

Apollo Client SDK perlu diarahkan ke server GraphQL, sehingga dapat secara otomatis menangani kode boilerplate yang biasanya diperlukan untuk integrasi semacam itu. Jadi, inilah tepatnya yang kami lakukan saat kami memodifikasi src/apollo.js saat menyiapkan aplikasi frontend.

Membuat Permintaan Berlangganan GraphQL (Live-Query)

Tentukan langganan yang kita lihat di bagian sebelumnya di file src/GraphQL.jsx :

 const SUBSCRIPTION_RESULT = ` subscription getResult($pollId: uuid!) { poll_results ( order_by: option_id_desc, where: { poll_id: {_eq: $pollId} } ) { option_id option { id text } votes } }`;

Kami akan menggunakan definisi ini untuk memasang komponen React kami:

 export const Result = (pollId) => ( <Subscription subscription={gql`${SUBSCRIPTION_RESULT}`} variables={pollId}> {({ loading, error, data }) => { if (loading) return

Memuat...</p>; jika (kesalahan) kembali

Kesalahan :</p>; kembali ( <div> <div> {renderChart(data)} </div> </div> ); }} </Berlangganan> )

Satu hal yang perlu diperhatikan di sini adalah bahwa langganan di atas juga bisa berupa kueri. Mengganti satu kata kunci dengan kata kunci lainnya hanya akan memberi kami "permintaan langsung", dan hanya itu yang diperlukan Apollo Client SDK untuk menghubungkan API waktu nyata ini dengan aplikasi Anda. Setiap kali ada set data baru dari kueri langsung kami, SDK memicu rendering ulang bagan kami dengan data yang diperbarui ini (menggunakan renderChart(data) ). Itu dia. Ini benar-benar sederhana!

Pikiran Akhir

Dalam tiga langkah sederhana (membuat backend GraphQL, memodelkan skema aplikasi, dan mengintegrasikan frontend dengan GraphQL API), Anda dapat dengan cepat memasang aplikasi real-time yang berfungsi penuh, tanpa terjebak dalam detail yang tidak perlu seperti menyiapkan koneksi websocket. Itu benar ada kekuatan perkakas komunitas yang mendukung abstraksi seperti GraphQL.

Jika menurut Anda ini menarik dan ingin menjelajahi GraphQL lebih lanjut untuk proyek sampingan atau aplikasi produksi Anda berikutnya, berikut adalah beberapa faktor yang mungkin ingin Anda gunakan untuk membangun toolchain GraphQL Anda:

  • Performa & Skalabilitas
    GraphQL dimaksudkan untuk dikonsumsi langsung oleh aplikasi frontend (tidak lebih baik dari ORM di backend; manfaat produktivitas nyata datang dari melakukan ini). Jadi, perkakas Anda harus pintar dalam menggunakan koneksi database secara efisien dan harus dapat menskalakan dengan mudah.
  • Keamanan
    Oleh karena itu dari atas bahwa sistem kontrol akses berbasis peran yang matang diperlukan untuk mengotorisasi akses ke data.
  • Otomatisasi
    Jika Anda baru mengenal ekosistem GraphQL, menulis tangan skema GraphQL dan mengimplementasikan server GraphQL mungkin tampak seperti tugas yang menakutkan. Maksimalkan otomatisasi dari perkakas Anda sehingga Anda dapat fokus pada hal-hal penting seperti membangun fitur frontend yang berpusat pada pengguna.
  • Arsitektur
    Meskipun upaya di atas tampak sepele, arsitektur backend aplikasi tingkat produksi mungkin melibatkan konsep GraphQL lanjutan seperti skema-stitching, dll. Selain itu, kemampuan untuk dengan mudah menghasilkan/menggunakan API real-time membuka kemungkinan membangun asinkron, reaktif aplikasi yang tangguh dan secara inheren dapat diskalakan. Oleh karena itu, penting untuk mengevaluasi bagaimana alat GraphQL dapat merampingkan arsitektur Anda.

Sumber Daya Terkait

  • Anda dapat melihat versi langsung dari aplikasi di sini.
  • Kode sumber lengkap tersedia di GitHub.
  • Jika Anda ingin menjelajahi skema database dan menjalankan kueri GraphQL pengujian, Anda dapat melakukannya di sini.