Kategorie
java

Netflix DGS Mutacje

Mutacje w Netflix DGS są bardzo przyjemne do realizacji. W końcu nie mogło być inaczej, bo zarówno Spring Boot, jak i biblioteki ze stosu OSS Netflixa przyzwyczaiły nas do fajnego API.

Zobaczmy, jak to będzie wyglądało w kodzie.

junior-hava-developer-handbook-what-to-know

Mutacje GraphQL

Bardzo dużo czasu poświęca się w przypadku GraphQL na omawianie zapytań do serwera. To dosyć naturalne, bo zwykle w kontekście np. frontów myślimy o ekranach i danych, jakie będziemy na nich wyświetlać. A je trzeba przecież skądś pobrać. Jednak… dane też trzeba zwykle modyfikować.

Netflix DGS oczywiście wspiera mutacje danych. I zapewnia poprawną ich interpretację z poziomu obsługi Spring Boot.

Z punktu widzenia GraphQL typ Mutation, jest drugim typem specjalnym w ramach schema. Wcześniej pisałem o typie Query. W ramach Mutation definiujemy wszystkie mutacje danych jakie będą możliwe w naszym API. Jest to drugi entry point do naszej usługi.

Rozszerzymy teraz schema naszej usługi o trochę więcej danych. Przede wszystkim pozwolimy na dodawanie komentarzy do poszczególnych projektów. Do tego przyda nam się wprowadzenie identyfikatora projektu oraz list komentarzy. Najprościej, jak się da.

type Query {
  projects(name: String): [Project]
}

type Mutation {
  addComment(projectId: ID!, comment: String!): Boolean
}

type Project {
  id: ID!
  name: String
  description: String
  comments: [String]
}

W schema powyżej pojawiło się pole addComment w ramach naszego entry point Mutation. Zakładamy, że komentarz będzie dodany do konkretnego projektu i nie będzie on nullem. Na to wskazuje wykrzyknik po typie argumentu.

Mutacje w Netflix DGS od strony kodu

Przede wszystkim klasa naszego projektu nieco się zmieniła. Jej aktualna implementacja wygląda następująco:

public class Project {
  private String id;
  private String name;
  private String description;
  private List<String> comments = new ArrayList<>();

  public Project(String id, String name, String description) {
    this.id = id;
    this.name = name;
    this.description = description;
  }

  public String id() { return id; }

  public String name() {
    return name;
  }

  public String description() {
    return description;
  }

  public void addComment(String comment) {
    comments.add(comment);
  }
}

Widzimy, że jej struktura przypomina tę z schema GraphQL.

Za obslugę mutacji będzie odpowiadać nowy komponent:

@DgsComponent
public class ProjectMutation {
  @DgsData(parentType = "Mutation", field = "addComment")
  public Boolean projects(DataFetchingEnvironment dfe) {
    String projectId = dfe.getArgument("projectId");
    String comment = dfe.getArgument("comment");

    Optional<Project> project = DATA.PROJECTS.stream()
        .filter(p -> Objects.equals(p.id(), projectId))
        .findFirst();
    project.ifPresent(p -> p.addComment(comment));
    return project.isPresent();
  }
}

Tutaj na uwagę zasługuje argument DataFetchingEnvironment. Jest to element, który pozwala nam dostać się do informacji zawartej w argumentach mutacji.

Korzystanie z DataFetchingEnvironment nie jest jednak zbyt wygodne. Nie lubimy podatnej na błędu obsługi ręcznej wiązania argumentów projectId i comment. Spring również przyzwyczaił nas do automatycznego wiązania danych. O tym też pomyślał zespół pracujący nad Netflix DGS i w przypadku mutacji możemy skorzystać również z adnotacji @InputArgument. Dzięki temu nasza metoda obsługująca może wyglądać następująco:

@DgsComponent
public class ProjectMutation {
  @DgsData(parentType = "Mutation", field = "addComment")
  public Boolean projects(@InputArgument("projectId") String projectId, @InputArgument("comment") String comment) {
    Optional<Project> project = DATA.PROJECTS.stream()
        .filter(p -> Objects.equals(p.id(), projectId))
        .findFirst();
    project.ifPresent(p -> p.addComment(comment));
    return project.isPresent();
  }
}

Od strony użytkownika

Do naszych testów ponownie wykorzystamy narzędzie dostępne pod http://localhost:8080/graphiql. Na początku nasze zapytanie:

{
  projects {
    id,
    name,
    comments
  }
}

zwróci listę projektów bez komentarzy:

{
  "data": {
    "projects": [
      {
        "id": "1",
        "name": "GraphQL",
        "comments": []
      },
      {
        "id": "2",
        "name": "Netflix DGS",
        "comments": []
      },
      {
        "id": "3",
        "name": "Spring Boot",
        "comments": []
      },
      {
        "id": "4",
        "name": "Spring Framework",
        "comments": []
      }
    ]
  }
}

Wykołanie mutacji danych będzie wyglądało następująco:

mutation {
  addComment(projectId: 2, comment: "Awesome project") 
} 

W odpowiedzi dostajemy wynik operacji. Zgodnie z naszą implementacją jest to po prostu boolean mówiący o tym, czy się udało dodać komentarz, czy też nie:

{
  "data": {
    "addComment": true
  }
}

Możemy dodać dalej kolejny komentarz i odpytać usługę o aktualne dane:

{
  projects {
    id
    name
    comments
  }
}

W odpowiedzi widzimy, że nasz projekt o identyfikatorze 2 został już skomentowany dwukrotnie:

{
  "data": {
    "projects": [
      {
        "id": "1",
        "name": "GraphQL",
        "comments": []
      },
      {
        "id": "2",
        "name": "Netflix DGS",
        "comments": [
          "Awesome project",
          "Really awesome library!"
        ]
      },
      {
        "id": "3",
        "name": "Spring Boot",
        "comments": []
      },
      {
        "id": "4",
        "name": "Spring Framework",
        "comments": []
      }
    ]
  }
}

Podsumowanie

Netflix DGS i mutacje idą w parze. Bardzo fajnie ułatwiają pracę z GraphQL w Spring Boot.

Teoretycznie mogliśmy te i inne operacji realizować wcześniej, przy okazji bardziej niskopoziomowych bibliotek. Jednak dobrze przygotowana nakładka na te biblioteki, czyli DGS, sprawia, że kodowanie jest po prostu przyjemniejsze.

Daj znać, czy planujesz skorzystać z Netflix DGS w swoim następnym projekcie?

HINT dla poszukujących pierwszej pracy. Hey, pamiętacie o tym, jak pisałem parę razy (np. tutaj ✔️ Perfekcyjna rozmowa techniczna Junior Programista i tutaj Rekrutacja Junior Programista – podsumowanie), że projektu na Github mogą być Waszym silnym argumentem? Z moich obserwacji wynika, że prawie 100% takich projektów jest w Spring Boot. Netflix DGS, mechanizm zapytań i mutacje, to chyba niezły element, którym można się wyróżnić – zgodzisz się ze mną?

5 3 votes
Article Rating
Subscribe
Powiadom o
guest
0 komentarzy
Inline Feedbacks
View all comments