Versiyon numarası olmadan GraphQL deprecation
5 dk okuma
Bir REST API’si /v1/’in yanında /v2/’yi de yayınlayabilir ve çağıranların kendi hızlarında
geçiş yapmasına izin verebilir. GraphQL’in bir endpoint’te tek bir şeması vardır, ve her client,
geçen yılın build’indeki mobil uygulama ve bu sabah dağıtılan dahili dashboard, aynı grafiği
sorgular. Fork’lanacak bir URL yoktur. Bir alanı deprecate etmek, herkesin zaten bağımlı olduğu bir
şemada, onu yerinde deprecated olarak işaretlemek anlamına gelir, bu da disiplini REST’ten farklı
kılar, temelde yatan sorun, çağıranlara bir şeyin kaybolacağını söylemek, API
deprecation’ın genel olarak ele aldığı sorunla aynı olsa bile.
Artırılacak bir versiyon yoksa GraphQL bir alanı deprecated olarak nasıl işaretler?
Doğrudan alana uygulanan @deprecated direktifiyle:
type Product {
price: Float @deprecated(reason: "Use priceV2 for multi-currency support.")
priceV2: Money
}
Alan sorgulanabilir kalır. Kaybolmaz, 404 vermez, davranışını değiştirmez; sadece çoğu GraphQL aracının, GraphiQL, Apollo Studio, şema linter’ları, şemaya göz atan veya ona karşı bir sorgu yazan herkese göstereceği, makine tarafından okunabilir bir not taşır. Mekanizma budur, hepsi bu kadar. Ayrı bir deprecation endpoint’i, header, ya da spec’in gerektirdiği bir eşlik eden belge yoktur, ki bu hem cazibesi hem de tuzağıdır: direktifi eklemek kolaydır ve görmezden gelmek de kolaydır, çünkü hiçbir şey bir client’ı ona bakmaya zorlamaz.
Deprecation nedenini gerçekten gören var mı?
Sadece şemayı doğrudan, introspection veya şemayı bilen bir editör aracılığıyla kullananlar, ve bu
bir API changelog’unun alışılmış okuyucularından daha küçük bir kitledir. Altı ay önce bir sorguya
karşı inşa edilmiş bir mobil uygulama o sorguyu zaten binary’sine pişirmiştir; deprecated olsun
olmasın, biri uygulamayı yeni alanla yeniden inşa edip bir güncelleme yayınlayana kadar price’ı
istemeye ve cevap almaya devam edecektir. Direktif, yeni kod yazan bir geliştiriciye eski alanı
kullanmamasını söyler. Zaten yayınlanmış ve çalışan client için hiçbir şey yapmaz.
| Mekanizma | Kime ulaşır |
|---|---|
@deprecated direktifi | Şemaya göz atan veya yeni sorgular yazan geliştiriciler |
| Şema linter CI hataları | Bir tane çalıştırıyorsa client kod tabanına sahip ekip |
| Bir changelog kaydı | Linter’ı olmayan bir client ekibi dahil, onu okuyan herkes |
| Hiçbir şey (alan çalışmaya devam eder) | Eski alanı kullanan zaten inşa edilmiş bir client |
Deprecated bir alan yine de bir changelog kaydı almalı mı?
Evet, ve tek başına direktiften daha fazla iş yapar, çünkü bir changelog direktifin ulaşamadığı insanlara ulaşır: şemasına göz atmadan grafiği tüketen bir ortak ekip, aylar önceki önbelleğe alınmış bir şema kopyasına karşı inşa edilmiş bir client, bunu sadece düz yazı okuyarak fark edecek herkes. API changelog’u bir kaydın çağırana genel olarak neyi borçlu olduğunu ele alır; bir GraphQL kaydı, REST’in nadiren açıkça belirtmesi gereken bir şeyi borçludur, çünkü REST çağıranları bunu versiyon numarasından çıkarır: eski alan bugün hâlâ çalışıyor mu, bir uyarıyla hâlâ çalışıyor mu, yoksa gerçekten veri döndürmeyi bırakmış mı. Direktif tek başına, şemayı hiç açmamış bir okuyucu için bunların hiçbirine cevap vermez.
Bir alanı şemadan kaldırmak gerçekte ne zaman güvenlidir?
Sadece sorgu günlükleri artık kimsenin onu istemediğini gösterdiğinde, ki bu bir kullanım
sorusudur, takvim sorusu değil. Bir alan bir yıl boyunca @deprecated taşıyabilir ve hiç yeniden
inşa edilmemiş bir client için hâlâ taşıyıcı olabilir; bir REST Sunset header’ının sık yaptığı
gibi onu sabit bir takvimde kaldırmak, o client’ı üzerinde hareket edebileceği hiçbir uyarı olmadan
bozar, çünkü GraphQL ona hiç okumadığı direktif dışında üzerinde hareket edebileceği hiçbir şey
vermez. Bir kaldırma tarihine bağlanmadan önce alan düzeyinde kullanımı loglayın, ve sıfır olmayan
herhangi bir sorgu sayısını geri sayım olarak değil, bir bekletme olarak ele alın.
Bir alan eklemek REST API’sindeki ile aynı riski taşır mı?
Yeni bir alan için daha az, çünkü bir GraphQL client’ı sadece açıkça istediği alanları alır.
price’ın yanına priceV2 eklemek, REST JSON yanıtına bir alan eklemenin katı bir deserializer’ı
bozabileceği şekilde mevcut bir sorguyu bozamaz, çünkü hiçbir şey client’ı yeni alanı istemeye
zorlamaz. Mevcut bir enum’a yeni bir değer eklemek aynı nefeste belirtmeye değer istisnadır: güçlü
tipli dillerin teşvik ettiği gibi her enum değerinde exhaustive switch yapan bir client, herhangi
bir sorgu onu istemiş olsun ya da olmasın, yeni bir değer geldiği anda bozulur. Bu güvenlik sadece
client’ın kendi isteğiyle dahil olduğu alanlar ve union üyeleri için geçerlidir; client’ın kodunun
elle numaralandırdığı kapalı bir küme için geçerli değildir.
Bir GraphQL changelog kaydı bir REST kaydının ihtiyaç duymadığı neye ihtiyaç duyar?
Sadece alan adına değil, sorgu şekline, çünkü “price alanı deprecated” bir çağıranın gerçekten
ihtiyaç duyduğu parçayı eksik bırakır: hangi tipler ve hangi sorgular ona dokunuyor. Yararlı bir
kayıt tipi, alanı, yerine geçen alanı ve, üretebiliyorsanız, üretimde hâlâ eski şekli isteyen
gerçek sorguları adlandırır. Bu son parça, deprecation bildirimini gerçek kullanıma bağlamak, REST
çağıranlarının bir URL’deki sunucu günlüklerinden bedavaya aldığı ve GraphQL çağıranlarının
almadığı bir şeydir, çünkü her sorgu ne isterse istesin aynı endpoint’e çarpar.
@deprecated direktifini alan dışında başka bir şey taşıyabilir mi?
Enum değerleri, aynı direktifi alanınkinin yerine değerin kendi tanımında kullanarak:
enum ShippingMethod {
STANDARD
EXPRESS
OVERNIGHT @deprecated(reason: "Use EXPRESS with priority: true instead.")
}
Spec, @deprecated’i tam olarak iki konum için tanımlar, bir alan tanımı veya bir enum değeri, ve
stabil sürüm itibarıyla başka hiçbir şey için; argüman ve input-field düzeyinde deprecation sadece
daha sonraki taslak dilde var, bugün çoğu sunucunun uyguladığı şeyde değil. Bu şekilde işaretlenmiş
bir enum değeri, bir sunucunun hâlâ döndürebileceği veya kabul edebileceği geçerli bir değer olarak
kalır, deprecated bir alanın yaptığı aynı breaking-olmayan vaat, ki bu da onu değeri gerçekten
kaldırmadan önce göndermeyi güvenli kılan şeydir.
FAQ
GraphQL, tüm bir endpoint için Sunset header’ı gibi bir şeyi destekler mi?
Hayır, çünkü genellikle sadece bir endpoint vardır. Deprecation zamanlaması alan düzeyinde,
@deprecated direktifinin neden metninde ve bir ekibin onun yanında yayınladığı changelog veya
geçiş kılavuzunda yaşar, bir client’ın programatik olarak okuyabileceği bir yanıt header’ında değil.
Deprecated bir alan kaldırılıp sonra farklı bir tiple yeniden eklenebilir mi?
Sadece yeni bir alan adı olarak. Aynı alan adını değişmiş bir tiple yeniden tanıtmak, tam olarak
deprecation döngüsünün önlemek için var olduğu breaking change’dir; yerine geçene priceV2’nin
yaptığı gibi kendi adını verin, ve isim yeniden kullanılabilir hale gelmeden önce eskisinin
tamamen sönmesine izin verin.
@deprecated neden metni changelog kaydına bağlantı vermeli mi?
Şema araçları destekliyorsa, evet. Neden alanı düz bir string kabul eder, ve o string içindeki bir
URL, introspection çıktısına bakan bir geliştiriciden bir changelog kaydının verebileceği daha
kapsamlı açıklamaya giden en kısa yoldur.
Bir GraphQL şema değişikliği hiç REST’in olmadığı bir şekilde geriye dönük uyumlu mudur? Eklemeli alan değişiklikleri, evet, yukarıdaki nedenden dolayı: client’lar sadece istedikleri şeyi alır. Yeni enum değerleri istisnadır, çünkü kapalı bir kümeyi numaralandıran bir client, beklemediği bir değerde bozulabilir. Kaldırmalar ve tip değişiklikleri REST karşılıkları kadar tam olarak breaking’dir.
Bu yazıdaki teknik iddialar bağımsız olarak kontrol edilmedi. Yanlış bir şey varsa bize söyle, düzeltelim.