Witajcie w już trzecim poście dotyczącym GraphQL. Jeśli ominęliście je to gorąco zachęcam do odwiedzenia: Jak zacząć zabawę z GraphQL oraz Typy i schematy w GrapQL. Jednak odbieranie danych to za mało. Musimy mieć możliwość wysyłania własnych danych. Dziś opiszę jak można w tym języku zapytań to zrobić przy pomocy mutacji(mutation).

Przekazywanie argumentów

Jednak zanim przejdę do właściwej części, w której pokażę jak wykonywać zapytania Insert i Delete zatrzymam się jeszcze na chwilę w zwykłych zapytaniach. Bardzo często nie potrzebujemy listy ze wszystkimi danymi. Zazwyczaj potrzebujemy tylko jeden konkretny element by go wyświetlić lub zedytować. W GraphQL do tego celu możemy wykorzystać przekazywanie argumentów. W schemacie możemy sobie zdefiniować nowe pole o takiej strukturze:

getPost(id:ID!):Post

Dzięki temu takie pole może przyjmować dodatkowe argumenty. To została nam jeszcze funkcja zwracająca wynik:

getPost:({id})=>posts[id],

Warto zauważyć, że argumentem jest obiekt. Tak samo muszą być przekazane dane podczas tworzenia zapytania. Nie możemy po prostu przekazać wartości, ponieważ dostaniemy następujący błąd: arguments_error Przy wysyłaniu zapytania musimy wysłać obiekt z nazwami pól odpowiadającymi tym, które zdefiniowaliśmy w schemacie. arguments_success

Mutacje

Mutacje są specjalnym rodzajem zapytania, które ma zmodyfikować dane na serwerze czyli będzie to odpowiednik INSERT, EDIT i DELETE z REST’a. Definiuje się je i używa podobnie do zwykłych zapytań a szczególnie pokazanych w poprzednim paragrafie zapytań z argumentem. Zapytania z tej grupy umieszczamy w specjalnym typie wewnątrz schematu:


type Mutation{
}

Mając coś takiego można tworzyć pola, które są nam potrzebne. Tworzymy je identycznie jak podczas przekazywania argumentów:

addPost(title:String,author:String):Post,

I od razu funkcję która to obsłuży :

addPost:({title,author})=>{
    posts[nextIndex]={title,author};
    nextIndex++;
    return {title,author};
},

Nad tworzeniem zapytań warto się chwilę zatrzymać ponieważ wygląda trochę inaczej. Pierwsza różnica to słowo kluczowe mutation na początku zapytania. Drugie to musimy podać jakie pola chcemy otrzymać z powrotem.

mutation_subfield

Bez tego dostaniemy następujący błąd:

mutation_error

Da się to ominąć ustawiając w schemacie zwracany typ na Boolean

addPost(title:String,author:String):Boolean

Wtedy możemy wykonać następujące zapytanie i nie dostaniemy błędu:

mutation_bool

Na sam koniec jeszcze wspomnę o możliwości zebrania wszystkich wymaganych pól, które należy przekazać w postaci obiektu. Nie możemy tutaj użyć słówka kluczowego type ale mamy za to słówko kluczowe input. Może to wyglądać w następujący sposób:

inputPostInput{
    title:String,
    author:String
}

type Mutation{
    addPost(post:PostInput):Post,
}

addPost:({post})=>{
    posts[nextIndex]=post;
    nextIndex++;
    return post;
},

Dzięki temu możemy zredukować ilość pól o jakich trzeba pamiętać i możemy używać tego w wielu miejscach np.: dodawanie nowego elementu i jego edycja może wymagać tych samych pól więc nie musimy powielać ich wszystkich tylko użyć odpowiedniego typu.