如何解决我可以安全地从GraphQLResolver回调GraphQLQueryResolver吗? 示例1:查询示例2:部分更新的变异解决方案
我的问题是:实现 resolution 方法时最好的是什么?是直接调用数据存储库还是调用主解析器又称一个实现GraphQLQueryResolver
的方法(只要它具有适当的方法)?换句话说(请参见下面的示例),在回调主解析器 时,DataFetchingEnvironment
是否已正确调整/设置?
注意:如果您不熟悉Resolvers
与GraphQL Java Tools的工作方式,那么让我看看@ https://www.graphql-java-kickstart.com/tools/schema-definition/
现在是示例。
在带有GraphQL Java工具(具有graphql-spring-boot-starter
依赖项)的Spring Boot应用程序中,让我们拥有以下架构:
type User {
id: ID
name: String
company: Company
}
type Company {
id: ID
name: String
}
具有匹配的POJO或实体(省略了getter / setter):
class User {
private Long id;
private String name;
private Long idCompany;
}
class Company {
private Long id;
private String name;
}
和这些 resolvers (注意:UserRepository和CompanyRepository是您常用的DAO / Repository类,由Spring Data(JPA)支持,其他某种东西或您自己的自定义实现,无论...):
QueryResolver implements GraphQLQueryResolver {
@Autowired
private UserRepository userRepository;
@Autowired
private CompanyRepository companyRepository;
public User user(String id) {
return userRepository.findById(id);
}
public Company company(String idCompany) {
return companyRepository.findById(idCompany);
}
}
UserResolver implements GraphQLResolver<User> {
@Autowired
private CompanyRepository companyRepository;
public Company company(User user) {
return companyRepository.findById(user.getIdCompany());
}
// ...or should I do:
@Autowired
private QueryResolver queryResolver;
public Company company(User user) {
return queryResolver.company(user.getIdCompany());
}
}
在每种方法的末尾添加DataFetchingEnvironment environment
并在执行对各种(数据)存储库的调用之前使用DataFetchingEnvironment
时,这(更)有意义。
继续上面的示例,这样做是否正确(即UserResolver implements GraphQLResolver<User> {
@Autowired
private QueryResolver queryResolver;
public Company company(User user,DataFetchingEnvironment environment) {
return queryResolver.company(user.getIdCompany(),environment);
}
}
在再次传输到主QueryResolver时是否正确填充)?
credential = ManagedIdentityCredential()
service_client = DataLakeServiceClient(account_url="{}://{}.dfs.core.windows.net".format("https",storage_account_name),credential=credential)
解决方法
简短回答
您可以将解析程序调用委派给服务层,但不要在解析程序/服务之间传递DataFecthingEnvironment。无法正确填充。
长答案
这是不安全的,并且可能导致难以确定的错误和数据丢失。
从正在执行的graphql查询/突变中填充了DataFetchingEnvironment,并且您希望您的resolver方法中的DataFetchingEnvironment与所调用的resolver方法一致。
考虑以下架构:
type Movie {
id: ID!
title: String!
rating: String
actors: [Actor]
}
type Actor {
id: ID!
name: String!
role: String
}
input ActorUpdateInput {
id: ID!
name: String
role: String
}
type Query {
#Search movies with a specified Rating
searchMovie(name: movieTitle,rating: String): Book
#Search R-rated movies
searchRRatedMovie(name: movieTitle): Book
}
type Mutation {
#Update a movie and its actors
updateMovie(id:Id!,title: String,actors: [ActorUpdateInput]): Movie
#Update an actor
updateActor(input: ActorUpdateInput!): Actor
}
示例1:查询
query {
searchRRatedMovie(name: "NotRRatedMovie") {
title
}
}
电影“ NotRRatedMovie”未获得R级评级,我们可以期望此查询返回空数据。
现在,下面的实现将DataFetchingEnvironment从searchRRatedMovie传递到searchMovie查询解析器实现。
public class QueryResolver {
@Autowired
MovieRepository repository;
public Movie searchRRatedMovie(String title,DataFetchingEnvironment environment) {
return this.searchMovie(name,"R",environment);
}
public Movie searchMovie(String title,String rating,DataFetchingEnvironment environment) {
if(!environment.containsArgument("rating")) {
//if the rating argument was omitted from the query
return repository.findByTitle(title);
} else if(rating == null) {
//rating is an argument but was set to null (ie. the user wants to retrieve all the movies without any rating)
return repository.findByTitleAndRating(title,null);
} else {
repository.findByNameAndTitle(name,rating);
}
}
}
这看起来不错,但查询不会返回null。
第一个解析器将呼叫searchRRatedMovie("NotRRatedMovie",environment)
。该环境不包含"rating"
参数。到达该行时:if(!environment.containsArgument("rating")) {
"rating"
参数不存在,它将进入if语句,返回repository.findByTitle("NotRRatedMovie")
而不是预期的repository.findByTitleAndRating("NotRRatedMovie","R")
。
示例2:部分更新的变异
我们可以使用DataFetchingEnvironment参数在突变中实现部分更新:如果参数为null
,则需要DataFetchingEnvironment参数来告诉我们参数是否为null
,因为它被设置为{{ 1}}(即,该突变应将基础值更新为null
),或者因为根本没有设置它(即,该突变不应将基础值更新)。
null
在这里,updateActor解析器期望输入参数(它将与updateActor突变定义匹配)。因为我们通过了一个错误填充的环境,所以实现失败了。
解决方案
没有DataFetchinEnvironment的部分更新
如果要实现部分更新,则可以不使用DataFecthingEnvironment来实现,就像我在此注释中所做的:https://github.com/graphql-java-kickstart/graphql-java-tools/issues/141#issuecomment-560938020
在将DataFetchingEnvironment传递给下一个解析器之前,先对其进行重建
如果您确实需要DataFetchingEnvironment,则仍可以构建一个新的传递给下一个解析器。这可能会更加困难且容易出错,但是您可以看看如何在ExecutionStrategy.java https://github.com/graphql-java/graphql-java/blob/master/src/main/java/graphql/execution/ExecutionStrategy.java#L246
中创建原始DataFetchingEnvironment。版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。