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.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir