GraphQL, Relay, Apollo Stack / Veri Erişiminde yeni bir bakış açısı .

Yeni bir veri sorgulama/erişim modeli :  GraphQL

Angular 2 ile çalışırken, Observables ve RxJs ile ilgilenmeye başladığımda, Bu ikilinin uygulama içinde her türlü veri türüyle rahatça çalışma imkanı verdiğini hemen fark etmiştim.

Üstelik sadece uygulamanın ihtiyacı olan veriyi değil, uygulamamız içindeki her türlü (asenkron)akışı ve events / olayıda  bir veriye dönüşütürüp RxJS ile kullanabilme imkanı Angular 2 ile uygulama geliştirme sürecini verimli yapan bir başka artı olarak karışımıza çıktı.

Ama, temel olarak değişen şey, veriye erişme yöntemimiz yada sorgulama modelimiz  değil, veriyi elde ettikten sonra işin içine Observables yada daha genel anlamda RxJs ile reactive programming nimetlerini katmakdan ibaretti.

Sadece Angular tarafından değil, genel olarak son 7-8 senedir yoğun olarak kullanılan “Restful yapı veya klasik MVC” modeli nerdeyse hiç değişmedi diyebiliriz. Verilerimize Resouce:Http Verbs eşleştirmesi ile veya Controller/Http Verbs/Action  eşleşmesi ile erişip,  istemci sunucu arası veri iletişimini sağlıyorduk.

Yine bu modelde, veri sorgulamaları(filitreleme, sayfalama vs. ) için ağırlıklı olarak klasik query parameters kullanımımız vardı.(?order=desc&limit=20 gibi). Yine bu modelde alt yada ilişkili modele ulaşmak için, nested resource dediğimiz kavramı kullandık uzun süre. (/api/tedarikci/3/urunler gibi.)

Bu model(restful mimari yada MVC yapısı) ihtiyaçlarımızı kimi zaman çok iyi karşıladı kimi zaman ise bu kalıpların dışına çıkmak zorunda kaldık. Örneğin gerçek hayattan bir durumu paylaşacak olursam; son dönemde çalışıtığımız bir projede(gerçek zamanlı bir sağlık takip uygulaması) şu şekilde bir durum söz konusu oldu;

Uygulamanın “Medical Summary / Sağlık Raporu” isimli kısmında, ilgi hastanın sistemde kayıtlı bir çok bilgisinin gösterildiği  bir ekranımız vardı, bu ekran asgari 15 olmak üzre kimi durumda 30-40 http request ile veri çekmekte ve uygulamanın hem hasta hem doktor tarafıyla en çok kullanılan ekranı durumundaydı.

Ekran, hastanın  sağlık durumu ile ilgili bir çok bilgiyi bu kadar çok requestle birlikte çekmek zorunda kaldığı için hem network trafiği açısından hem uygulama seviyesinde concurency tarafıyla , yoğun trafik olduğu zamanlarda zor zamanlar yaşatıyordu. Birde http requestlerin dışında web socket bağlantıları ve görüntülü konuşma sistemi gibi bir çok global bağlantının da sürekli açık olduğunu düşünün.

Ayrıca yoğun bir şekilde “Query Params” kullanımı ve bu parameterlere göre filitreleme, sıralama, sayfalama vs sözkonusu olduğu için, back-end tarafın da ciddi bir parsing telaşımız vardı.

Aklınıza takılmış olabilir, neden bu kadar çok web isteği var? diye sorabilirsiniz, hatırlarsanız, hem Restful hemde klasik MVC modelinde, her resource / kaynak için bir end-point oluşturmak standartdır. Aşağıdaki listeye bir bakın;

/api/patient/{id}/profile
/api/patient/{id}/medication
/api/patient/{id}/vitals
...

Yukaridaki liste devam edip gitmekte. Ayrıca başka bir sorunda, hem http isteklerinin hemde bazi web socket bağlantılarının şartlı olması yani hasta bilgilerine göre(son tansiyon bilgisi, kalp atışı ölçümü vs. gibi) yada doktorun iletişimine göre şartlı istekler de oluşturmaktaydı. Sonuç olarak aşağıdaki gibi sorunlarla yüz yüze kalmak zorunda kaldık;

  1. Network problemleri, sistem yoğun olarak kullanıldığı zaman ya firewall seviyesinde ya sunucu seviyesinde max connection sayısını yönetmek gittikçe zorlaştı
  2. Payload overload veya over-fetching / Gereksiz veri transferi; Örneğin, yukarıda bahsettiğim “medical summary” ekranı için, hastanın profil bilgilerinden sadece resim isim ve yaş bilgisine ihtiyaç varken “/api/patient/{id}/profile” gibi bir istekle hastanın tüm profil bilgisi istemciye döndürülmekte. Bu durum diğer end-point ler içinde böyle olabiliyor.  Ve bir başka konuda uygulamanızın başka kısımlarında hasta profilinden gösterceğiniz bilgi oranınin farklı olmasi. Bu durumu ya back-end de bir den fazla şarta cevap verecek şekilde yönetmeniz gerek yada her isteğe tüm profil bilgisini göndermeniz.
  3. İstemci farklılıkları: Web ve Mobil uygulamaların bu istek döngüsünü ve veri akışını yönetmesi gittikçe zorlaşmakta.

Yukarıdaki listeyi buyutebiliriz. Ama aklıma ilk gelen sorunları bu şekilde özetlemeye çalıştım. Yukarıdaki sorunların bir kısmını çözebilmek adına, ister Restful mimari de olsun isterseniz MVC yapısında, kendinizi bu iki tasarımında dışında kalan ve “Ad Hoc Endpoints” dediğimiz hiç bir standarta uymayan ama ihtiyacımızı karşılayan end-pointler oluşturur halde bulduk.

Benim bahsettiğim örnekte, medical summary ekranı için sadece bu ekrana özel 4-5 ekstra  end-point oluşuturup mevcut yapı(restfull mimariyi) bozmak zorunda kaldık. Zaman geçtikçe bu durum tekrar etti ve neticede uygulamanızın ihtiyacı olan kompleks verilerin Restful mimari yada MVC modelinde karşılanmasının hiç kolay olmadığını gördük.

Ayrıca, bu değişiklik sonrası istemcilerinde bu değişikliğe ayak uydurabilmesi adına, eski halide bir süre daha aktif halde bırakmak ve “maintain” etmek zorunda kaldık.

Buraya kadar “GraphQL” den henüz hiç bahsetmedim. Genel olarak mevcut durumla ilgili bazı tesbitler ile karşılaştığımız sorunları göz önünde bulundurarak, veriye erişimde ve sorgulamada(en azından MVC veya Restful yapıya göre daha farklı ihtiyaçları olan uygulamalarımız için) yeni bir alternatif ihtiyacının belirginleştiğini belirtmeye çalıştım.

Bunlar, kafamdayken, okuduğum bir kaç makaleden/blogdan ve bir kaç mail grubundan gelen bazı iletilerde dikkatimi çeken bişey olmuştu. Artık veriye erişim modelimiz yada veriyi sorgulama modelimizin yeni alternatifler içinde yeniden tanımlanmaya başlandığını gördüm. Klasik rest mimarisi yerine, “resource/kaynak bazlı bir istek modeli yerine(/api/products gibi)”, istemcinin ihtiyacı olan veriyi kendinin tanımladığı bir model olan GraphQL dikkatimi çekti.

Facebook tarafından geliştirilen/standartlaştırılan GraphQL  “veri sorgulama ve erişimi ” için yeni bir yaklaşım tarzı sunuyor. GraphQL, ayrıca Restful mimariyede tamamen yeni bir alternatif olma özelliğiyle de dikkat çekiyor.

Birde Meteorjs in yeni sürümlerinden itibaren standart olarak GraphQL desteği ile gelecek olması ile node.js dünyasındaki Frameworklerin artık hem restful yapıyı hemde GraphQL mimarisini beraber desteklemeye başlamasıda da benim için ayrıca önemli bir faktör oldu.

Biz de bu yazı ile, son günlerde sıkça duymaya başladığımız, GraphQL, Relay, Apollo Stack gibi yeni yaklaşımlar ve framework ler hakkında konuşalım ve istemci sunucu iletişiminde yeni bir soyutlama modeli diyebileceğimiz bu yeni kavramları tanımaya çalışalım.

GraphQL Nedir ?

İsme baktığımızda “GraphQL” i aslında biraz “kafa karışıtırıcı (en azından benim için öyleydi)” bulabilirsiniz. Sanki, Sunucu tarafında Graph veritabanlarını sorgulama için yeni bir dil gibi gelmişti. Ama işin doğrusu GraphQL için “Application Level Query Language” tanımı görebilmekteyiz. Yani bir veri tabanı sorgulama dili vs değil . Çözmeye çalıştığı problem, application level / uygulama seviyesinde istemciler için bir sorgulama ara yüzü oluşturmak.

Application levelden kastımız, sunucu tarafında oluşturulan Query Interface ile istemci tarafında bu interface uygun olarak istemcinin kendi sorgularını oluşturabilme imkanı kazanması yeteneğini düşünebiliriz.

Bu noktaya kadar hala soyut olarak konuştuğumuz “GraphQL” i biraz daha iyi anlayabilmek için bir örnek karşılaştırma ile devam edelim. Ve şöyle bir ihtiyacımız olsun;

  1. İstemcimizin, veri tabanımızdan x ürününü  istediğini düşünün
    1.  /api/product/x
  2. Ayrıca bu ürünün stok durumu ve bu ürün ü de kapsayan son 20 satışa da ihtiyacımız olsun
    1. /api/product/x/stok
    2. /api/product/x/sales?limit=20
  3. Sonra, ürünle ilgili resimleri de ilgili tablodan sorgulayalım
    1. /api/product/x/pictures

Yukarıda, API alt yapınızı nasıl yapılandırdığınıza bağlı olarak (bizim örneğimizde çok kullanılan nested resource routing) 4 ayrı istekde bulunduk. Son 5-6 senedir bir çok framework tarafından(Rails, Laravel, ASP.NET MVC vs.) uyarlanan ve yaygın kullanılan bu  restfull / MVC yapı ile istemcimiz sunucudan veri talebinde bulunmuş oldu.

Her bir kaynak ve ya o kaynağın ilişkisi olan  diğer kaynak için ayrı ayrı endpoint ler tanımlayıp, sorgulamalar yaptığımız bu model yerine , yukarıdaki işlemi bir GraphQL sorgusu ile eşleştirmeye çalışalım.

{
  urun(x){
    _id,
    name,
    price,
    stok {
      count
    },
    sales(limit:20) {
      customer,
      total 
    },
    pictures{
    thumbs,
    name 
    }
  }
}

 

İlk olarak GraphQL sorgumuza baktığımızda, sorgunun kendi kendini açıklayan ve kolay bir yapıda olduğunu görmekteyiz. Ayrıca, İstemcinin, örneğin “ürün” alanı için sadece , “id,name, ve price” alanlarını istediğini ve yine ürünle ilgili son 20 satışı ve ürünün resimlerinide bekledğini açıkca anlamaktayız. Üstelik bu sorgumuz, farklı farklı noktalara iletilmek zorunda da değil.

Rest yada MVC örneğimizde ise istemci, sadece belirli end-point lere istekler göndererek sunucudan talepde bulunuyor, uygulamanın içinde her bir alt birim kendi istekleri için sürekli  farklı veya aynı noktalara istekler yapmaktalar. İlk modelimizde (MVC/Rest) , ilgili ürünleri almanız sonrasında bu ürün için tekrar tekrar istekde bulunmanız gerekecek.

Rest/MVC mimarisiyle ilgili başka bir sıkıntıyı ve GraphQL in bu konudaki yardimini yine bir pratik karsilastirma yaparak anlamaya calisalim;

Uygulamamizin bir yerinde, ürünümüzün “ismi,fiyatı ve markasını” göstermemiz gereksin, istemcinin aşağıdaki gibi bir isteği ile ;

/api/products/x

şöyle bir cevap alalım;

{
    id:22,
    name:"televizyon",
    price:"12.32",
    brand:"Vestel",
    model:"y1233",
    isOnSale:false,
    isOnHomePage:false,
    lastUpdatedByUserId:232,
    created_at:"132132133",
    updated_at:"132142135"
    
}

Bu tür bir cevap yerine(ürünün sadece şu 3 alanına ihtiyacımız varken “ismi,fiyatı ve markası” ) istemcimiz ürün bilgisinin tamamını alacaktır. Uygulamanın başka bir noktasında ise belki ürünün sadece id alanına ihtiyaç duyacağız vs. GraphQL örneğinde, istemci neye ihtiyacı olduğunu kendisi belirteceği için sunucu tarafında aynı alt yapı ile istemcinin hemen hemen tüm ihtiyaçlarına cevap verebileceğiz.

{
    urun(x)
    {
        name,
        price,
        brand
    }

}

yada;

   urun(x)
    {
        _id
    }

gibi.  Aşağıdaki iki resime bakarak , GraphQL ve Rest/MVC arasındaki ilk ayrışmamızı görsel olarakda görebiliriz;

Klasik MVC/Rest

relay react graphql authentication

GRAPHQL

relay react graphql authentication

İkinci ayrımız olan “istemcinin isteğini kendi ihtiyacına göre tanımlayabilmesi ile ilgili ise aşağıdaki gerçek bir sorguya bakalım;

 

Yukarıdaki görüntüde, (evet bir facebook componenti) sol taraftaki GraphQL sorgumuzun ne kadar anlaşılır ve “declarative” olduğuna bir bakın , sorgumuzun aldığı cevap ise sağ tarafta gösterilmekte. Klasik Rest/MVC yapısı ile en az 2-3 farklı controller gerektiren ve belki 4-5 http request ile yapabileceğimiz işlemin GraphQL ile nekadar sade bir şekilde gerçekleştiği aşikar.

Şimdiye dek konuştuğumuz konulara bir kaç ekleme daha yaparak devam edelim. GraphQL, mimarisi iki parçalı bir yapıdan oluşmakta;

  1. GraphQL  sunucusu (Aplicaton Level Query Layer ) ve
  2. GraphQL istemcisi, (sorguları düzgün bir şekilde oluşturup, sunucu ile iletişimi kuracak client)

Hemen belirtelim, GraphQL istemcisi çok karışık komplex bir yapı değil ve teknik olarak zorunluda değil, sorgularımızı bu tür bir yardımcı olmadanda kendimiz oluşuturup sunucuya gönderebiliriz ve cevabı kendi kendimize işleyebiliriz. Ama Tahmin edeceğiniz gibi bu durum çok iş yükü getirecektir, o yüzden hazır istemcilerden birini seçip kullanmak en ideali. Yazının devamında bu konuya tekrar döeneceğiz.

Sunucu tarafındaki GraphQL alt yapısı ise yine hazır bir framework kullanmadan ve GraphQL standartlarına uyarak hemen hemen her türlü dil ve platform için gerçeklenebilir.Ama sıfırdan kendi GraphQL sunucumuzu oluşturmak muhtemelen pek isteyeceğimiz bir durum degil. Yazınnın devamında bugün itibariyle kullanabileceğimiz bazı alternatiflerden bahsedeğiz ama genel olarak bir GraphQL sunucusu aşağıdaki gibi bir yapıya sahip diyebiliriz;

  1.  schema — GraphQL yapısı gereği, strongly  typed / veri tipi zorunluluğu gerektiren bir veri katmanına ihtiyaç duymakta. GraphQL standartlarına göre bu veri şemalarımıza yada bir başka değişle “data types” ihtiyacımız var.
  2.  resolve functions , GraphQL sunucumuzun verileri nerden ve nasıl temin edeğini tanımlaycak fonksiyonlar.

Yukarıdaki iki maddeye başka eklemeler yapılabilir ama, en önemli iki maddemiz bu ikisi diyebiliriz.

Eğer, .NET geliştiricisiyseniz, GraphQL mimariyi anlamanıza yardımcı olacak güzel bir örnek olarak “LINQ” i düşünebilirsiniz. Basitçe, IQueryable Arayüzünü implement eden her collection ı LINQ ile sorgulayabilme, filitreleme yada eğer immutable yapı adına izin veriyorsa manipüle edebilmekteyiz.

GraphQL örneğimizle kıyasalayacak olursak, IQueryable ara yüzünü  uygulama seviyesinde sunucumuzun implement etmesini GraphQL sunucusu olarak düşünebiliriz, GraphQL istemcimizi ise LINQ in kendisine benzetebiliriz. Elinizde IQueryable arayüzünü implement etmiş bir http end point var ve istemci tarafında  LINQ e sahipsiniz gibi düşünebilirsiniz.

Bu tanım teknik bir kıyaslama değil tabiki sadece mantık benzerliği ile yardımcı olmak adına belirttim.

Şimdi,  GraphQL e biraz daha yakından bakmak adına GraphQL sunucuları için geliştirilmiş, bir test ve bir yönüyle dökümantasyon oluşturma aracı olan “GraphQL IDE yada diğer ismiyle GraphiQL ” e bakarak devam edelim.(isim de harfi fazla GraphiQL)

GraphiQL, sunucumuzda GraphQL data types ile senkronize olarak çalışacağı için, sunucumuzda yaptığımız her değişim otomatik olarak hemen test ortamımıza yansımış olacak ayrıca, aynı şekilde dökümentasyonumuzda otomatik  olarak güncellenmiş olacak.

https://sandbox.learngraphql.com/ adresinde online olarak deneyebileceğimiz bir GraphiQL uygulaması çalışmakta şimdi bu adrese girip bir kaç deneme yapalım;

Görüntüden de görebileceğiniz gibi çok hızlı ve sade bir şekilde sorgularımızı oluşturabiliyoruz. Bir başka güzel tarafta, Auto Complete özelliği. Ayrıca hem test ortamı hemde dökümantasyon olarak kullanılabilmekte.

Şimdiye dek her hangi bir kurulumdan vs bahsetmedik, çünkü GraphQL in kendisi bir framework yada kütüphane değil dedik, Facebook bünyesinde geliştirilen yeni bir dizayn kalıbı ve veri erişimi/sorgulaması için yeni bir alternatifin tanımlanıp standartlaştırılmasından ibaret.( facebook kendi uyarlamasını Relay ile birlikte 2012 den beri kullanmakta)

GraphQL mimari ile uygulama geliştirmek için bu mimariyi gerçekleyen framework yada kütüphanelere ihtiyacımız var. İşte bu noktada GraphQL mimari yi baz alan aşağıdaki alternatifler ortaya çıkmakta

GraphQL Servers:

Yukarıda bahsettiğimiz gibi , GraphQL sunucunuzu standartlara uyarak kendinizde yazabilirsiniz ama bu “hiç de kolay olmayacaktır.” GraphQL 2012 den beri facebook tarafından web ve mobile uygulamalarında kullanılsada, facebook dışında hala yeni diyebiliriz. Ama bu yeniliğe rağmen 2016 yılı içinde  bir çok farklı platform için (PHP,JAVA,C# vs.) bir çok GraphQL frameworkün çıktığını duyduk.

Şu an itibariyle, plug & play diyebileceğimiz alternatifler az, ama başlangıç noktası olarak alıp biraz özelleştirmeyle kullanabileceğimiz alternatiflerin sayısı  fazla. Sadece, Node.js ekosistemi içinde şuan hazır ve kullanılabilir alternatifler mevcut ve gün geçtikçe bu sayıda artmakta. .NET ve Java için ise muhtemelen yıl sonuna doğru yeni daha stabil alternatifleri duyarız diyebilirim.

Node.js dünyasından başlayacak olursak;

  1. Node + Express ve express-graphql modulü
  2. Nodal.js. Nodal, tam teşekküllü bir GraphQL ve Restful sunucu olarak kullanılabiliyor
  3. Meteor ve reactive-graphql paketi. Meteor  muhtemelen node.js dünyasındaki en başarılı GraohQL alta yapisini sunan alternatiflerden biri.
  4. Apollo Stack . 3,maddede bahsettiğimiz Meteor tarafından kullanilan sunucu ve istemci paketi. Meteor bu yapıyı ana sistemden ayrı geliştirerek tüm Node.js ekosistemi içinde kullanmaya imkan sağlamış oldu. Apollo Stack  ı şimdiden kullanabilirsiniz.

Diğer platformlar için çok fazla inceleme yapamadığım için bulabildğim bir kaç alternatifi belirterek devam edelim;

Java & Scala:

graphql-java ve sangria , spring-graphql-common

Php: Laravel + laravel-graphql

GraphQL framework for Python http://graphene-python.org/

graphql-dotnet – GraphQL for .NET.

Daha detaylı bir listeye bu adresten bakabilirsiniz.

GraphQL için en zengin imkanlar şu an itibariyle Javascript ve Node.js dünyasında diyebiliriz. Sunucu alternatiflerimize genel oalrak baktıktan sonra, şimdi istemci tarafındaki (GraphQL istemcileri) alternatiflerimize bakarak devam edelim.

Relay:  Facebook tarafından geliştirilen GraphQL(client) Framework

Relay, facebook tarafından geliştirilen ve kullanılan, QraphQL istemcisi.  Relay muhtemelen, Apollo Stack ile birlikte  bulabileceğiniz en yetenekli GraphQL istemcisi.  Ayrıca , facebook ihtiyaçları için geliştirildiğinden dolayı,  “query merging, pagination and deferred queries” gibi ihtiyaçlar için çok güçlü bir alt yapıya sahip.

Fakat Relay için bir kaç önemli nokta var;

Facebook tarafından kendi ihtiyaçları için geliştirildiğinden dolayı ciddi derecede React bağımlılığı var, react olmadan kullanmak nerdeyse imkansız gibi. Ayrıca yine facebook  un ihtiyaçlarını karşılayabilmek adına diğer alternatiflerine göre daha kompleks bir yapıya sahip.

Apollo  Stack : Apollo GraphQL Client .

Apollo Client, Meteor tarafından gelişitirilen GraphQL  istemcisi, Relay ile kıyasladığınızda, bener zengin özellikleri mevcut. Bir çok uygulamada ihtiyacınızı fazlasıyla karşılayacaktır. Eğer Meteor ile kullanacaksanız Meteorun Reactive yapısına %100 uyumlu.

Ayrıca en önemli avantajı, Relay ın tersine React bağımlılığı yok, Angular, Vue yada ember.js fark etmeden veya her hangi bir javascript framework kullanmadan eski usul olarak GraphQL sunucunuza bağlanmanızı ve sorgulamalarınızı yapmanıza imkan vermekte.

/lokka 

Diğer iki alternatifine göre çok daha sade ve hafif bir istemci. Relay ve Apollo ile kıyasladığınızda çok daha az yeteneği var ama temel işlem olan, sorguları oluşuturup sunucu bağlantısını yerine getirme adına kullanabileceğiniz bir istemci.

Yazımızda genel olarak GraphQL mimari ve ekosisteminin giriş seviyesinde tanımaya çalıştık.

Kolay Gele.

 

Bazı Kaynaklar:

http://www.apollodata.com/

https://facebook.github.io/relay/docs/thinking-in-graphql.html

http://graphql.nodaljs.com/

http://graphql.org/docs/getting-started/

https://learngraphql.com/basics/introduction

View story at Medium.com

 

3 thoughts on “GraphQL, Relay, Apollo Stack / Veri Erişiminde yeni bir bakış açısı .

Leave a Reply

Your email address will not be published. Required fields are marked *