GraphQL Şema İntrospection ve Dokümantasyon Rehberi
GraphQL ile çalışmaya başladığınızda, en büyük avantajlardan birinin API’nizin kendi kendini belgeleyebilmesi olduğunu fark edersiniz. REST API’lerde Swagger ya da OpenAPI dökümanlarını elle yazarken, GraphQL’de şema zaten her şeyi biliyor. Introspection sistemi sayesinde bir GraphQL API’sine “kendin hakkında ne biliyorsun?” diye sorabilirsiniz ve size tüm tipler, alanlar, argümanlar, açıklamalar hakkında eksiksiz bilgi verir. Bu yazıda introspection mekanizmasını, güvenlik boyutlarını, dokümantasyon araçlarını ve gerçek dünya senaryolarında nasıl kullanacağınızı ele alacağız.
Introspection Nedir ve Nasıl Çalışır?
GraphQL introspection, bir API’nin kendi şemasını sorgulamanıza olanak tanıyan yerleşik bir sistemdir. Yani istemciler çalışma zamanında hangi tiplerin, alanların ve operasyonların mevcut olduğunu dinamik olarak keşfedebilir. Bu mekanizma GraphQL spesifikasyonunun ayrılmaz bir parçasıdır ve tüm uyumlu implementasyonlar bunu desteklemek zorundadır.
Sistem, __schema, __type, __typename gibi çift alt çizgiyle başlayan özel alanlar üzerinden çalışır. Bu alanlara “meta-alanlar” denir ve her sorgunun kök tipinde otomatik olarak mevcuttur.
En temel introspection sorgusunu bir örnek üzerinde görelim:
# Basit bir introspection sorgusu ile tüm tipleri listeleyin
curl -X POST https://api.orneksite.com/graphql
-H "Content-Type: application/json"
-d '{
"query": "{ __schema { types { name kind description } } }"
}' | jq '.data.__schema.types[] | select(.name | startswith("__") | not)'
Bu sorgu çalıştırıldığında, API’deki kullanıcı tanımlı tüm tipleri listeler. __ ile başlayanları filtreliyoruz çünkü onlar dahili introspection tipleridir.
Daha kapsamlı bir introspection sorgusu ise “full introspection query” olarak bilinir ve GraphQL araçlarının büyük çoğunluğu bunu kullanır:
# Full introspection sorgusunu çalıştır ve dosyaya kaydet
curl -X POST https://api.orneksite.com/graphql
-H "Content-Type: application/json"
-H "Authorization: Bearer TOKEN_BURAYA"
-d '{
"query": "query IntrospectionQuery { __schema { queryType { name } mutationType { name } subscriptionType { name } types { ...FullType } directives { name description locations args { ...InputValue } } } } fragment FullType on __Type { kind name description fields(includeDeprecated: true) { name description args { ...InputValue } type { ...TypeRef } isDeprecated deprecationReason } inputFields { ...InputValue } interfaces { ...TypeRef } enumValues(includeDeprecated: true) { name description isDeprecated deprecationReason } possibleTypes { ...TypeRef } } fragment InputValue on __InputValue { name description type { ...TypeRef } defaultValue } fragment TypeRef on __Type { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name } } } } } } }"
}' > schema_introspection.json
echo "Introspection tamamlandi, boyut: $(wc -c < schema_introspection.json) byte"
Şema Dokümantasyonu Yazma
İyi bir GraphQL şemasında dokümantasyon, kod içinde yaşar. SDL (Schema Definition Language) formatında açıklamalar eklemek için tırnak işaretleri kullanırsınız ve bu açıklamalar introspection sorgularında otomatik olarak görünür.
# schema.graphql dosyasını oluştur
cat > schema.graphql << 'EOF'
"""
Kullanici sistemindeki temel kullanici tipini temsil eder.
Her kullanicinin benzersiz bir ID'si ve e-posta adresi vardir.
"""
type User {
"""Kullanicinin benzersiz tanimlayicisi (UUID formatinda)"""
id: ID!
"""Kullanicinin tam adi, maksimum 100 karakter"""
fullName: String!
"""Giris icin kullanilan e-posta adresi, sistemde tekil olmalidir"""
email: String!
"""Hesap olusturma tarihi (ISO 8601 formatinda)"""
createdAt: DateTime!
"""
Kullanicinin aktif olup olmadigi.
False durumunda kullanici giris yapamaz ancak veriler silinmez.
"""
isActive: Boolean!
"""Bu kullaniciya ait siparisler, varsayilan olarak en yeni once sirali"""
orders(
"""Kac siparis getirileceği, varsayilan 10, maksimum 100"""
limit: Int = 10
"""Sayfalama icin offset degeri"""
offset: Int = 0
"""Siralama yonu, ASC veya DESC"""
orderBy: OrderDirection = DESC
): [Order!]!
}
"""Siparis durumunu gosteren enum tipi"""
enum OrderStatus {
"""Siparis alindi, henuz islenmedi"""
PENDING
"""Siparis isleniyor"""
PROCESSING
"""Siparis kargolandi"""
SHIPPED
"""Siparis teslim edildi"""
DELIVERED
"""Siparis iptal edildi"""
CANCELLED
}
EOF
echo "Dokumante edilmis schema olusturuldu"
Bu şekilde yazılan açıklamalar, GraphiQL veya Apollo Studio gibi araçlarda otomatik olarak görüntülenir. Geliştirici ekibinizin ayrı bir wiki sayfası tutmasına gerek kalmaz.
Deprecation Yönetimi
Gerçek dünyada API’ler değişir. Bir alanı kaldırmak yerine önce deprecated olarak işaretlemek, tükentekilere geçiş süresi tanımanın en doğru yoludur. GraphQL bunu yerleşik olarak destekler:
# Deprecated alanlari introspection ile sorgula
curl -X POST https://api.orneksite.com/graphql
-H "Content-Type: application/json"
-d '{
"query": "{ __type(name: "User") { fields(includeDeprecated: true) { name isDeprecated deprecationReason } } }"
}' | jq '.data.__type.fields[] | select(.isDeprecated == true)'
Şema tarafında deprecated işaretlemesi şöyle görünür:
# deprecated_schema_ornegi.graphql
cat > deprecated_example.graphql << 'EOF'
type User {
id: ID!
fullName: String!
# Eski alan - kullanmayin
name: String @deprecated(reason: "fullName alani kullanin. Bu alan v3.0'da kaldirilacak.")
email: String!
# Eski telefon alani
phone: String @deprecated(reason: "phoneNumber alani ile degistirildi")
phoneNumber: String
}
EOF
echo "Deprecated ornegi olusturuldu"
Ekibinizde bir CI/CD pipeline kuruyorsanız, deprecated alanların kullanımını otomatik olarak tespit edebilirsiniz:
#!/bin/bash
# deprecated_check.sh - PR'larda deprecated alan kullanimi kontrol eder
SCHEMA_FILE="schema.graphql"
QUERIES_DIR="src/queries"
DEPRECATED_FIELDS=$(grep -n "@deprecated" $SCHEMA_FILE | awk -F: '{print $3}' | grep -oP '(?<=")[^"]+(?=":)' 2>/dev/null)
echo "=== Deprecated Alan Kontrol Raporu ==="
FOUND=0
for query_file in $(find $QUERIES_DIR -name "*.graphql"); do
while IFS= read -r field; do
if grep -q "$field" "$query_file"; then
echo "UYARI: $query_file dosyasinda deprecated alan kullaniliyor: $field"
FOUND=$((FOUND + 1))
fi
done <<< "$DEPRECATED_FIELDS"
done
if [ $FOUND -gt 0 ]; then
echo ""
echo "Toplam $FOUND deprecated alan kullanimi bulundu!"
exit 1
else
echo "Deprecated alan kullanimi tespit edilmedi."
exit 0
fi
Introspection Güvenliği
Burada sysadmin bakış açısıyla önemli bir noktaya değinmem gerekiyor. Introspection, geliştirme ortamında müthiş kullanışlı olsa da, production ortamında güvenlik riski oluşturabilir. Kötü niyetli kullanıcılar introspection sorgularıyla API’nizin tüm yapısını keşfedebilir ve saldırı yüzeyini belirleyebilir.
Yaygın yaklaşım, production’da introspection’ı devre dışı bırakırken staging/development ortamlarında açık tutmaktır:
# Node.js / Apollo Server için environment bazli kontrol
# apollo_config.js
cat > apollo_config.js << 'EOF'
const { ApolloServer } = require('@apollo/server');
const server = new ApolloServer({
typeDefs,
resolvers,
// Production'da introspection kapali, diger ortamlarda acik
introspection: process.env.NODE_ENV !== 'production',
// Production'da playground da kapali olmali
plugins: [
process.env.NODE_ENV === 'production'
? ApolloServerPluginLandingPageDisabled()
: ApolloServerPluginLandingPageGraphQLPlayground()
]
});
EOF
# Nginx seviyesinde introspection engellemek icin
cat > /etc/nginx/conf.d/graphql_security.conf << 'EOF'
# Introspection sorgularini production'da engelle
location /graphql {
# __schema veya __type iceren istekleri reddet
if ($request_body ~* "__schema|__type") {
return 403 '{"error": "Introspection bu ortamda devre disi"}';
}
proxy_pass http://localhost:4000;
proxy_set_header Content-Type application/json;
}
EOF
echo "Guvenlik konfigurasyonu uygulandı"
Ancak introspection’ı tamamen kapatmak yerine kimlik doğrulaması gerektiren introspection da tercih edilen bir yöntemdir. Bu şekilde iç ekibiniz production verilerini görebilirken, dış kullanıcılar göremez.
Dokümantasyon Araçları
GraphiQL Kurulumu
GraphiQL, en yaygın kullanılan interaktif GraphQL IDE’sidir. Introspection üzerinden çalışır ve şemanızı otomatik olarak keşfeder:
# GraphiQL'i standalone olarak Docker ile ayaga kaldir
docker run -d
--name graphiql
-p 8080:8080
-e GRAPHQL_ENDPOINT=https://api.orneksite.com/graphql
-e GRAPHQL_SUBSCRIPTION_ENDPOINT=wss://api.orneksite.com/graphql
--restart unless-stopped
ghcr.io/graphql/graphiql-app:latest
echo "GraphiQL http://localhost:8080 adresinde calisiyor"
# Health check
sleep 3
curl -s http://localhost:8080 | grep -q "GraphiQL" && echo "Basarili" || echo "Baslatma hatasi"
SpectaQL ile Statik Dokümantasyon Üretimi
SpectaQL, introspection sonucundan güzel bir statik HTML dokümantasyonu üretir. CI/CD pipeline’ınıza entegre etmek için idealdir:
# SpectaQL kurulumu ve kullanimi
npm install -g spectaql
# Konfigurasyon dosyasi olustur
cat > spectaql_config.yml << 'EOF'
spectaql:
logoFile: ./assets/logo.png
faviconFile: ./assets/favicon.ico
displayAllServers: true
info:
title: Uygulama API Dokumantasyonu
description: |
Bu dokumantasyon otomatik olarak GraphQL semasindan uretilmistir.
Son guncelleme: ${DATE}
version: 2.1.0
contact:
name: Backend Ekibi
email: [email protected]
servers:
- url: https://api.orneksite.com/graphql
description: Production
production: true
- url: https://staging-api.orneksite.com/graphql
description: Staging
introspection:
url: https://api.orneksite.com/graphql
headers:
Authorization: "Bearer ${SPECTAQL_TOKEN}"
removeTrailingPeriodFromDescriptions: false
extensions:
graphqlScalarExamples: true
EOF
# Dokumantasyonu uret
DATE=$(date +%Y-%m-%d) spectaql spectaql_config.yml
--target-dir ./docs/api
--embeddable
echo "Dokumantasyon ./docs/api dizinine uretildi"
ls -la ./docs/api/
CI/CD ile Otomatik Dokümantasyon
Gerçek dünyada en verimli yaklaşım, her main branch güncellemesinde dokümantasyonu otomatik olarak yeniden üretmek ve deploy etmektir:
#!/bin/bash
# ci_docs_deploy.sh - GitHub Actions veya GitLab CI ile kullanin
set -e
echo "=== GraphQL Dokumantasyon Build Sureci ==="
# 1. Onceki introspection ile karsilastir
if [ -f ".last_schema_hash" ]; then
LAST_HASH=$(cat .last_schema_hash)
else
LAST_HASH=""
fi
# 2. Guncel introspection'i indir
echo "Introspection sorgusu calistiriliyor..."
curl -s -X POST "${GRAPHQL_ENDPOINT}"
-H "Content-Type: application/json"
-H "Authorization: Bearer ${DOCS_TOKEN}"
-d '{"query": "{ __schema { types { name } } }"}'
> /tmp/current_schema.json
CURRENT_HASH=$(md5sum /tmp/current_schema.json | awk '{print $1}')
if [ "$LAST_HASH" == "$CURRENT_HASH" ]; then
echo "Schema degismemis, dokumantasyon guncellenmesine gerek yok"
exit 0
fi
echo "Schema degismis, dokumantasyon yeniden olusturuluyor..."
# 3. Dokumantasyonu uret
spectaql spectaql_config.yml --target-dir ./docs/api
# 4. S3'e veya web sunucusuna deploy et
if [ "${DEPLOY_ENV}" == "production" ]; then
aws s3 sync ./docs/api s3://${DOCS_BUCKET}/api-docs
--delete
--cache-control "max-age=3600"
aws cloudfront create-invalidation
--distribution-id ${CF_DISTRIBUTION_ID}
--paths "/api-docs/*"
echo "Production dokumantasyon deploy edildi"
fi
# 5. Hash guncelle
echo "$CURRENT_HASH" > .last_schema_hash
echo "Tamamlandi!"
Introspection ile Schema Validation
Ekibinizde birden fazla geliştirici çalışıyorsa, şema değişikliklerinin geriye dönük uyumluluğunu otomatik olarak kontrol etmek kritik önem taşır. Bu iş için graphql-inspector aracı son derece kullanışlıdır:
# graphql-inspector kurulumu
npm install -g @graphql-inspector/cli
# Iki versiyon arasindaki farkları karsilastir
graphql-inspector diff
"https://api.orneksite.com/graphql"
"./schema_local.graphql"
--rule suppressRemovalOfDeprecatedField
# Kritik degisiklikleri kontrol et (breaking changes)
graphql-inspector diff
"./schema_v1.graphql"
"./schema_v2.graphql"
--onComplete="if [ $BREAKING -gt 0 ]; then exit 1; fi"
# Introspection'dan SDL olustur
graphql-inspector introspect
"https://api.orneksite.com/graphql"
--header "Authorization: Bearer ${TOKEN}"
--write "./schema_current.graphql"
echo "Schema SDL formatinda kaydedildi: schema_current.graphql"
cat schema_current.graphql | head -50
Monitoring ve Introspection Analitigi
Production’da introspection sorgularını izlemek de önemlidir. Kim ne zaman introspection çalıştırıyor, bu bilgi güvenlik audit’i için değerlidir:
# Nginx access log'larindan introspection sorgularini filtrele
# /var/log/nginx/graphql_access.log formatinda JSON log varsayiyoruz
cat > /usr/local/bin/introspection_monitor.sh << 'SCRIPT'
#!/bin/bash
LOG_FILE="/var/log/nginx/graphql_access.log"
ALERT_THRESHOLD=50
WINDOW_MINUTES=5
# Son 5 dakikadaki introspection sayisini hesapla
COUNT=$(grep "__schema|__type|IntrospectionQuery" "$LOG_FILE" |
awk -v d="$(date -d "$WINDOW_MINUTES minutes ago" '+%d/%b/%Y:%H:%M')"
'$0 >= d' | wc -l)
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Son ${WINDOW_MINUTES} dakikada introspection istegi: $COUNT"
if [ "$COUNT" -gt "$ALERT_THRESHOLD" ]; then
echo "UYARI: Yuksek introspection aktivitesi tespit edildi!"
# En cok sorgu yapan IP'leri bul
echo "En aktif IP'ler:"
grep "__schema|__type" "$LOG_FILE" |
awk '{print $1}' | sort | uniq -c | sort -rn | head -10
# Slack veya webhook'a bildirim gonder
curl -s -X POST "${SLACK_WEBHOOK_URL}"
-H "Content-Type: application/json"
-d "{"text": "GraphQL Introspection Uyarisi: Son ${WINDOW_MINUTES} dakikada ${COUNT} istek"}"
fi
SCRIPT
chmod +x /usr/local/bin/introspection_monitor.sh
# Crontab'a ekle - her 5 dakikada bir calistir
(crontab -l 2>/dev/null; echo "*/5 * * * * /usr/local/bin/introspection_monitor.sh >> /var/log/introspection_monitor.log 2>&1") | crontab -
echo "Monitoring kuruldu"
Gerçek Dünya Senaryosu: Mikro Servis Ortamında Schema Registry
Birden fazla GraphQL servisiniz varsa ve bunları bir gateway üzerinde birleştiriyorsanız (Apollo Federation gibi), şema yönetimi karmaşıklaşır. Schema registry bu sorunu çözer:
# Apollo Studio CLI ile schema registry kullanimi
npm install -g @apollo/rover
# Subgraph schemani registry'ye push et
rover subgraph publish ${APOLLO_GRAPH_REF}
--schema ./schema.graphql
--name "kullanici-servisi"
--routing-url "https://kullanici-api.internal/graphql"
# Mevcut composed schema'yi kontrol et
rover supergraph fetch ${APOLLO_GRAPH_REF}
--profile production > composed_schema.graphql
# Degisiklik oncesi etki analizini yap
rover subgraph check ${APOLLO_GRAPH_REF}
--schema ./schema_yeni.graphql
--name "kullanici-servisi"
echo "Schema registry guncelleme tamamlandi"
# Tum subgraph'larin introspection durumunu kontrol et
for SERVICE in kullanici siparis urun odeme; do
RESULT=$(curl -s -o /dev/null -w "%{http_code}"
-X POST "https://${SERVICE}-api.internal/graphql"
-H "Content-Type: application/json"
-d '{"query": "{ __typename }"}')
if [ "$RESULT" == "200" ]; then
echo "[OK] ${SERVICE} servisi introspection'a yanit veriyor"
else
echo "[HATA] ${SERVICE} servisi erisilemez! HTTP: $RESULT"
fi
done
Sonuç
GraphQL introspection ve dokümantasyon konusu, ilk bakışta sadece “API’yi tanımlamak” gibi görünse de aslında çok daha geniş bir ekosistemi kapsar. Şema içi açıklamalar sayesinde kodunuz tek source of truth haline gelir, ayrı bir wiki tutma derdiniz ortadan kalkar. SpectaQL gibi araçlarla bu bilgiyi otomatik olarak güzel bir dokümantasyona dönüştürebilirsiniz.
Güvenlik tarafında production’da introspection’ı kapatmak ya da kısıtlamak, özellikle hassas domain modelleri barındıran API’ler için kritik bir adımdır. Nginx seviyesinde filtreleme ile uygulama koduna dokunmadan bu kontrolü sağlayabilirsiniz.
CI/CD pipeline’ınıza schema validation ve dokümantasyon üretimini entegre etmek ise uzun vadede en büyük kazanımı sağlar. Her deploy’da şema otomatik kontrol edilir, breaking change’ler engellenir, dokümantasyon güncel kalır. Bu üç prensibi hayata geçirdiğinizde, GraphQL API’niz gerçek anlamda self-documenting bir sisteme dönüşür ve onboarding süreçleriniz dramatik biçimde kolaylaşır.
