REST'in Ötesi: GraphQL ve Falcor

Farklı gereksinimler ve elbette yapabiliyorsan daha basitini yap (bkz. kiss) ve kendini tekrarlama (bkz. dry) prensipleri birbirini ikame eden ve/veya birbirini tamamlayan teknolojilerin doğmasına ön ayak olmakta.

AA

Elbette bu süreci sadece prensipler çerçevesinde okumak yanlış olacaktır. Bu yazıda REST ve API süreçlerinde, çok sayıda anlık isteğe maruz kalan ve bu duruma istinaden RESTful mimarisinin ve MVC‘nin getirdiği bazı zorluklara karşılık olarak ortaya çıkan 2 araçtan bahsedeceğim; GraphQL ve Falcor. İlerleyen yazılarda ise GraphQL üzerinden ilerleyeceğim. Bu sayede adım adım Headless WordPress örneği için de gerekli zemini oluşturmuş olacağız. Kısa tanımlamalarla başlayalım.

GraphQL

GraphQL, verileri istemeyi açıklayan (belirli bir schema doğrultusunda) bir sözdizimidir (syntax). Graph database ile alakası yoktur. Facebook tarafından geliştirilmektedir1. GraphQL katmanı bir veya birden fazla veri kaynağı ile istemcinin arasında yaşar, istemciden (client) gelen istekleri alır ve gereken verileri döner. Özetlemek gerekirse, GraphQlL şu üç ana özelliğe sahiptir:

  • İstemcinin (client) istediği verilerin belirtilmesini sağlar.
  • Birden fazla kaynağın veriye ulaşılmasını kolaylaştırır.
  • Bir tür sistem ile veriyi açıklar.

GraphQL, yazının başında da belirtildiği üzere, veri sorgulama yoğunluğuna bağlı olarak, klasik REST mimarisi ile yaşanan sorunlara istinaden (resource yerine) oraya çıkan yeni bir yaklaşım (Application Level Query Language) olarak nitelendirilebilir.

REST / GraphQL

Diğer bir deyişle, uygulama seviyesinde (application level) istemciler için bir sorgulama ara yüzü olarak tanımlayabileceğimiz GraphQL istemcinin kendi sorgularını oluşturabilmesini mümkün kılmaktadır. Unutmadan, GraphQL framework’lerin çoğu Client Caching (istemci tarafında önbellekleme) özelliği sunmakta. Bu sayede client tarafından hali hazırda yapılmış sorgular cache üzerinden edinilebilmekte.

Şimdi, yukarıdaki anlatıları örneklendirelim ve https://swapi.co/api/people/1/ üzerinden ilerleyelim2.

{
 "name": "Luke Skywalker",
 "height": "172",
 "mass": "77",
 "hair_color": "blond",
 "skin_color": "fair",
 "eye_color": "blue",
 "birth_year": "19BBY",
 "gender": "male",
 "homeworld": "https://swapi.co/api/planets/1/",
 "films": [
  "https://swapi.co/api/films/2/",
  "https://swapi.co/api/films/6/",
  "https://swapi.co/api/films/3/",
  "https://swapi.co/api/films/1/",
  "https://swapi.co/api/films/7/"
 ],
 "species": [
  "https://swapi.co/api/species/1/"
 ],
 "vehicles": [
  "https://swapi.co/api/vehicles/14/",
  "https://swapi.co/api/vehicles/30/"
 ],
 "starships": [
  "https://swapi.co/api/starships/12/",
  "https://swapi.co/api/starships/22/"
 ],
 "created": "2014-12-09T13:50:51.644000Z",
 "edited": "2014-12-20T21:17:56.891000Z",
 "url": "https://swapi.co/api/people/1/"
}

SWAPI‘nin bahsi API Testing yazısında geçmişti. Bu yapı üzerinden ilerleyelim.

Client (istemci)’in planet listesi içeriğinden bir gezegeni (örn. Kamino) istediğini düşünelim.

{
   "name": "Kamino",
   "rotation_period": "27",
   "orbital_period": "463",
   "diameter": "19720",
   "climate": "temperate",
   "gravity": "1 standard",
   "terrain": "ocean",
   "surface_water": "100",
   "population": "1000000000",
   "residents": [
    "https://www.swapi.co/api/people/22/",
    "https://www.swapi.co/api/people/72/",
    "https://www.swapi.co/api/people/73/"
   ],
   "films": [
    "https://www.swapi.co/api/films/5/"
   ],
   "created": "2014-12-10T12:45:06.577000Z",
   "edited": "2014-12-20T20:58:18.434000Z",
   "url": "https://www.swapi.co/api/planets/10/"
  }

/api/planets/3/. Ayrıca, bu gezegenin geçtiği filmlerin (films) ve bu gezegende yaşayanların (residents) sadece id, name / title içeriklerini görüntülemek isteyelim; /api/planets/3/films ve /api/planets/3/residents. Bu ihtiyaçlar çerçevesinde ayrı isteklerin gerçekleştirilmesi gerekir ve her defasında ihtiyacımız olsun ya da olmasın tüm içerik bize iletilecektir. Ancak, GraphQL ile her bir kaynak (resource) veya ilişkili diğer kaynaklar için ayrı endpoint‘ler yerine sadece şu sorguyu kullanabiliriz:

query {
        allPlanets(
          orderBy:name_DESC,
          filter: {
            name:"Kamino"
          }
        ) {
          id
          name
          films(orderBy:title_ASC) {
            id
           title
          }
          residents(orderBy:id_ASC) {
            id
            name
          }
        }
      }

Yukarıdaki query’i swapi.graph.cool üzerinden ilettiğinizde şu dönüşü alırsınız:

{
  "data": {
    "allPlanets": [
      {
        "id": "cj0o7m34cs0l80172xvnmsjq0",
        "name": "Kamino",
        "films": [
          {
            "id": "cj0nxmy3xga5u0114fbqads8y",
            "title": "Attack of the Clones"
          }
        ],
        "residents": [
          {
            "id": "cj0nv9pg3ewho0130tijy6bk9",
            "name": "Boba Fett"
          },
          {
            "id": "cj0nv9puxewsg0130dvk9i1qx",
            "name": "Lama Su"
          },
          {
            "id": "cj0nv9pv8ewsi0130haxytem4",
            "name": "Taun We"
          }
        ]
      }
    ]
  }
}

Oldukça pratik, değil mi? Query içeriğine baktığımızda, sorgunun kolayca tanımlanabildiğini görüyoruz. Ek olarak, client’in planet için id, name, films, residents alanlarını istediğini, sonucu bir sıralama ile sunduğunu ve filtre ile filmin gezegen adı ile ilişkilendirildiğini görüyoruz. REST örneğinde client belirli end-point(ler) üzerinden request göndererek server’dan response alabilir.

Şimdilik GraphQL konusunu burada durduralım ve bir diğer çözüm yolu olan Falcor‘a geçelim. Ancak, Query, schema ve resolve konularına değindiğim bir sonraki yazıya da buradan geçiş yapabilirsiniz.

Falcor

Falcor modeli Netflix tarafından geliştirilen bir JavaScript kütüphanesidir3. Tüm uzak veri kaynaklarının sanal bir JSON graph aracılığıyla (Virtual JSON Resource) tek bir domian model aracılığıyla temsil edilmesini sağlar. Veri toplamak için hala REST yapısını kullanır. Yani, bir request için farklı endpoint’lere istek gönderilir ve her resource için JSON object döndürülür.

GraphQL ve Falcor Karşılaştırması

Her iki çözüm de modern web / mobil uygulamaların artan karmaşık veri gereksinimlerini yönetmek amacıyla ortaya çıkmıştır. Sadece, bu sorunu farklı şekillerde ele alırlar4.

Falcor, etkili data fetching işlemleri gerçekleştirebilmek amacıyla Netflix tarafından geliştirilen bir JavaScript kütüphanesidir. Tüm veri kaynakları virtual JSON graph aracılığıyla tek bir domain model ile temsil edilir.REST yapısı ile iç içedir. GraphQL’e göre bir alt seviyede bir çözümdür5.

GraphQL, bir ver sorgu dili (data query language) ve runtime’dir. 2012 yılından bu yana Facebook tarafından mobil ve web uygulama istekleri (request) ve iletimleri (deliver) için kullanılmaktadır. REST yapısından ayrılır. Bir üst seviye çözümüdür.

İleri Okumalar

  1. GraphQL queries, mutations etc.
  2. Thinking in GraphQL
  3. Nodal – GraphQL Playground
  4. SWAPI GraphQL
  5. GraphQL for JavaScript
  6. GraphQL server for Express, Connect, Hapi, Koa and more
  7. GraphQL vs. REST
  8. Falcor vs GraphQL: What are the differences?
  9. GraphQL vs Falcor
  10. GraphQL vs. Falcor
  11. The Falcor data model is a graph, and the GraphQL data model is a tree.