GraphQL SPQR和Spring Boot入門 | baeldung

banq發表於2022-04-06

GraphQL Schema Publisher & Query Resolver,簡稱 SPQR,是從帶註釋的 Java 類中生成 GraphQL 模式。
在傳統的方法中,如果我們想把GraphQL新增到我們的專案中,我們將不得不遵循兩個步驟:
  • 首先,我們必須在專案中新增GraphQL schema資料結構檔案。
  • 其次,我們需要編寫各自的Java POJO,代表模式中的每個型別。
  •  

這意味著我們要在兩個地方維護相同的資訊:在模式檔案和Java類中。這種方法很容易出錯,而且需要花費更多精力來維護專案。
SPQR試圖解決這種不匹配mismatch現象:

設定
在Maven中加入:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>io.leangen.graphql</groupId>
    <artifactId>spqr</artifactId>
    <version>0.11.2</version>
</dependency>


模型類:

public class Book {
    private Integer id;
    private String author;
    private String title;
}

正如我們在上面看到的,它不包括任何SPQR註釋。如果我們不擁有原始碼,但想從這個庫中獲益,這可能非常有用。

服務:

@Service
public class BookService implements IBookService {

    Set<Book> books = new HashSet<>();

    public Book getBookWithTitle(String title) {
        return books.stream()
            .filter(book -> book.getTitle()
                .equals(title))
            .findFirst()
            .orElse(null);
    }

    public List<Book> getAllBooks() {
        return books.stream()
            .collect(Collectors.toList());
    }

    public Book addBook(Book book) {
        books.add(book);
        return book;
    }

    public Book updateBook(Book book) {
        books.remove(book);
        books.add(book);
        return book;
    }

    public boolean deleteBook(Book book) {
        return books.remove(book);
    }
}


用graphql-spqr公開服務
剩下的事情就是建立一個解析器,它將暴露GraphQL的改變和查詢。為了做到這一點,我們將使用兩個重要的SPQR註解--@GraphQLMutation和@GraphQLQuery。

@Service
public class BookResolver {

    @Autowired
    IBookService bookService;

    @GraphQLQuery(name = "getBookWithTitle")
    public Book getBookWithTitle(@GraphQLArgument(name = "title") String title) {
        return bookService.getBookWithTitle(title);
    }

    @GraphQLQuery(name = "getAllBooks", description = "Get all books")
    public List<Book> getAllBooks() {
        return bookService.getAllBooks();
    }

    @GraphQLMutation(name = "addBook")
    public Book addBook(@GraphQLArgument(name = "newBook") Book book) {
        return bookService.addBook(book);
    }

    @GraphQLMutation(name = "updateBook")
    public Book updateBook(@GraphQLArgument(name = "modifiedBook") Book book) {
        return bookService.updateBook(book);
    }

    @GraphQLMutation(name = "deleteBook")
    public void deleteBook(@GraphQLArgument(name = "book") Book book) {
        bookService.deleteBook(book);
    }
}


控制器
最後,我們將定義一個Spring @RestController。為了用SPQR暴露服務,我們將配置GraphQLSchema和GraphQL物件。

@RestController
public class GraphqlController {

    private final GraphQL graphQL;

    @Autowired
    public GraphqlController(BookResolver bookResolver) {
        GraphQLSchema schema = new GraphQLSchemaGenerator()
          .withBasePackages("com.baeldung")
          .withOperationsFromSingleton(bookResolver)
          .generate();
        this.graphQL = new GraphQL.Builder(schema)
          .build();
    }

值得注意的是,我們必須將我們的BookResolver註冊為一個單例

在我們使用SPQR的過程中,最後一項任務是建立一個/graphql端點。它將作為與我們的服務的單一聯絡點,並將執行所要求的查詢和變化。

@PostMapping(value = "/graphql")
    public Map<String, Object> execute(@RequestBody Map<String, String> request, HttpServletRequest raw)
      throws GraphQLException {
        ExecutionResult result = graphQL.execute(request.get("query"));
        return result.getData();
    }
}


測試
我們可以通過檢查/graphql端點來檢查結果。例如,讓我們通過執行以下cURL命令來檢索所有的圖書記錄。

curl -g \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"query":"{getAllBooks {id author title }}"}' \
  http://localhost:8080/graphql



使用GraphQL SPQR Spring Boot啟動器
從事SPQR工作的團隊已經建立了一個Spring Boot啟動器,這使得使用它更加容易。讓我們來看看吧

<dependency>
    <groupId>io.leangen.graphql</groupId>
    <artifactId>graphql-spqr-spring-boot-starter</artifactId>
    <version>0.0.6</version>
</dependency>


@Service
@GraphQLApi
public class BookService implements IBookService {

    Set<Book> books = new HashSet<>();

    @GraphQLQuery(name = "getBookWithTitle")
    public Book getBookWithTitle(@GraphQLArgument(name = "title") String title) {
        return books.stream()
            .filter(book -> book.getTitle()
                .equals(title))
            .findFirst()
            .orElse(null);
    }

    @GraphQLQuery(name = "getAllBooks", description = "Get all books")
    public List<com.baeldung.sprq.Book> getAllBooks() {
        return books.stream()
            .toList();
    }

    @GraphQLMutation(name = "addBook")
    public Book addBook(@GraphQLArgument(name = "newBook") Book book) {
        books.add(book);
        return book;
    }

    @GraphQLMutation(name = "updateBook")
    public Book updateBook(@GraphQLArgument(name = "modifiedBook") Book book) {
        books.remove(book);
        books.add(book);
        return book;
    }

    @GraphQLMutation(name = "deleteBook")
    public boolean deleteBook(@GraphQLArgument(name = "book") Book book) {
        return books.remove(book);
    }
}

我們不需要GraphqlController類:/graphql端點將被自動新增。

相關文章