Postgres'te GraphQL Abonelikleri ile Gerçek Zamanlı Bir Uygulama Nasıl Oluşturulur
Yayınlanan: 2022-03-10Bu makalede, gerçek zamanlı uygulamalar oluşturmanın getirdiği zorluklara ve ortaya çıkan takımların, akıl yürütmesi kolay zarif çözümlerle bunları nasıl ele aldığına bir göz atacağız. Bunu yapmak için, sadece Postgres, GraphQL, React kullanarak ve arka uç kodu olmadan gerçek zamanlı bir anket uygulaması (gerçek zamanlı genel istatistikleri olan bir Twitter anketi gibi) oluşturacağız!
Öncelikli odak, arka uç (kullanıma hazır araçları dağıtma, şema modelleme) ve GraphQL ile ön uç entegrasyonunun yönleri ve ön yüzün UI/UX'i hakkında daha az olacaktır (bazı ReactJS bilgisi yardımcı olacaktır). Eğitim bölümü, sayılara göre boyama yaklaşımını benimseyecek, bu nedenle tüm uygulamayı sıfırdan oluşturmak yerine şema modelleme ve kullanıcı arayüzü için bir GitHub deposunu klonlayacağız ve ince ayar yapacağız.
Her Şey GraphQL
GraphQL hakkında bilmeniz gereken her şeyi biliyor musunuz? Şüpheleriniz varsa, Eric Baer, kökenleri, dezavantajları ve onunla nasıl çalışacağınıza dair temel bilgiler hakkında ayrıntılı bir rehber hazırladı. İlgili bir makaleyi okuyun →
Bu makaleyi okumaya devam etmeden önce, aşağıdaki teknolojiler (veya ikameleri) hakkında çalışma bilgisinin faydalı olduğunu belirtmek isterim:
- ReactJS
Bu, istemci kitaplığı belgelerini izleyerek herhangi bir ön uç çerçevesi, Android veya IOS ile değiştirilebilir. - Postgres
Diğer veritabanlarıyla çalışabilirsiniz, ancak farklı araçlarla, bu gönderide özetlenen ilkeler yine de geçerli olacaktır.
Bu eğitim içeriğini diğer gerçek zamanlı uygulamalar için de çok kolay bir şekilde uyarlayabilirsiniz.

Altta eşlik eden GraphQL yükü ile gösterildiği gibi, uygulamamız gereken üç ana özellik vardır:
- Anket sorusunu ve seçenekler listesini getirin (sol üstte).
- Bir kullanıcının belirli bir anket sorusu için oy kullanmasına izin verin ("Oy Ver" düğmesi).
- Anketin sonuçlarını gerçek zamanlı olarak alın ve bir çubuk grafikte görüntüleyin (sağ üstte; bu kullanım durumunun tam bir kopyası olduğu için, şu anda çevrimiçi olan kullanıcıların bir listesini getirmek için özelliğin üzerinde durabiliriz).
Gerçek Zamanlı Uygulamalar Oluşturmanın Zorlukları
Gerçek zamanlı uygulamalar oluşturmak (özellikle bir ön uç geliştirici veya son zamanlarda tam yığın geliştirici olmaya geçiş yapmış biri olarak), çözülmesi zor bir mühendislik problemidir. Çağdaş gerçek zamanlı uygulamalar genellikle bu şekilde çalışır (örnek uygulamamız bağlamında):
- Ön uç, bir veritabanını bazı bilgilerle günceller; Bir kullanıcının oyu arka uca gönderilir, yani yoklama/seçenek ve kullanıcı bilgileri (
user_id
,option_id
). - İlk güncelleme, gerçek zamanlı olarak uygulamaya geri aktarılan bir çıktı oluşturmak için anket verilerini toplayan başka bir hizmeti tetikler (herhangi biri tarafından yeni bir oy verildiğinde; bu verimli bir şekilde yapılırsa, yalnızca güncellenen anketin verileri işlenir ve yalnızca bu ankete abone olan müşteriler güncellenir):
- Oy verileri ilk önce bir
poll_results
hizmetini tetikleyen birregister_vote
hizmeti tarafından işlenir (burada bazı doğrulamaların gerçekleştiğini varsayalım). - Gerçek zamanlı toplu anket verileri, genel istatistikleri görüntülemek için
poll_results
hizmeti tarafından ön uca iletilir.
- Oy verileri ilk önce bir

Bu model, geleneksel bir API oluşturma yaklaşımından türetilmiştir ve sonuç olarak benzer sorunları vardır:
- Sıralı adımlardan herhangi biri yanlış gidebilir ve UX'i askıda bırakarak diğer bağımsız işlemleri etkileyebilir.
- Birden çok hizmetle etkileşime giren ön uç uygulaması için tek bir iletişim noktası olduğundan API katmanında çok fazla çaba gerektirir. Ayrıca websockets tabanlı gerçek zamanlı bir API uygulaması gerekiyor - bunun için evrensel bir standart yok ve bu nedenle araçlarda otomasyon için sınırlı destek görüyor.
- Ön uç uygulamasının, gerçek zamanlı API'yi kullanmak için gerekli tesisatı eklemesi gerekir ve ayrıca gerçek zamanlı uygulamalarda tipik olarak görülen veri tutarlılığı sorununu çözmesi gerekebilir (seçtiğimiz örneğimizde daha az önemli, ancak mesajları gerçek zamanlı olarak sıralamak için kritiktir). -zaman sohbet uygulaması).
- Birçok uygulama, kolay gerçek zamanlı API desteği için sunucu tarafında (Firebase, vb.) ilişkisel olmayan ek veritabanları kullanmaya başvurur.
GraphQL ve ilgili araçların bu zorlukları nasıl ele aldığına bir göz atalım.
GraphQL Nedir?
GraphQL, API'ler için bir sorgu dili ve sorguları yürütmek için sunucu tarafı çalışma zamanı için bir belirtimdir. Bu belirtim, uygulama geliştirmeyi hızlandırmak ve standartlaştırılmış, veritabanından bağımsız bir veri erişim biçimi sağlamak için Facebook tarafından geliştirilmiştir. Spesifikasyonla uyumlu herhangi bir GraphQL sunucusu aşağıdakileri desteklemelidir:
- Okumalar için sorgular
Bir veri kaynağından iç içe geçmiş verileri istemek için bir istek türü (bir veritabanı, bir REST API veya başka bir GraphQL şeması/sunucusu olabilir). - yazma için mutasyonlar
Yukarıda belirtilen veri kaynaklarına veri yazmak/aktarmak için bir istek türü. - Canlı sorgular için abonelikler
İstemcilerin gerçek zamanlı güncellemelere abone olmaları için bir istek türü.
GraphQL ayrıca yazılan bir şema kullanır. Ekosistem, geliştirme/derleme zamanında hataları belirlemenize yardımcı olan ve daha az çalışma zamanı hatasıyla sonuçlanan birçok araca sahiptir.
İşte GraphQL'in gerçek zamanlı uygulamalar için harika olmasının nedeni:
- Canlı sorgular (abonelikler), GraphQL belirtiminin örtük bir parçasıdır. Herhangi bir GraphQL sisteminin yerel gerçek zamanlı API yeteneklerine sahip olması gerekir.
- Gerçek zamanlı sorgular için standart bir belirtim, topluluk çabalarını istemci tarafı araçları etrafında birleştirdi ve bu da GraphQL API'leri ile çok sezgisel bir entegrasyon yolu sağladı.
GraphQL ve veritabanı olayları ve sunucusuz/bulut işlevleri için açık kaynaklı araçların bir kombinasyonu, eşzamansız iş mantığı ve oluşturması ve yönetmesi kolay gerçek zamanlı özelliklerle bulutta yerel uygulamalar oluşturmak için harika bir alt tabaka sunar. Bu yeni paradigma aynı zamanda harika bir kullanıcı ve geliştirici deneyimi sağlar.
Bu makalenin geri kalanında, bu mimari şemasına dayalı bir uygulama oluşturmak için açık kaynaklı araçları kullanacağım:

Gerçek Zamanlı Bir Anket/Oylama Uygulaması Oluşturma
GraphQL'e bu girişle birlikte, ilk bölümde açıklandığı gibi yoklama uygulamasını oluşturmaya geri dönelim.
Uygulamamızın yapacağı farklı GraphQL istek türlerini göstermek için üç özellik (veya vurgulanan hikayeler) seçildi:
- Sorgu
Anket sorusunu ve seçeneklerini getirin. - mutasyon
Bir kullanıcının oy vermesine izin verin. - abonelik
Anket sonuçları için gerçek zamanlı bir gösterge panosu görüntüleyin.

Önkoşullar
- Bir Heroku hesabı (ücretsiz katmanı kullanın, kredi kartı gerekmez)
Bir GraphQL arka ucunu (aşağıdaki bir sonraki noktaya bakın) ve bir Postgres örneğini dağıtmak için. - Hasura GraphQL Engine (ücretsiz, açık kaynak) Postgres üzerinde kullanıma hazır bir GraphQL sunucusu.
- Apollo İstemcisi (ücretsiz, açık kaynaklı SDK)
İstemci uygulamalarını bir GraphQL sunucusuyla kolayca entegre etmek için. - npm (ücretsiz, açık kaynaklı paket yöneticisi)
React uygulamamızı çalıştırmak için.
Veritabanını ve GraphQL Arka Uçunu Dağıtma
Heroku'nun ücretsiz katmanında Postgres ve GraphQL Engine'in her birinin bir örneğini dağıtacağız. Bunu tek bir tıklamayla yapmak için şık bir Heroku düğmesi kullanabiliriz.

Not: Ayrıca bu bağlantıyı takip edebilir veya Heroku (veya diğer platformlar) için Hasura GraphQL dağıtımı belgelerini arayabilirsiniz.

Herhangi bir ek yapılandırmaya ihtiyacınız olmayacak ve "Uygulamayı dağıt" düğmesine tıklamanız yeterli. Dağıtım tamamlandıktan sonra uygulama URL'sini not edin:
<app-name>.herokuapp.com
Örneğin, yukarıdaki ekran görüntüsünde şöyle olacaktır:
hge-realtime-app-tutorial.herokuapp.com
Şimdiye kadar yaptığımız şey, bir Postgres örneğini (Heroku dilinde bir eklenti olarak) ve bu Postgres örneğini kullanmak üzere yapılandırılmış bir GraphQL Engine örneğini dağıtmaktır. Bunu yapmanın bir sonucu olarak, artık kullanıma hazır bir GraphQL API'sine sahibiz, ancak veritabanımızda herhangi bir tablo veya veri olmadığı için bu henüz kullanışlı değil. O halde bu konuyu hemen ele alalım.
Veritabanı şemasını modelleme
Aşağıdaki şema diyagramı, anket uygulamamız için basit bir ilişkisel veritabanı şemasını yakalar:

Gördüğünüz gibi şema, yabancı anahtar kısıtlamalarından yararlanan basit, normalleştirilmiş bir şemadır. GraphQL Engine tarafından 1:1 veya 1:çok ilişki olarak yorumlanan bu kısıtlamalardır (örneğin, poll:options
1:çok ilişkisidir, çünkü her anket arasında yabancı anahtar kısıtlaması ile bağlanan 1'den fazla seçenek olacaktır. poll
tablosunun id
sütunu ve option
tablosundaki poll_id
sütunu). İlgili veriler bir grafik olarak modellenebilir ve böylece bir GraphQL API'sini güçlendirebilir. GraphQL Engine'in yaptığı tam olarak budur.

Yukarıdakilere dayanarak, şemamızı modellemek için aşağıdaki tabloları ve kısıtlamaları oluşturmamız gerekecek:
-
Poll
Anket sorusunu yakalamak için bir tablo. -
Option
Her anket için seçenekler. -
Vote
Bir kullanıcının oyu kaydetmek için. - Aşağıdaki alanlar arasında yabancı anahtar kısıtlaması (
table : column
):-
option : poll_id → poll : id
-
vote : poll_id → poll : id
-
vote : created_by_user_id → user : id
-
Artık şema tasarımımız olduğuna göre, onu Postgres veritabanımızda uygulayalım. Bu şemayı anında ortaya çıkarmak için yapacağımız şey şu:
- GraphQL Engine CLI'yi indirin.
- Bu depoyu klonlayın:
$ git clone clone https://github.com/hasura/graphql-engine $ cd graphql-engine/community/examples/realtime-poll
-
hasura/
gidin veconfig.yaml
dosyasını düzenleyin:endpoint: https://<app-name>.herokuapp.com
- Proje dizininin içinden (klonlayarak az önce indirdiğiniz) CLI'yi kullanarak geçişleri uygulayın:
$ hasura migrate apply
Arka uç için bu kadar. Artık GraphQL Engine konsolunu açabilir ve tüm tabloların mevcut olup olmadığını kontrol edebilirsiniz (konsol https://<app-name>.herokuapp.com/console
mevcuttur).
Not: Bireysel tablolar oluşturarak ve ardından bir UI kullanarak kısıtlamalar ekleyerek şemayı uygulamak için konsolu da kullanabilirdiniz. GraphQL Engine'de geçişler için yerleşik desteği kullanmak, örnek depomuzda gerekli tabloları oluşturmak ve ilişkileri/kısıtlamaları yapılandırmak için geçişlere sahip olduğu için mevcut olan uygun bir seçenektir (bu, bir hobi oluşturup oluşturmadığınıza bakılmaksızın şiddetle tavsiye edilir). proje veya üretime hazır bir uygulama).
Frontend React Uygulamasını GraphQL Backend ile Entegre Etme
Bu öğreticideki ön uç, anket sorusunu, oylama seçeneğini ve toplu anket sonuçlarını tek bir yerde gösteren basit bir uygulamadır. Daha önce bahsettiğim gibi, ilk önce bu uygulamayı çalıştırmaya odaklanacağız, böylece yakın zamanda dağıtılan GraphQL API'mizi kullanmanın anında memnuniyetini elde edeceksiniz, bu makalenin başlarında incelediğimiz GraphQL kavramlarının böyle bir uygulamanın farklı kullanım durumlarını nasıl desteklediğini görün ve ardından GraphQL entegrasyonunun başlık altında nasıl çalıştığını keşfedin.
NOT: ReactJS'de yeniyseniz, bu makalelerden bazılarına göz atmak isteyebilirsiniz. Uygulamanın React bölümünün ayrıntılarına girmeyeceğiz ve bunun yerine daha çok uygulamanın GraphQL yönlerine odaklanacağız. React uygulamasının nasıl oluşturulduğuna dair her türlü ayrıntı için depodaki kaynak koduna başvurabilirsiniz .
Ön Uç Uygulamasını Yapılandırma
- Önceki bölümde klonlanan depoda, src/apollo.js
HASURA_GRAPHQL_ENGINE_HOSTNAME
(/community/examples/realtime-poll
klasörünün içindeki) HASURA_GRAPHQL_ENGINE_HOSTNAME öğesini düzenleyin ve yukarıdan Heroku uygulaması URL'sine ayarlayın:export const HASURA_GRAPHQL_ENGINE_HOSTNAME = 'random-string-123.herokuapp.com';
- Depo/uygulama klasörünün (
/realtime-poll/
) kök dizinine gidin ve ön koşul modüllerini yüklemek için npm'yi kullanın ve ardından uygulamayı çalıştırın:$ npm install $ npm start

Artık uygulamayla oynayabilmelisiniz. Devam edin ve istediğiniz kadar oy verin, sonuçların gerçek zamanlı olarak değiştiğini fark edeceksiniz. Aslında, bu kullanıcı arayüzünün başka bir örneğini ayarlar ve aynı arka uca yönlendirirseniz, tüm örneklerde toplanan sonuçları görebileceksiniz.
Peki, bu uygulama GraphQL'i nasıl kullanıyor? Okumaya devam etmek.
Perde Arkası: GraphQL
Bu bölümde, uygulamayı destekleyen GraphQL özelliklerini keşfedeceğiz, ardından bir sonraki bölümde entegrasyonun kolaylığını göstereceğiz.
Anket Bileşeni ve Toplu Sonuç Grafiği
Sol üstteki, tüm seçenekleriyle bir anket getiren ve bir kullanıcının oyu veritabanında yakalayan anket bileşeni. Bu işlemlerin her ikisi de GraphQL API kullanılarak yapılır. Bir anketin ayrıntılarını almak için bir sorgu yaparız (bunu GraphQL tanıtımından hatırlıyor musunuz?):
query { poll { id question options { id text } } }
React- react-apollo
Mutation bileşenini kullanarak, mutasyonun, form gönderildiğinde optionId
ve userId
değişkenleri kullanılarak yürütüleceği şekilde, mutasyonu bir HTML formuna bağlayabiliriz:
mutation vote($optionId: uuid!, $userId: uuid!) { insert_vote(objects: [{option_id: $optionId, created_by_user_id: $userId}]) { returning { id } } }
Anket sonuçlarını göstermek için, oy tablosundaki verilerden seçenek başına oy sayısını çıkarmamız gerekiyor. Bir Postgres Görünümü oluşturabilir ve bu türetilmiş verileri GraphQL üzerinden kullanılabilir hale getirmek için GraphQL Engine kullanarak onu takip edebiliriz.
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;
poll_results
görünümü, her seçenek için toplam oy sayısı sağlamak için vote
ve poll
tablolarından verileri birleştirir.
Bu görünüm üzerinde GraphQL Aboneliklerini, tepki-google-charts'ı ve react-apollo
-apollo'nun abonelik bileşenini kullanarak, herhangi bir istemciden yeni bir oy geldiğinde gerçek zamanlı olarak güncellenen reaktif bir grafik bağlayabiliriz.
subscription getResult($pollId: uuid!) { poll_results(where: {poll_id: {_eq: $pollId}}) { option { id text } votes } }
GraphQL API Entegrasyonu
Daha önce bahsettiğim gibi, bir ReactJS uygulamasını GraphQL arka ucuyla entegre etmek için açık kaynaklı bir SDK olan Apollo Client'ı kullandım. Apollo Client, python istekleri, JavaScript için standart http modülü vb. gibi herhangi bir HTTP istemci kitaplığına benzer. Bir HTTP isteği (bu durumda POST istekleri) yapma ayrıntılarını kapsar. Sorgu/mutasyon/abonelik istekleri yapmak için ( src/apollo.js
içinde belirtilen) yapılandırmayı kullanır (REACT uygulamanızın JavaScript kodunda dinamik olarak değiştirilebilen değişkenleri kullanma seçeneği ile src/GraphQL.jsx içinde belirtilir) bir GraphQL uç noktası. Ayrıca, yukarıda belirtilen istekler için derleme/geliştirme zamanı doğrulaması sağlamak için GraphQL bitiş noktasının arkasındaki yazılan şemadan yararlanır. Bir istemci uygulamasının GraphQL API'sine canlı sorgu (abonelik) isteğinde bulunmasının ne kadar kolay olduğunu görelim.
SDK'yı Yapılandırma
Apollo İstemci SDK'sının bir GraphQL sunucusuna yönlendirilmesi gerekir, böylece böyle bir entegrasyon için tipik olarak gereken ortak kod kodunu otomatik olarak işleyebilir. Ön uç uygulamasını kurarken src/apollo.js'yi değiştirdiğimizde tam olarak bunu yaptık.
GraphQL Abonelik Talebi Yapma (Canlı Sorgu)
Önceki bölümde incelediğimiz aboneliği src/GraphQL.jsx dosyasında tanımlayın:
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 } }`;
React bileşenimizi bağlamak için bu tanımı kullanacağız:
export const Result = (pollId) => ( <Subscription subscription={gql`${SUBSCRIPTION_RESULT}`} variables={pollId}> {({ loading, error, data }) => { if (loading) return
Yükleniyor...</p>; eğer (hata) dönerse
Hata :</p>; dönüş ( <div> <div> {renderChart(veri)} </div> </div> ); }} </Abonelik> )
Burada dikkat edilmesi gereken bir şey, yukarıdaki aboneliğin de bir sorgu olabileceğidir. Yalnızca bir anahtar kelimeyi bir başkasıyla değiştirmek bize bir "canlı sorgu" verir ve Apollo Client SDK'nın bu gerçek zamanlı API'yi uygulamanıza bağlaması için gereken tek şey budur. Canlı sorgumuzdan her yeni veri kümesi olduğunda, SDK bu güncellenmiş verilerle grafiğimizin yeniden oluşturulmasını tetikler ( renderChart(data)
çağrısını kullanarak). Bu kadar. Gerçekten bu kadar basit!
Son düşünceler
Üç basit adımda (bir GraphQL arka ucu oluşturma, uygulama şemasını modelleme ve ön ucu GraphQL API ile entegre etme), kurulum gibi gereksiz ayrıntılara bulaşmadan tam işlevli bir gerçek zamanlı uygulamayı hızlı bir şekilde bağlayabilirsiniz. bir websocket bağlantısı. İşte bu, GraphQL gibi bir soyutlamayı destekleyen topluluk araçlarının gücüdür.
Bunu ilginç bulduysanız ve bir sonraki yan projeniz veya üretim uygulamanız için GraphQL'i daha fazla keşfetmek istiyorsanız, GraphQL araç zincirinizi oluşturmak için kullanmak isteyebileceğiniz bazı faktörler şunlardır:
- Performans ve Ölçeklenebilirlik
GraphQL, doğrudan ön uç uygulamalar tarafından tüketilmek üzere tasarlanmıştır (arka uçtaki bir ORM'den daha iyi değildir; gerçek üretkenlik faydaları bunu yapmaktan gelir). Bu nedenle, takımlarınızın veritabanı bağlantılarını verimli bir şekilde kullanma konusunda akıllı olması ve zahmetsizce ölçeklenebilmesi gerekir. - Güvenlik
Yukarıdan, verilere erişimi yetkilendirmek için olgun bir rol tabanlı erişim kontrol sistemine ihtiyaç duyulduğu sonucu çıkar. - Otomasyon
GraphQL ekosisteminde yeniyseniz, bir GraphQL şemasını el yazısıyla yazmak ve bir GraphQL sunucusunu uygulamak göz korkutucu görevler gibi görünebilir. Kullanıcı merkezli ön uç özellikleri oluşturmak gibi önemli şeylere odaklanabilmeniz için araçlarınızdaki otomasyonu en üst düzeye çıkarın. - Mimari Yukarıdaki çabalar önemsiz gibi görünse de, üretim düzeyinde bir uygulamanın arka uç mimarisi, şema birleştirme vb. gibi gelişmiş GraphQL kavramlarını içerebilir. Ayrıca, gerçek zamanlı API'leri kolayca oluşturma/tüketme yeteneği, eşzamansız, reaktif oluşturma olasılığını açar. esnek ve doğası gereği ölçeklenebilir uygulamalar. Bu nedenle, GraphQL araçlarının mimarinizi nasıl düzene sokabileceğini değerlendirmek çok önemlidir.
alakalı kaynaklar
- Uygulamanın canlı bir sürümünü buradan kontrol edebilirsiniz.
- Tam kaynak kodu GitHub'da mevcuttur.
- Veritabanı şemasını keşfetmek ve test GraphQL sorgularını çalıştırmak isterseniz, bunu buradan yapabilirsiniz.