Categories: Genel

GraphQL – Hızlı Başlangıç

Bu yazıyı okuduğunuza göre siz de benim gibi GraphQL’i merak edip, öğrenmeye çalışıyorsunuz demektir. Bu yazıda Github’ın sunduğu GraphQL API’ı üzerinden hızlı bir tanışma yapmayı planlıyorum. Yapacağım işlemler Github API’ına istekler göndermekten ibaret olacak ama genel olarak  GraphQL’i tanımak açısından faydalı olacağını düşünüyorum. Başka bir zamanda da Django ile kendi GraphQL API servisimi oluşturmayı deneyeceğim.

Kısaca bahsetmek gerekirse GraphQL, Facebook tarafından 2012 yılında mobil uygulamalarında veri alışverişini kolaylaştırmak için oluşturulmuş bir  “query language”.  Yani dil bağımsız olarak kendi graph servislerimizi yazabiliriz. 2015 yılında ise proje açık kaynak olarak paylaşıldı. Şu anda kullananlar arasında Github, Shopify, Coursera, Pinterest var.

Fazla uzatmadan GitHub GraphQL API’yı kullanamaya başlayalım. Giriş yaptıktan sonra ilk örnek sorgumuz bizim için hazırlanmış durumda zaten;

Hello there!

query { 
  viewer { 
    login
  }
}

“Execute Query”, “oynat” simgesine sahip butona, tıkladığım zaman aldığım dönen sonuç şu şekilde;

{
  "data": {
    "viewer": {
      "login": "yusufkaracin"
    }
  }
}

Burada yaptığımız basit bir sorgu oluşturmaktı. Bir sorgu oluşturduğumuz zaman objelerin sahip olduğu alanların değerini almış oluyoruz. viewer giriş yapmış kullanıcıyı temsil ediyor, anlayacağınız gibi…

Bir de sorgumuzu şu şekilde yapalım;

{
  viewer {
    login
    name
    bio
    avatarUrl
  }
}
{
  "data": {
    "viewer": {
      "login": "yusufkaracin",
      "name": "Yusuf Karaçin",
      "bio": null,
      "avatarUrl": "https://avatars3.githubusercontent.com/u/6485586?v=3"
    }
  }
}

Sorgu ve dönen sonuç aynı şekilde. GraphQL’in en büyük artılarından birisi de bu. Hangi verilere ihtiyacımız varsa, sadece onları isteyip, sorguyla aynı formatta alıyoruz.

Argüman Gönderme

Bazı alanlar için sorgu yazarken argüman göndermemiz gerekebilir. Argümanları parantezler içinde gönderiyoruz. Bilmemiz gereken en önemli nokta, çift tırnağın zorunlu olması. yani login: "github" yerine login: 'github' hata verecektir.

{
  repositoryOwner(login: "github") {
    id
    url
    avatarUrl
  }
}

Bazı alanlar için argüman göndermek zorunlu. Mesela repository için name ve owner için argüman geçmek gerek.

{
  repository(owner: "django") {
    id
    createdAt
    description
  }
}

# HATA

{
  "data": null,
  "errors": [
    {
      "message": "Field 'repository' is missing required arguments: name",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ]
    }
  ]
}

Doğru sorgu için name ve owner gerekli;

{
  repository(owner: "django", name: "django") {
    id
    createdAt
    description
  }
}

# CEVAP

{
  "data": {
    "repository": {
      "id": "MDEwOlJlcG9zaXRvcnk0MTY0NDgy",
      "createdAt": "2012-04-28T02:47:18Z",
      "description": "The Web framework for perfectionists with deadlines."
    }
  }
}

Aliases ve Fragments

Alias

Aynı alan için farklı argümanlarla sorgu yapmamız gerekirse, “alias” kullanmamız gerek. Demek istediğimi daha iyi anlatmak için şu sorguyu çalıştırmayı deneyelim;

{
  repository(owner: "django", name: "django") {
    id
    createdAt
    description
  },
  repository(owner: "facebookresearch", name: "ELF") {
    id
    createdAt
    description
  }
}

# HATA

{
  "data": null,
  "errors": [
    {
      "message": "Field 'repository' has an argument conflict: {owner:\"\\\"django\\\"\",name:\"\\\"django\\\"\"} or {owner:\"\\\"ELF\\\"\",name:\"\\\"facebookresearch\\\"\"}?",
      "locations": [
        {
          "line": 2,
          "column": 3
        },
        {
          "line": 7,
          "column": 3
        }
      ]
    }
  ]
}

repository için farklı argümanlarla sorgu yapmayı denedik ama “argument conflict” hatası aldık. Bu hatanın önüne geçmek için sorgumuzu şu şekilde düzeltebiliriz;

{
  djangoQuery: repository(owner: "django", name: "django") {
    id
    createdAt
    description
  },
  elfQuery: repository(owner: "facebookresearch", name: "ELF") {
    id
    createdAt
    description
  }
}

Fragment

Yukarıdaki sorgulardakiid, createdAt, description gibi tekrar tekrar aynı alanların değerini almak istediğimizde, “fragment” tanımlayıp kullanabiliriz.

fragment repositoryFragment on Repository {
  id
  createdAt
  description
}

{
  djangoQuery: repository(owner: "django", name: "django") {
    ...repositoryFragment
  }
  elfQuery: repository(owner: "facebookresearch", name: "ELF") {
    ...repositoryFragment
  }
}

Connections

Şu ana kadar yaptığımız sorguların sonucunda hiç liste olarak sonuç gelmedi. 1’den çoğa ilişkisi olan bir senaryoda, bir albümün birden fazla şarkıya sahip olması gibi, “connection” devreye giriyor. GitHub GraphQL API üzerinden sahip olduğumuz repoları listeleyen sorguya bakarsak aslında çok basit bir şeyden bahsettiğimi anlarız;

{
  repositoryOwner(login: "github") {
    id
    repositories(first: 2) {
      edges {
        node {
          id
          name
          description
        }
      }
    }
  }
}

# CEVAP

{
  "data": {
    "repositoryOwner": {
      "id": "MDEyOk9yZ2FuaXphdGlvbjk5MTk=",
      "repositories": {
        "edges": [
          {
            "node": {
              "id": "MDEwOlJlcG9zaXRvcnkxODQ5OTY=",
              "name": "version_sorter",
              "description": "Fast sorting of version numbers"
            }
          },
          {
            "node": {
              "id": "MDEwOlJlcG9zaXRvcnkzNTU4OTM=",
              "name": "markup",
              "description": "The code we use to render README.your_favorite_markup"
            }
          }
        ]
      }
    }
  }
}

Sorgu sonuçlarının görüntülendiği pencerenin sağ üstündeki “Docs”a tıklayıp,  repositories‘e bakarsak RepositoryConnection tipinde olduğunu görürüz. Sırayla edges ve node alanlarının detayına bakarsak her bir node aslında Repositorytipinde olduğunu görürüz.

Bu vesileyle de GraphQL ile iç içe sorgular yapmanın aslında ne kadar basit olduğunu görmüş olduk.

Değişken Tanımlama

Şu ana kadar yaptığımız sorgularda değişkenlerden faydalanmadık. GitHub GraphQL API’da sorguları yazdığımız pencerenin hemen altında “Query Variables” isminde başka bir pencere var. Şimdi hem sorgumuza bir isim verelim hem de bu sorgumuza argüman geçerken değişkenleri kullanalım;

# Query Variables
{
  "login": "github",
  "first": 5
}

# Query
query GetRepositoriesByLogin($login:String!, $first:Int!){
  repositoryOwner(login: $login) {
    id
    repositories(first: $first) {
      edges {
        node {
          id
          name
          description
        }
      }
    }
  }
}

Mutation

Belki çoktan aklınıza şu soru gelmiştir: “Hep data almak için mi sorgu yapıyoruz? Datalar üzerinde değişikleri nasıl yapabiliriz?”. Sorunun cevabı mutation “keyword”‘ünde saklı. GitHub GraphQL API kullandığımız için, Github’ın bize sunduğu mutationlarından üzerinden sorgumuzu yapacağız.  Yapmaya çalışacağımız şey, yeni yorum eklemek. Önce test için yeni bir repo oluşturalım ve issue ekleyelim.

Şu sorgu ile de açtığımız son repoyu ve “issue”ları listeleyelim. Issueların id bilgisi(subjectId) gerekli olacak.

query($login: String!, $last: Int!) {
  repositoryOwner(login: $login) {
    id
    repositories(last: $last) {
      edges {
        node {
          id
          name
          description
          issues(first: 2) {
            edges {
              node {
                id
                title
              }
            }
          }
        }
      }
    }
  }
}

Şimdi de gelelim mutationoluşturmaya;

# Query Variables
{
  "input": {
    "clientMutationId": "123",
    "subjectId": "MDU6SXNzdWUyNDE0ODM4NzM=",
    "body": "Bu yorum GraphQL API Explorer ile yapıldı"
  }
}

# Query
mutation AddComment($input: AddCommentInput!) {
  addComment(input: $input) {
    clientMutationId
    subject {
      id
    }
  }
}

# CEVAP

{
  "data": {
    "addComment": {
      "clientMutationId": "123",
      "subject": {
        "id": "MDU6SXNzdWUyNDE0ODM4NzM="
      }
    }
  }
}

Burada subjectIddışındaki değerleri biz belirledik. “Query Variables” kısmında göndereceğimiz obje için “Docs > addComment > AddCommentInput”  bölümüne bakabilirsiniz. Sorgu sonucu dönecek cevap AddCommentPayloadtipinde olacak ve yine “Docs” kısmından hangi alanları kullanabileceğimizi görebilirsiniz.

Bye!

Çok kısa da olsa GraphQL ile tanışmış olduk ve sadece ufak bir kısmını denedik. graphql.org/code adresinde göreceğiz gibi bir çok dilde kendi servisimizi yazmamız mümkün ve GraphQL hakkında öğreneceğimiz çok şey bizi bekliyor.

Share
Published by
yusufkaracin

Recent Posts

Celery Checklist [Python]

Celery ile alakalı "best practice"leri ve faydalı araçları bir araya getiren güzel bir checklist'e denk…

5 yıl ago

JavaScript Dizileri için 13 İpucu

Diziler en temel ve sık kullandığımız araçlardan... Kod yazarken işimizi kolaylaştıracak, daha temiz kod yazmamızı…

5 yıl ago

List & Tuple Mini Test (Python)

listve tuple bilginizi test etmek ister misiniz? realpython.com da keşfettiğim ve Türkçe'ye çevirdiğim mini teste…

5 yıl ago

Bilmeniz Gereken 11 Python Mülakat Sorusu

Rehberlik sağlaması ve bilgi tazelemesi açısından faydalı olduğunu düşündüğüm bir Toptal blog paylaşımınıTürkçe'ye çevirdim.Devamını okuyunBilmeniz…

5 yıl ago

Angular Componentlere Konsol Üzerinden Hızlı Erişim

Angular componentlerine console üzerinden hızlıca erişmek için kullanılan bir teknik. Unutmamak için kendime not düşüyorum.Devamını…

5 yıl ago

Birkaç Güzel JavaScript Sorusu İster Miydiniz?

Geçtiğimiz günlerde keşfettiğim ve oldukça da hoşuma giden repoyu paylaşmak istiyorum: lydiahallie/javascript-questions Genel olarak temel…

5 yıl ago