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端点将被自动添加。