在spring-boot中使用graphql
首先构建spring-boot项目,pom.xml文件中加入
com.graphql-java-kickstart
graphql-java-tools
5.4.0
com.graphql-java
graphql-spring-boot-starter
5.0.2
com.graphql-java
graphiql-spring-boot-starter
5.0.2
接着定义graphql的schema,在resources目录下任意位置的*.graphqls文件都会被扫描到,作为graphql 的schema。
这里在resources下先建一个文件夹/graphql,建立schema文件
schema.graphqls
type Query {
user(nickname: String): User
users: [User]
article(title: String!): Article
}
type Mutation {
addUser(mail: String!, nickname: String!, password: String!): User
addArticle(title: String!, content: String!, authorId: String!): Article
}
type User {
id: String!
mail: String!
nickname: String!
password: String!
description: String
}
type Article {
id: String!
author: User!
title: String!
content: String!
createBy: String
thumbUp: Int
}
Resolver 和数据类
GraphQL Java Tools可以将schema中定义的类型的属性与java对象的属性或方法对应起来。即上面的User类型,可以使用一个类与之对应
public class User {
@Id
private String id;
private String nickname;
private String mail;
private String password;
private String description;
// 构造器,getter和setter
}
但是在Article类型中author的属性是User,我们该如何解决呢?
这时我们可以使用一个GraphQLResolver指定某个类型的解析
@Component
public class ArticleResolver implements GraphQLResolver {
private final UserRepository userRepository;
public ArticleResolver(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User author(Article article) {
return userRepository.findById(article.getAuthorId()).get();
}
}
指定Article类型的解析方式,其中标量类型可以直接从Aritcle的java类属性中获取,所以不必写方法,对于author这个属性,其类型为User,我们指定author()方法进行解析。
那么到底type Article {...}schema里面的属性怎么解析呢?是与数据类进行映射,还是与resolver中的方法进行映射?
官网上给出了映射的优先级:
首先是resolver
method 属性名(...)
method is属性名(...)
method get属性名(...)
method getField属性名(...)
其次是Data Class(即与类型对应的java类)
method 属性名(...)
method is属性名(...)
method get属性名(...)
method getField属性名(...)
field 属性名
所以首先在ArticleResolver中查找author的映射,找不到的属性则一致向下找到属性的java类的get方法/属性本身。
另外,要给Query和Mutation至少创建一个Resolver
@Component
public class QueryResolver implements GraphQLQueryResolver {
private final UserRepository userRepository;
private final ArticleRepository articleRepository;
public QueryResolver(UserRepository userRepository, ArticleRepository articleRepository) {
this.userRepository = userRepository;
this.articleRepository = articleRepository;
}
public Article article(String title) {
return articleRepository.findArticleByTitle(title);
}
public User user(String nickname) {
return userRepository.findUserByNickname(nickname);
}
public List users() {
return userRepository.findAll();
}
}
@Component
public class MutationResolver implements GraphQLQueryResolver, GraphQLMutationResolver {
private final ArticleRepository articleRepository;
private final UserRepository userRepository;
private final BCryptPasswordEncoder encoder;
public MutationResolver(ArticleRepository articleRepository, UserRepository userRepository, BCryptPasswordEncoder encoder) {
this.articleRepository = articleRepository;
this.userRepository = userRepository;
this.encoder = encoder;
}
public User addUser(String mail, String nickname, String password) {
if(userRepository.findUserByNickname(nickname) != null){
return null;
}
return userRepository.save(User.builder()
.nickname(nickname)
.mail(mail)
.password(encoder.encode(password))
.build());
}
public Article addArticle(String title, String content, String authorId) {
if(!userRepository.findById(authorId).isPresent()){
return null;
}
return articleRepository.save(Article.builder()
.authorId(authorId)
.title(title)
.content(content)
.createBy(new Date())
.thumbUp(0)
.build());
}
}
这里使用mongodb存储数据。
运行,在http://localhost:8080/graphiql 中进行操作