如何通过 parameters/variables 来查询或变异?
How to pass parameters/variables to query or mutation?
我正在尝试读取通过后端变量传递的一些参数,让我们看看:
(此方法在 AuthenticationService
内,注入到我的 graphql 控制器中,见下文)
@GraphQLMutation(name = "getSessionToken")
public AuthReturn getSessionToken(@GraphQLArgument(name = "user") String u, @GraphQLArgument(name = "password") String p) {...}
这是我的 graphQL 请求:
mutation ($user: String!, $password: String!) {
getSessionToken(user: $user, password: $password) {
status
payload
}
}
和我的变量:
{ "user": "myuser", "password": "mypass"}
但是当我尝试运行这个示例代码时,显示了以下错误:
{"timestamp":"2019-07-29T17:18:32.753+0000","status":400,"error":"Bad Request","message":"JSON parse error: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token\n at [Source: (PushbackInputStream); line: 1, column: 162] (through reference chain: java.util.LinkedHashMap[\"variables\"])","path":"/graphql"}
[编辑]
这是我的控制器:
@RestController
public class GraphQLController {
private final GraphQL graphQL;
public GraphQLController(AgendamentoService agendamentos, ConfiguracaoService config, ProcessoService processos, ParametroService parametros, AuthenticationService autenticacao) {
GraphQLSchema schema = new GraphQLSchemaGenerator()
.withResolverBuilders(
//Resolve by annotations
new AnnotatedResolverBuilder())
.withOperationsFromSingletons(agendamentos, config, processos, parametros, autenticacao)
.withValueMapperFactory(new JacksonValueMapperFactory())
.generate();
graphQL = GraphQL.newGraphQL(schema).build();
}
@CrossOrigin
@PostMapping(value = "/graphql", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public Map<String, Object> graphql(@RequestBody Map<String, String> request, HttpServletRequest raw) {
// em context estamos passando o Request, usamos para fazer as verificacoes de autenticacao com GraphQl
ExecutionResult executionResult = graphQL.execute(ExecutionInput.newExecutionInput()
.query(request.get("query"))
.operationName(request.get("operationName"))
.context(raw)
.build());
return executionResult.toSpecification();
}
}
但是如果我 运行 这个突变没有根据要求将参数作为 variables
传递,则一切正常。我该怎么做才能将变量传递给我的 graphQl 请求?提前致谢。
您实际上并没有将变量传递给 graphql-java。这必须通过 ExecutionInput
完成。
我建议创建一个 class 例如:
@JsonIgnoreProperties(ignoreUnknown = true)
public class GraphQLRequest {
private final String query;
private final String operationName;
private final Map<String, Object> variables;
@JsonCreator
public GraphQLRequest(@JsonProperty("query") String query,
@JsonProperty("operationName") String operationName,
@JsonProperty("variables") Map<String, Object> variables) {
this.query = query;
this.operationName = operationName;
this.variables = variables != null ? variables : Collections.emptyMap();
}
public String getQuery() {
return query;
}
public String getOperationName() {
return operationName;
}
public Map<String, Object> getVariables() {
return variables;
}
}
并将其用作控制器方法中的参数:
@CrossOrigin
@PostMapping(value = "/graphql", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public Map<String, Object> graphql(@RequestBody GraphQLRequest graphQLRequest, HttpServletRequest httpRequest) {
// em context estamos passando o Request, usamos para fazer as verificacoes de autenticacao com GraphQl
ExecutionInput.Builder inputBuilder = ExecutionInput.newExecutionInput()
.query(graphQLRequest.getQuery())
.operationName(graphQLRequest.getOperationName())
.variables(graphQLRequest.getVariables()) //this is the line you were missing
.context(httpRequest);
return executionResult.toSpecification();
}
ExecutionInput
中缺少变量仍然无法解释您遇到的反序列化错误。它说在需要字符串的 JSON 中找到了一个对象。不确定这是从哪里编译的,但我怀疑网络部分比实际代码更重要。
无论哪种方式,在控制器代码中放置一个断点并查看请求是否正确反序列化以及 GraphQL 引擎是否被命中。
我还建议您简化设置:
public GraphQLController(AgendamentoService agendamentos, ConfiguracaoService config, ProcessoService processos, ParametroService parametros, AuthenticationService autenticacao) {
GraphQLSchema schema = new GraphQLSchemaGenerator()
.withResolverBuilders(
//Resolve by annotations
new AnnotatedResolverBuilder())
.withOperationsFromSingletons(agendamentos, config, processos, parametros, autenticacao)
.withValueMapperFactory(new JacksonValueMapperFactory())
.generate();
graphQL = GraphQL.newGraphQL(schema).build();
}
至
public GraphQLController(AgendamentoService agendamentos, ConfiguracaoService config, ProcessoService processos, ParametroService parametros, AuthenticationService autenticacao) {
GraphQLSchema schema = new GraphQLSchemaGenerator()
.withOperationsFromSingletons(agendamentos, config, processos, parametros, autenticacao)
.generate();
graphQL = GraphQL.newGraphQL(schema).build();
}
因为其他行都是多余的。他们只是在设置默认行为。
我正在尝试读取通过后端变量传递的一些参数,让我们看看:
(此方法在 AuthenticationService
内,注入到我的 graphql 控制器中,见下文)
@GraphQLMutation(name = "getSessionToken")
public AuthReturn getSessionToken(@GraphQLArgument(name = "user") String u, @GraphQLArgument(name = "password") String p) {...}
这是我的 graphQL 请求:
mutation ($user: String!, $password: String!) {
getSessionToken(user: $user, password: $password) {
status
payload
}
}
和我的变量:
{ "user": "myuser", "password": "mypass"}
但是当我尝试运行这个示例代码时,显示了以下错误:
{"timestamp":"2019-07-29T17:18:32.753+0000","status":400,"error":"Bad Request","message":"JSON parse error: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token\n at [Source: (PushbackInputStream); line: 1, column: 162] (through reference chain: java.util.LinkedHashMap[\"variables\"])","path":"/graphql"}
[编辑] 这是我的控制器:
@RestController
public class GraphQLController {
private final GraphQL graphQL;
public GraphQLController(AgendamentoService agendamentos, ConfiguracaoService config, ProcessoService processos, ParametroService parametros, AuthenticationService autenticacao) {
GraphQLSchema schema = new GraphQLSchemaGenerator()
.withResolverBuilders(
//Resolve by annotations
new AnnotatedResolverBuilder())
.withOperationsFromSingletons(agendamentos, config, processos, parametros, autenticacao)
.withValueMapperFactory(new JacksonValueMapperFactory())
.generate();
graphQL = GraphQL.newGraphQL(schema).build();
}
@CrossOrigin
@PostMapping(value = "/graphql", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public Map<String, Object> graphql(@RequestBody Map<String, String> request, HttpServletRequest raw) {
// em context estamos passando o Request, usamos para fazer as verificacoes de autenticacao com GraphQl
ExecutionResult executionResult = graphQL.execute(ExecutionInput.newExecutionInput()
.query(request.get("query"))
.operationName(request.get("operationName"))
.context(raw)
.build());
return executionResult.toSpecification();
}
}
但是如果我 运行 这个突变没有根据要求将参数作为 variables
传递,则一切正常。我该怎么做才能将变量传递给我的 graphQl 请求?提前致谢。
您实际上并没有将变量传递给 graphql-java。这必须通过 ExecutionInput
完成。
我建议创建一个 class 例如:
@JsonIgnoreProperties(ignoreUnknown = true)
public class GraphQLRequest {
private final String query;
private final String operationName;
private final Map<String, Object> variables;
@JsonCreator
public GraphQLRequest(@JsonProperty("query") String query,
@JsonProperty("operationName") String operationName,
@JsonProperty("variables") Map<String, Object> variables) {
this.query = query;
this.operationName = operationName;
this.variables = variables != null ? variables : Collections.emptyMap();
}
public String getQuery() {
return query;
}
public String getOperationName() {
return operationName;
}
public Map<String, Object> getVariables() {
return variables;
}
}
并将其用作控制器方法中的参数:
@CrossOrigin
@PostMapping(value = "/graphql", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public Map<String, Object> graphql(@RequestBody GraphQLRequest graphQLRequest, HttpServletRequest httpRequest) {
// em context estamos passando o Request, usamos para fazer as verificacoes de autenticacao com GraphQl
ExecutionInput.Builder inputBuilder = ExecutionInput.newExecutionInput()
.query(graphQLRequest.getQuery())
.operationName(graphQLRequest.getOperationName())
.variables(graphQLRequest.getVariables()) //this is the line you were missing
.context(httpRequest);
return executionResult.toSpecification();
}
ExecutionInput
中缺少变量仍然无法解释您遇到的反序列化错误。它说在需要字符串的 JSON 中找到了一个对象。不确定这是从哪里编译的,但我怀疑网络部分比实际代码更重要。
无论哪种方式,在控制器代码中放置一个断点并查看请求是否正确反序列化以及 GraphQL 引擎是否被命中。
我还建议您简化设置:
public GraphQLController(AgendamentoService agendamentos, ConfiguracaoService config, ProcessoService processos, ParametroService parametros, AuthenticationService autenticacao) {
GraphQLSchema schema = new GraphQLSchemaGenerator()
.withResolverBuilders(
//Resolve by annotations
new AnnotatedResolverBuilder())
.withOperationsFromSingletons(agendamentos, config, processos, parametros, autenticacao)
.withValueMapperFactory(new JacksonValueMapperFactory())
.generate();
graphQL = GraphQL.newGraphQL(schema).build();
}
至
public GraphQLController(AgendamentoService agendamentos, ConfiguracaoService config, ProcessoService processos, ParametroService parametros, AuthenticationService autenticacao) {
GraphQLSchema schema = new GraphQLSchemaGenerator()
.withOperationsFromSingletons(agendamentos, config, processos, parametros, autenticacao)
.generate();
graphQL = GraphQL.newGraphQL(schema).build();
}
因为其他行都是多余的。他们只是在设置默认行为。