IFTTT melalui direktif
Gato GraphQL menyediakan kemampuan untuk mengimplementasikan strategi IFTTT (If This Then That, "jika ini maka itu") melalui direktif. Direktif-direktif ini ditambahkan secara dinamis ke query setiap kali field atau direktif tertentu ada dalam query.
Secara umum, IFTTT adalah aturan yang memicu tindakan setiap kali suatu peristiwa tertentu terjadi. Dalam kasus kita, pasangan peristiwa/tindakannya adalah:
- Jika "field X ditemukan dalam query" maka "lampirkan direktif Y ke field X"
- Jika "direktif Z ditemukan dalam query" maka "jalankan direktif Y sebelum/setelah direktif Z"
Menambahkan direktif IFTTT secara dinamis ke skema adalah proses rekursif: direktif semacam itu dapat, dengan sendirinya, dikonfigurasi dengan sekumpulan direktif IFTTT miliknya sendiri yang juga ditambahkan ke rantai direktif.
Di mana digunakan
Di balik layar, klien dalam Gato GraphQL menggunakan mekanisme ini untuk mengonfigurasi skema GraphQL.
Sebagai contoh, Access Control memungkinkan kita memilih aturan kontrol akses mana yang akan diterapkan pada operasi, field, dan direktif. Melalui IFTTTlah aturan-aturan ini diterapkan pada elemen-elemen dari skema GraphQL.

Secara umum, berikut adalah beberapa contoh penggunaannya:
Mendefinisikan max-age cache control per field
Melampirkan direktif @CacheControl ke semua field, dengan menyesuaikan nilai parameter maxAge: 1 tahun untuk field url milik Post, dan 1 jam untuk field title.
Menyiapkan kontrol akses
Melampirkan direktif @validateDoesLoggedInUserHaveAnyRole ke field email dari tipe User, sehingga hanya admin yang dapat melakukan query email pengguna.
Menyinkronkan kontrol akses dengan cache control
Dengan merantaikan direktif, kita dapat memastikan bahwa setiap kali memvalidasi apakah pengguna dapat mengakses field/direktif, respons tidak akan di-cache. Misalnya:
- Lampirkan direktif
@validateIsUserLoggedInke fieldme - Lampirkan direktif
@CacheControldengan nilai argumenmaxAgesebesar0ke direktif@validateIsUserLoggedIn.
Memperketat keamanan
Melampirkan direktif @validateIsUserLoggedIn ke direktif @translate, untuk mencegah aktor jahat menjalankan query terhadap layanan GraphQL yang dapat membuat server tidak responsif dan membengkakkan tagihannya (dalam hal ini, @translate berbasis Google Translate dan membayar biaya untuk menggunakan layanan ini)
Cara kerjanya
Bagaimana kita menambahkan direktif ke skema melalui IFTTT? Katakanlah, misalnya, kita ingin membuat direktif kustom @authorize(role: String!), untuk memvalidasi bahwa pengguna yang menjalankan field myPosts memiliki peran author yang diharapkan, atau menampilkan error sebaliknya.
Jika kita membuat skema menggunakan SDL, tampilannya akan seperti ini:
directive @authorize(role: String!) on FIELD_DEFINITION
type User {
myPosts: [Post] @authorize(role: "author")
}Aturan IFTTT mendefinisikan maksud yang sama dengan yang dideklarasikan oleh SDL di atas: setiap kali meminta field myPosts, jalankan direktif @authorize(role: "author") padanya. Kemudian, setiap kali field myPosts ditemukan dalam query, engine akan secara otomatis melampirkan @authorize(role: 'author') ke field tersebut pada query yang dapat dieksekusi.
Aturan IFTTT juga dapat dipicu saat menemukan direktif, bukan hanya field. Misalnya, kita dapat mengatur aturan "Setiap kali direktif @translate ditemukan dalam query, jalankan direktif @cache(time: 3600) pada field tersebut".
Menambahkan direktif IFTTT ke query adalah proses rekursif: ini akan memicu peristiwa baru yang diproses oleh aturan IFTTT, yang berpotensi melampirkan direktif lain ke query, dan seterusnya.
Misalnya, aturan "Setiap kali direktif @cache ditemukan, jalankan direktif @log" akan mencatat entri tentang eksekusi field, lalu memicu peristiwa baru terkait direktif yang baru ditambahkan ini.
Mengaturnya melalui kode PHP
Tipe User memiliki field roles dan capabilities, yang dapat dianggap sebagai informasi sensitif, sehingga tidak boleh diakses oleh pengguna sembarang.
Jadi kita dapat melampirkan direktif @validateDoesLoggedInUserHaveAnyRole ke dua field ini, dikonfigurasi untuk memvalidasi bahwa hanya pengguna dengan peran tertentu (dikonfigurasi melalui variabel lingkungan) yang dapat mengaksesnya. Konfigurasi disediakan melalui CompilerPass:
$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],
]
]
);
}Saat menjalankan query, pengguna yang belum login dan pengguna tanpa peran yang diperlukan tidak akan diizinkan mengakses field-field tersebut.