8 dakika
Sorgulama - Örnek Uygulamalar
The Graph, blokzincirlerinden veri sorgulamak için merkeziyetsiz bir yöntem sağlar. Verileri bir GraphQL API’si aracılığıyla sunulur ve bu da GraphQL diliyle sorgulamayı kolaylaştırır.
Subgraph’inizi optimize etmek için gerekli temel GraphQL dili kurallarını ve örnek uygulamaları öğrenin.
Bir GraphQL API’sini sorgulama
Bir GraphQL Sorgusunun Anatomisi
REST API’den farklı olarak, bir GraphQL API’si, hangi sorguların gerçekleştirilebileceğini tanımlayan bir Şema üzerine kuruludur.
Örneğin, token
sorgusunu kullanarak bir token almak için yapılacak sorgu aşağıdaki gibi olacaktır:
1query GetToken($id: ID!) {2 token(id: $id) {3 id4 owner5 }6}
ve bu sorgu (doğru $id
değişkeni geçirildiğinde) aşağıdaki öngörülebilir JSON yanıtını döndürecektir:
1{2 "token": {3 "id": "...",4 "owner": "..."5 }6}
GraphQL sorguları, bir spesifikasyon temelinde tanımlanmış olan GraphQL dilini kullanır.
Yukarıdaki GetToken
sorgusu, birden fazla dil bileşeninden oluşur (aşağıda [...]
yer tutucularıyla gösterilmiştir):
1query [operationName]([variableName]: [variableType]) {2 [queryName]([argumentName]: [variableName]) {3 # "{ ... }" express a Selection-Set, we are querying fields from `queryName`.4 [field]5 [field]6 }7}
GraphQL Sorgusu Yazmanın Kuralları
- Her bir
queryName
, işlem başına yalnızca bir kez kullanılmalıdır. - Her bir
field
, bir seçim içinde yalnızca bir kez kullanılmalıdır (örneğin,token
altındaid
alanını iki kez sorgulayamayız) - Bazı
field
’lar veya sorgular (örneğintokens
), alt alan seçimi gerektiren karmaşık türler döndürür. Beklendiğinde alt alan seçimi yapmamak (ya da beklenmediğinde böyle bir seçim yapmak, örneğinid
üzerinde) bir hata oluşturur. Bir alanın türünü öğrenmek için lütfen Graph Gezgini sayfasına bakın. - Bir argümana atanan herhangi bir değişken, onun türüyle eşleşmelidir.
- Belirli bir değişken listesinde, her bir değişken özgün olmalıdır.
- Tanımlanan tüm değişkenler kullanılmalıdır.
Not: Bu kurallara uyulmaması, The Graph API’sinin hata vermesi ile sonuçlanacaktır.
Kod örnekleriyle birlikte tam kurallar listesi için GraphQL Doğrulamaları rehberine göz atın.
Bir GraphQL API’sine sorgu göndermek
GraphQL, HTTP üzerinden taşınan bir dil ve kurallar bütünüdür.
Bu, (yerel olarak veya @whatwg-node/fetch
ya da isomorphic-fetch
aracılığıyla) standart fetch
kullanarak bir GraphQL API’sini sorgulayabileceğiniz anlamına gelir.
Ancak, “Bir Uygulamadan Sorgulama” bölümünde belirtildiği gibi, aşağıdaki benzersiz özellikleri destekleyen graph-client
ın kullanılması önerilir:
- Zincirler arası Subgraph İşleme: Tek bir sorguda birden fazla Subgraph’ten veri sorgulama
- Otomatik Blok Takibi
- Otomatik Sayfalama
- Tamamen yazılmış sonuç
graph-client
aracılığıyla The Graph sorgusu nasıl yapılır:
1import { execute } from '../.graphclient'23const query = `4query GetToken($id: ID!) {5 token(id: $id) {6 id7 owner8 }9}10`11const variables = { id: '1' }1213async function main() {14 const result = await execute(query, variables)15 // `result` is fully typed!16 console.log(result)17}1819main()
Daha fazla GraphQL istemcisi alternatifi, “Bir Uygulamadan Sorgulama” bölümünde ele alınmıştır.
En İyi Uygulamalar
Her zaman statik sorgular yazın
Yaygın (ve kötü) bir uygulama, sorgu dizelerini aşağıdaki gibi dinamik olarak oluşturmaktır:
1const id = params.id2const fields = ['id', 'owner']3const query = `4query GetToken {5 token(id: ${id}) {6 ${fields.join('\n')}7 }8}9`1011// Sorguyu çalıştır...
Yukarıdaki kod parçası geçerli bir GraphQL sorgusu üretse de, birçok dezavantaja sahiptir:
- sorguyu bir bütün olarak anlamayı zorlaştırır
- geliştiriciler, dize enterpolasyonunun güvenliğini sağlamakla sorumludur
- değişken değerlerinin istek parametreleriyle gönderilmemesi sunucu tarafındaki önbellekleme olasılığını ortadan kaldırır
- bu, araçların sorguyu statik olarak analiz etmesini engeller (örneğin: Linter veya tür üretim araçları)
Bu nedenle, sorguları her zaman statik dizeler olarak yazmanız önerilir:
1import { execute } from 'dilediğiniz-graphql-istemcisi'23const id = params.id4const query = `5query GetToken($id: ID!) {6 token(id: $id) {7 id8 owner9 }10}11`1213const result = await execute(query, {14 variables: {15 id,16 },17})
Bunu yapmak birçok avantaj sağlar:
- Okuması ve bakımı kolay sorgular
- GraphQL sunucusu değişkenlerin güvenli hale getirilmesini üstlenir
- Değişkenler sunucu düzeyinde önbelleğe alınabilir
- Sorgular araçlar tarafından statik olarak analiz edilebilir (detaylar sonraki bölümlerde açıklanacaktır)
Statik sorgularda alanlar nasıl koşullu olarak dahil edilir
owner
alanını yalnızca belirli bir koşulla dahil etmek isteyebilirsiniz.
Bunun için, @include(if:...)
yönergesinden aşağıdaki gibi yararlanabilirsiniz:
1import { execute } from 'dilediğiniz-graphql-istemcisi'23const id = params.id4const query = `5query GetToken($id: ID!, $includeOwner: Boolean) {6 token(id: $id) {7 id8 owner @include(if: $includeOwner)9 }10}11`1213const result = await execute(query, {14 variables: {15 id,16 includeOwner: true,17 },18})
Not: Bunun tersi yönerge @skip(if: ...)
şeklindedir.
İstediğini sor
GraphQL, “İstediğini sor” sloganıyla ün kazanmıştı.
Bu nedenle, GraphQL’de tüm kullanılabilir alanları tek tek listelemeden almanın bir yolu yoktur.
- GraphQL API’leri sorgularken, her zaman sadece gerçekten kullanılacak alanları sorgulamayı düşünmelisiniz.
- Sorguların yalnızca gerçekten ihtiyaç duyduğunuz kadar varlık getirdiğinden emin olun. Varsayılan olarak, sorgular bir koleksiyondan 100 varlık getirir. Bu miktar genellikle gerekenden, örneğin kullanıcıya gösterilecek olandan, çok daha fazladır. Bu durum yalnızca sorgulardaki en üst düzey koleksiyonlar için değil, özellikle iç içe varlık koleksiyonları için de geçerlidir.
Örneğin, aşağıdaki sorguda:
1query listTokens {2 tokens {3 # en fazla 100 token getirilecektir4 id5 transactions {6 # en fazla 100 işlem getirilecektir7 id8 }9 }10}
Yanıt, 100 token için 100’er işlem içerebilir.
Uygulama yalnızca 10 işleme ihtiyaç duyuyorsa, sorguda transactions (işlemler) alanına açıkça first: 10
değeri verilmelidir.
Birden fazla kaydı istemek için tek bir sorgu kullanın
Varsayılan olarak, Subgraph’ler tek bir kayıt için tekil bir varlık sunar. Birden fazla kayıt almak için çoğul varlıkları ve filtrelemeyi kullanın: where: {id_in:[X,Y,Z]}
veya where: {volume_gt:100000}
Verimsiz bir sorgulama örneği:
1query SingleRecord {2 entity(id: X) {3 id4 name5 }6}7query SingleRecord {8 entity(id: Y) {9 id10 name11 }12}
Optimize edilmiş bir sorgulama örneği:
1query ManyRecords {2 entities(where: { id_in: [X, Y] }) {3 id4 name5 }6}
Birden fazla sorguyu tek bir istekte birleştirin
Uygulamanız buradaki gibi birden fazla veri türünü sorgulamanızı gerektirebilir:
1import { execute } from "dilediğiniz-graphql-istemcisi"23const tokensQuery = `4query GetTokens {5 tokens(first: 50) {6 id7 owner8 }9}10`11const countersQuery = `12query GetCounters {13 counters {14 id15 value16 }17}18`1920const [tokens, counters] = Promise.all(21 [22 tokensQuery,23 countersQuery,24 ].map(execute)25)
Bu uygulama tamamen geçerli olsa da, GraphQL API’si ile iki kez veri alışverişi yapılmasını gerektirir.
Neyse ki, aynı GraphQL isteği içinde birden fazla sorgu göndermek de aşağıdaki gibi geçerlidir:
1import { execute } from "dilediğiniz-graphql-istemcisi"23const query = `4query GetTokensandCounters {5 tokens(first: 50) {6 id7 owner8 }9 counters {10 id11 value12 }13}14`1516const { result: { tokens, counters } } = execute(query)
Bu yaklaşım, ağ üzerinde harcanan süreyi azaltarak genel performansı artırır (API’ye yapılan bir gidiş-dönüşü ortadan kaldırır) ve daha sade bir uygulama sunar.
GraphQL Parçalarını (Fragment) Kullanın
GraphQL sorguları yazarken faydalı bir özellik de GraphQL Fragment’tir.
Aşağıdaki sorguya baktığınızda, bazı alanların birden fazla Seçim Kümesi ({ ... }
) içinde tekrarlandığını fark edeceksiniz:
1query {2 bondEvents {3 id4 newDelegate {5 id6 active7 status8 }9 oldDelegate {10 id11 active12 status13 }14 }15}
Bu tür tekrarlanan alanlar (id
, active
, status
) birçok sorunu beraberinde getirir:
- Daha kapsamlı sorguların okunması zorlaşır.
- Sorgulara dayanarak TypeScript türleri üreten araçlar kullanıldığında (ilgili detaylar için son bölüme bakınız),
newDelegate
veoldDelegate
iki ayrı satır içi arayüz (inline interface) olarak tanımlanır.
Sorgunun yeniden düzenlenmiş hali aşağıdaki gibi olacaktır:
1query {2 bondEvents {3 id4 newDelegate {5 ...DelegateItem6 }7 oldDelegate {8 ...DelegateItem9 }10 }11}1213# sorguda tekrarlanan alanları ortaklaştırmak için14# transcoder üzerinde bir fragment (alt tür) tanımlıyoruz15fragment DelegateItem on Transcoder {16 id17 active18 status19}
GraphQL fragment
kullanmak, okunabilirliği artırır (özellikle büyük sorgularda) ve daha iyi TypeScript türleri üretilmesini sağlar.
Tür üretim aracını kullanırken, yukarıdaki sorgu doğru bir DelegateItemFragment
türü (sondaki “Araçlar” bölümüne bakabilirsiniz) oluşturacaktır.
GraphQL Fragment kullanırken yapılması ve kaçınılması gerekenler
Fragment tabanı bir tip olmalıdır
Bir Fragment, geçerli olmayan bir tür üzerinde tanımlanamaz. Kısacası, alanları olmayan bir tür üzerinde kullanılamaz:
1fragment MyFragment on BigInt {2 # ...3}
BigInt
, bir skaler (yerel “basit” tür) olduğu için bir fragment’in temeli olarak kullanılamaz.
Fragment Nasıl Yayılır
Fragment’ler belirli türler üzerinde tanımlanırlar ve sorgularda buna uygun şekilde kullanılmalılardır.
Örnek:
1query {2 bondEvents {3 id4 newDelegate {5 ...VoteItem # Hata! `VoteItem` fragment'i `Transcoder` türü üzerinde kullanılamaz6 }7 oldDelegate {8 ...VoteItem9 }10 }11}1213fragment VoteItem on Vote {14 id15 voter16}
newDelegate
ve oldDelegate
, Transcoder
türündendir.
Burada Vote
türünde bir fragment kullanılamaz.
Fragment’ı atomik bir veri iş birimi olarak tanımlayın
GraphQL’de bir Fragment
, kullanım amacına göre tanımlanmalıdır.
Çoğu kullanım senaryosunda, her tür için bir fragment tanımlamak (özellikle tekrarlanan alan kullanımı veya tür üretimi durumlarında) yeterlidir.
İşte fragment kullanımı için temel bir kural:
- Aynı türdeki alanlar bir sorguda tekrar ediyorsa, bunları bir
Fragment
içinde gruplayın. - Benzer ancak farklı alanlar tekrar ediyorsa, birden fazla “fragment” oluşturun. Örneğin:
1# temel fragment (genellikle listeleme işlemlerinde kullanılır)2fragment Voter on Vote {3 id4 voter5}67# genişletilmiş fragment (bir vote'un detaylı görünümünü sorgularken kullanılır)8fragment VoteWithPoll on Vote {9 id10 voter11 choiceID12 poll {13 id14 proposal15 }16}
Temel Araçlar
Web tabanlı GraphQL gezginleri
Sorgularınızı uygulamanızda çalıştırarak denemek zahmetli olabilir. Bu nedenle, sorgularınızı uygulamaya eklemeden önce test etmek için Graph Gezginini kullanmaktan çekinmeyin. Graph Gezgini, sorgularınızı test etmeniz için önceden yapılandırılmış bir GraphQL playground’u sunar.
Sorgularınızda hata ayıklamak/sorgularınızı test etmek için daha esnek bir yol arıyorsanız, Altair ve GraphiQL gibi benzer web tabanlı araçlar da mevcuttur.
GraphQL’de Linting
Yukarıda belirtilen örnek uygulamalar ve sözdizim kurallarına uyum sağlamak için aşağıdaki iş akışı ve IDE (Entegre Geliştirme Ortamı) araçlarını kullanmanız şiddetle tavsiye edilir.
GraphQL ESLint
GraphQL ESLint, GraphQL örnek uygulamalarına zahmetsizce uymanıza yardımcı olur.
“operations-recommended” yapılandırmasını kurmak, aşağıdakiler gibi temel kuralları zorunlu kılar:
@graphql-eslint/fields-on-correct-type
: alan doğru tür üzerinde mi kullanılmış?@graphql-eslint/no-unused-variables
: verilen bir değişken kullanılmadan mı bırakılmış?- ve daha fazlası!
Bu sayede, sorguları playground’da test etmeye ya da üretim ortamında çalıştırmaya gerek kalmadan hataları önceden yakalayabilirsiniz!
IDE eklentileri
VSCode ve GraphQL
GraphQL VSCode uzantısı, geliştirme sürecinize aşağıdakileri sağlamak için mükemmel bir eklentidir:
- Sözdizimi vurgulama
- Otomatik tamamlama önerileri
- Şemaya karşı doğrulama
- Kod parçacıkları (snippets)
- Fragment’ler ve girdi türleri için tanıma gitme özelliği
graphql-eslint
kullanıyorsanız, ESLint VSCode uzantısı kodunuzda hataları ve uyarıları satır içi şekilde doğru bir biçimde görüntülemek için mutlaka edinilmesi gereken bir araçtır.
WebStorm/Intellij ve GraphQL
JS GraphQL eklentisi, GraphQL ile çalışırken deneyiminizi aşağıdakileri sağlayarak önemli ölçüde iyileştirir:
- Sözdizimi vurgulama
- Otomatik tamamlama önerileri
- Şemaya karşı doğrulama
- Kod parçacıkları (snippets)
Bu konuyla ilgili daha fazla bilgi için, eklentinin tüm ana özelliklerini gösteren WebStorm makalesine göz atabilirsiniz.