Mimari
MimariDirektifler Aracılığıyla IFTTT

Direktifler Aracılığıyla IFTTT

Gato GraphQL, direktifler aracılığıyla IFTTT (If This Then That — Bunu Yaparsan Şunu Yap) stratejileri uygulama imkânı sunar. Bu direktifler, sorguda belirli bir alan veya direktif bulunduğunda sorguya dinamik olarak eklenir.

Genel olarak IFTTT, belirli bir olay gerçekleştiğinde eylemleri tetikleyen kurallardır. Bizim durumumuzda olay/eylem çiftleri şöyledir:

  • "Sorguda X alanı bulunursa" → "X alanına Y direktifini ekle"
  • "Sorguda Z direktifi bulunursa" → "Z direktifinden önce/sonra Y direktifini çalıştır"

IFTTT direktiflerinin şemaya dinamik olarak eklenmesi özyinelemeli bir süreçtir: söz konusu direktifin kendisi de kendi IFTTT direktifleri kümesiyle yapılandırılabilir ve bu direktifler de direktif zincirine eklenir.

Nerede Kullanılır

Arka planda, Gato GraphQL'deki istemciler GraphQL şemasını yapılandırmak için bu mekanizmayı kullanır.

Örneğin, Access Control işlemlere, alanlara ve direktiflere hangi erişim denetimi kurallarının uygulanacağını seçmemize olanak tanır. Bu kuralların GraphQL şemasındaki ilgili öğelere uygulanması IFTTT sayesinde gerçekleşir.

Erişim denetimi girişi

Genel olarak bazı kullanım senaryoları şunlardır:

Alan Bazında Önbellek Denetimi max-age Değerini Tanımlama

Tüm alanlara bir @CacheControl direktifi ekleyerek maxAge parametresinin değerini özelleştirin: Post'un url alanı için 1 yıl, title alanı için 1 saat.

Erişim Denetimini Yapılandırma

User tipinin email alanına @validateDoesLoggedInUserHaveAnyRole direktifi ekleyerek yalnızca yöneticilerin kullanıcı e-posta adresini sorgulayabilmesini sağlayın.

Erişim Denetimini Önbellek Denetimiyle Senkronize Etme

Direktifleri zincirleyerek, kullanıcının bir alana/direktife erişip erişemeyeceği doğrulanırken yanıtın önbelleğe alınmamasını sağlayabiliriz. Örneğin:

  • me alanına @validateIsUserLoggedIn direktifini ekleyin
  • @validateIsUserLoggedIn direktifine maxAge argüman değeri 0 olan @CacheControl direktifini ekleyin.

Güvenliği Güçlendirme

@translate direktifine @validateIsUserLoggedIn direktifi ekleyerek kötü niyetli aktörlerin sunucuyu çökertebilecek ve faturayı artırabilecek queries çalıştırmasını önleyin (bu durumda @translate, Google Translate tabanlıdır ve bu hizmetin kullanımı ücrete tabidir).

Nasıl Çalışır

IFTTT aracılığıyla şemaya direktifler nasıl eklenir? Örneğin, myPosts alanını çalıştıran kullanıcının beklenen author rolüne sahip olduğunu doğrulamak ya da aksi takdirde hata göstermek için özel bir @authorize(role: String!) direktifi oluşturmak istediğimizi varsayalım.

Şemayı SDL kullanarak oluştursaydık şöyle görünürdü:

directive @authorize(role: String!) on FIELD_DEFINITION
 
type User {
  myPosts: [Post] @authorize(role: "author")
}

IFTTT kuralı, yukarıdaki SDL'nin bildirdiği amacın aynısını tanımlar: myPosts alanı her istendiğinde, o alanda @authorize(role: "author") direktifini çalıştır. Dolayısıyla sorguda myPosts alanı her bulunduğunda motor, çalıştırılabilir sorguda o alana @authorize(role: 'author') direktifini otomatik olarak ekler.

IFTTT kuralları yalnızca bir alanla karşılaşıldığında değil, bir direktifle karşılaşıldığında da tetiklenebilir. Örneğin, "Sorguda @translate direktifi bulunduğunda o alanda @cache(time: 3600) direktifini çalıştır" kuralını yapılandırabiliriz.

IFTTT direktiflerinin sorguya eklenmesi özyinelemeli bir süreçtir: IFTTT kuralları tarafından işlenecek yeni bir olay tetiklenir ve bu durum potansiyel olarak sorguya başka direktifler eklenmesine yol açar.

Örneğin, "@cache direktifi bulunduğunda @log direktifini çalıştır" kuralı, alanın çalıştırılmasına ilişkin bir günlük kaydı oluşturur ve ardından bu yeni eklenen direktife dair yeni bir olay tetikler.

PHP Kodu Aracılığıyla Yapılandırma

User tipinin roles ve capabilities alanları hassas bilgi olarak değerlendirilebileceğinden rastgele kullanıcılar tarafından erişilebilir olmamalıdır.

Bu nedenle bu iki alana @validateDoesLoggedInUserHaveAnyRole direktifini ekleyebilir ve yalnızca belirli bir role sahip kullanıcıların (ortam değişkeni aracılığıyla yapılandırılan) bu alanlara erişebileceğini doğrulayacak şekilde yapılandırabiliriz. Yapılandırma bir CompilerPass aracılığıyla sağlanır:

$accessControlManagerDefinition = $containerBuilderWrapper->getDefinition(AccessControlManagerInterface::class);
 
if ($roles = Environment::anyRoleLoggedInUserMustHaveToAccessRolesFields()) {
  $accessControlManagerDefinition->addMethodCall(
    'addEntriesForFields',
    [
      UserRolesAccessControlGroups::ROLES,
      [
        [RootObjectTypeResolver::class, 'roles', $roles],
        [UserObjectTypeResolver::class, 'roles', $roles],
        [RootObjectTypeResolver::class, 'capabilities', $roles],
        [UserObjectTypeResolver::class, 'capabilities', $roles],
      ]
    ]
  );
}
if ($capabilities = Environment::anyCapabilityLoggedInUserMustHaveToAccessRolesFields()) {
  $accessControlManagerDefinition->addMethodCall(
    'addEntriesForFields',
    [
      UserCapabilitiesAccessControlGroups::CAPABILITIES,
      [
        [RootObjectTypeResolver::class, 'roles', $capabilities],
        [UserObjectTypeResolver::class, 'roles', $capabilities],
        [RootObjectTypeResolver::class, 'capabilities', $capabilities],
        [UserObjectTypeResolver::class, 'capabilities', $capabilities],
      ]
    ]
  );
}

Sorgu çalıştırılırken, giriş yapmamış kullanıcılar ve gerekli rollere sahip olmayan kullanıcılar bu alanlara erişemeyecektir.