Skip to main content

Mutation

Introduction to GraphQL Input

In GraphQL, GraphQLObjects returned by queries are dynamic objects of arbitrary shapes. However, if mutation operations accept object parameters, they must be GraphQLInputs, which are static objects of fixed shapes.

See GraphQLInput to learn more.

Take the GraphQL declaration file in the example schema.graphqls as an example:

type Book implements CommonEntity { ❶
id: Long!
name: String!
edition: Int!
price: BigDecimal!
store: BookStore
authors: [Author!]!
createdTime: LocalDateTime!
modifiedTime: LocalDateTime!
tenant: String!
}

input BookInput { ❷
id: Long
name: String!
edition: Int
price: BigDecimal!
storeId: Long
authorIds: [Long!]!
}

...other code omitted...
  • ❶ Types declared with the type keyword are dynamic types used to express arbitrary data structures, used as GraphQL output types

  • ❷ Types declared with the input keyword are static types used to express fixed data structures, used as GraphQL input types

Define Jimmer Input DTO

Jimmer Input DTOs are introduced in great detail in Save Command/Input DTO, which will not be repeated here.

Jimmer provides two ways to define Input DTOs:

Using the DTO language can achieve our goal very efficiently, so this article adopts this approach.

  1. In the project where the entity is defined, create the directory src/main/dto

  2. Under src/main/dto, create subdirectories com/yourcompany/yourproject/model according to the package path where the entities are located

  3. Under the directory created in the previous step, create the file Book.dto. The file must have the same name as the entity class and the extension must be dto

  4. Edit this file and use the DTO language to define various DTO shapes for the Book entity

    Book.dto
    input BookInput {

    #allScalars(Book)

    id(store)

    id(authors) as authorIds
    }

    ...other DTO definitions omitted...

After compilation, the following Input DTO will be generated automatically:

BookInput.java
@GeneratedBy(file = "<your_project>/src/main/dto/Book.dto")
public class BookInput implements Input<Book> {

@Nullable
private Long id;

private String name;

private int edition;

private BigDecimal price;

@Nullable
private Long storeId;

private List<Long> authorIds;

@Override
public Book toEntity() {
...omitted...
}

...other members omitted...
}
  • ❶ The BookInput class implements the interface org.babyfish.jimmer.Input, which supports the toEntity method to convert the current Input DTO object to a Jimmer dynamic entity object.

  • ❷ Implements the Input.toEntity method

Implement GraphQL mutation

BookStoreService.java
package com.example.business;

import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.MutationMapping;
import org.springframework.stereotype.Controller;

...other imports omitted...

@Controller
public class BookStoreService {

private final BookStoreRepository bookStoreRepository;

public BookStoreService(BookStoreRepository bookStoreRepository) {
this.bookStoreRepository = bookStoreRepository;
}

@MutationMapping
@Transactional
public Book saveBook(
@Argument BookInput input ❷
) {
// `save(input)` is shorthand for `save(input.toEntity())`
return bookRepository.save(input);
}
}
  • ❶ Use annotation @org.springframework.graphql.data.method.annotation.MutationMapping

  • ❷ Use the static Input DTO type BookInput to allow users to pass only data structures of specified shapes to conform to GraphQLInput

  • Save command to save arbitrary data structures in one line

    Here bookRepository.save(input) is actually shorthand for bookRepository.save(input.toEntity()).

    tip

    No matter how simple or relatively complex the data structure defined by the BookInput type, it can be saved in one line. This is the core value of the save command feature.