İndiyədək məlumatı yalnız oxuyurduq. Amma demək olar ki, hər tətbiq onu dəyişməlidir də: post yaratmaq, yazı səhvini düzəltmək, şərhi silmək. GraphQL-də bunun üçün mutation-lar (mutations) var. Mağazanı təsəvvür edin. Query — vitrinə baxmaqdır: baxırsınız və heç nəyi dəyişmirsiniz. Mutation — kassadır: dünyada nəyisə dəyişirsiniz (alırsınız, rəsmiləşdirirsiniz, qaytarırsınız) və dərhal çek alırsınız — nəyin alındığına dair təsdiq. GraphQL mutation-unda «çek» cavabda qaytarılmasını istədiyiniz obyektdir. Kassa isə vitrindən fərqli olaraq növbə ilə xidmət edir — bu barədə də danışacağıq. Bu dərsdə blogumuzun postları üçün CRUD mutation-larını yazacağıq.
Mutation-un query-dən fərqi
Sintaksis baxımından mutation sorğudan az fərqlənir: query əvəzinə mutation yazılır, içəridə isə eyni sahələr, arqumentlər, dəyişənlər, alias-lar və fraqmentlər olur. Fərqlər mənada və bir texniki detaldadır:
query | mutation | |
|---|---|---|
| Nə üçün | məlumatı oxumaq | yaratmaq, dəyişmək, silmək |
| Kök tip | Query | Mutation |
| Yuxarı səviyyə sahələri | paralel icra oluna bilər | ciddi növbə ilə icra olunur |
| Tipik adlar | isimlər: posts, user | fel və isim: createPost |
| Təkrar və keş | təkrarlamaq və keşləmək təhlükəsizdir | təkrar dəyişikliyi də təkrarlayır |
«Query oxuyur, mutation yazır» razılaşmasını server texniki cəhətdən yoxlamır: sorğunun resolver-i də nəyisə yaza bilərdi. Amma bütün ekosistem — müştərilər, keşlər, alətlər — buna güvənir.
⚠️
query-nin içində məlumatı dəyişməyin. Müştəri istənilən an query-ni təkrar göndərə, nəticəsini keşləyə və ya sahələri paralel icra edə bilər — və «zərərsiz» oxuma birdən nəyisə dəyişməyə başlayar, özü də gözlənilməz sırada.
İlk mutation: post yaradırıq
Mutation-u addım-addım quraq.
Addım 1. Giriş məlumatları. Mutation-un adətən çoxlu parametri olur: başlıq, mətn, müəllif. Bir yığın arqument əvəzinə onları bir input obyektində toplayırlar — input tiplərinə sxem dərsində rast gəlmişdik. Postun yaradılması və qismən dəyişdirilməsi üçün iki tip lazımdır:
input CreatePostInput {
title: String!
body: String!
published: Boolean = false
authorId: ID!
}
input UpdatePostInput {
title: String
body: String
published: Boolean
}CreatePostInput-da məcburi sahələr ! ilə işarələnib, published isə defolt olaraq false-dur. UpdatePostInput-da bütün sahələr ixtiyaridir: müştəri yalnız dəyişmək istədiyini göndərir, qalanına server toxunmur. authorId hələlik müştəridən gəlir; avtorizasiya dərsində müəllif daxil olmuş istifadəçiyə görə müəyyən ediləcək — «mən kiməm?» sualında müştəriyə etibar etmək olmaz.
Addım 2. Nəticə. Mutation nə qaytarsın? Post-un özünü qaytarmaq olar, amma onda yoxlama xətası haqqında xəbər verməyə yer qalmır. Ona görə xüsusi tip qaytarmaq qəbul olunub — payload («əməliyyatın nəticəsi»):
type UserError {
field: String
message: String!
}
type CreatePostPayload {
post: Post
errors: [UserError!]!
}
type UpdatePostPayload {
post: Post
errors: [UserError!]!
}
type DeletePostPayload {
deletedPostId: ID
errors: [UserError!]!
}