İ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:

querymutation
Nə üçünməlumatı oxumaqyaratmaq, dəyişmək, silmək
Kök tipQueryMutation
Yuxarı səviyyə sahələriparalel icra oluna bilərciddi növbə ilə icra olunur
Tipik adlarisimlər: posts, userfel və isim: createPost
Təkrar və keştəkrarlamaq və keşləmək təhlükəsizdirtə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:

graphql
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»):

graphql
type UserError {
  field: String
  message: String!
}

type CreatePostPayload {
  post: Post
  errors: [UserError!]!
}

type UpdatePostPayload {
  post: Post
  errors: [UserError!]!
}

type DeletePostPayload {
  deletedPostId: ID
  errors: [UserError!]!
}