Graphql apollo 客户端从 AppSync 返回空值
Posted
技术标签:
【中文标题】Graphql apollo 客户端从 AppSync 返回空值【英文标题】:Graphql apollo client returning null value from AppSync 【发布时间】:2019-01-04 00:54:22 【问题描述】:我有一个 AppSync api 设置,具有特定的突变设置。当我在 AppSync 中测试该突变时,效果很好。但是,当我尝试在反应应用程序中使用相同的查询时,我得到一个空值。但是,当我在浏览器中查看网络选项卡时,AppSync 正在返回正确的数据。
我的 React 应用中有以下突变:
import gql from 'graphql-tag';
export default gql`
mutation CreateUser(
$email: String!,
$name: String
)
createUser(input:
email: $email
name: $name
)
__typename
id
`;
我的 React 组件(为简洁起见略有删节):
import React, Component from 'react';
import MutationCreateUser from '../GraphQL/MutationCreateUser';
import graphql from "react-apollo";
class UserForm extends Component
state =
name: '',
email: '',
...
err: null
...
submit = async () =>
const createUser, history = this.props;
const user = this.state;
try
const result = await createUser(
name: user.name,
email: user.email
);
// This shows "data": "createUser": "null"
console.log('RES', result);
catch (e)
this.setState( err: e.message );
...
...
export default graphql(
MutationCreateUser,
props: ( mutate ) =>
return
createUser: (user) =>
return mutate(
variables: user
);
)(UserForm);
当我在网络选项卡中检查查询时,我看到:
"data":"createUser":"__typename":"User","id":"860b7cec-e882-4242-aca0-d4865154b640"
但是,在我的 React 组件中,我看到:
"data": "createUser": "null"
我不确定我是否遗漏了有关如何使用 Apollo 设置组件的内容,这意味着数据未正确加载。但查询本身似乎工作正常。
数据也按预期正确存储在 DynamoDB 中。
这是我的请求映射:
"version": "2017-02-28",
"operation": "PutItem",
"key":
"id": $util.dynamodb.toDynamoDBJson($util.autoId()),
,
"attributeValues": $util.dynamodb.toMapValuesJson($ctx.args.input),
"condition":
"expression": "attribute_not_exists(#id)",
"expressionNames":
"#id": "id",
,
,
我的响应映射:
$util.toJson($ctx.result)
最后是我的架构:
input CreateQuestionInput
text: String!
sectionId: ID!
input CreateScoreInput
score: Int!
questionId: ID!
userId: ID!
input CreateSectionInput
title: String
subSection: String
input CreateUserInput
email: String!
name: String
jobTitle: String
jobTitleShare: Boolean
department: String
level: Int
yearRange: Int
industry: String
orgSize: Int
input DeleteQuestionInput
id: ID!
input DeleteScoreInput
id: ID!
input DeleteSectionInput
id: ID!
input DeleteUserInput
id: ID!
type Mutation
createSection(input: CreateSectionInput!): Section
updateSection(input: UpdateSectionInput!): Section
deleteSection(input: DeleteSectionInput!): Section
createScore(input: CreateScoreInput!): Score
updateScore(input: UpdateScoreInput!): Score
deleteScore(input: DeleteScoreInput!): Score
createQuestion(input: CreateQuestionInput!): Question
updateQuestion(input: UpdateQuestionInput!): Question
deleteQuestion(input: DeleteQuestionInput!): Question
batchCreateQuestion(questions: [CreateQuestionInput]!): [Question]
createUser(input: CreateUserInput!): User
updateUser(input: UpdateUserInput!): User
deleteUser(input: DeleteUserInput!): User
type Query
getSection(id: ID!): Section
listSections(filter: TableSectionFilterInput, limit: Int, nextToken: String): SectionConnection
getScore(id: ID!): Score
listScores(filter: TableScoreFilterInput, limit: Int, nextToken: String): ScoreConnection
getQuestion(id: ID!): Question
listQuestions(filter: TableQuestionFilterInput, limit: Int, nextToken: String): QuestionConnection
getUser(id: ID!): User
listUsers(filter: TableUserFilterInput, limit: Int, nextToken: String): UserConnection
type Question
id: ID!
text: String!
sectionId: ID!
type QuestionConnection
items: [Question]
nextToken: String
type Schema
query: Query
type Score
id: ID!
score: Int!
questionId: ID!
userId: ID!
type ScoreConnection
items: [Score]
nextToken: String
type Section
id: ID!
title: String
subSection: String
questions: [Question]
type SectionConnection
items: [Section]
nextToken: String
type Subscription
onCreateSection(id: ID, title: String): Section
@aws_subscribe(mutations: ["createSection"])
onUpdateSection(id: ID, title: String): Section
@aws_subscribe(mutations: ["updateSection"])
onDeleteSection(id: ID, title: String): Section
@aws_subscribe(mutations: ["deleteSection"])
onCreateScore(
id: ID,
score: Int,
questionId: ID,
userId: ID
): Score
@aws_subscribe(mutations: ["createScore"])
onUpdateScore(
id: ID,
score: Int,
questionId: ID,
userId: ID
): Score
@aws_subscribe(mutations: ["updateScore"])
onDeleteScore(
id: ID,
score: Int,
questionId: ID,
userId: ID
): Score
@aws_subscribe(mutations: ["deleteScore"])
onCreateQuestion(id: ID, text: String, sectionId: ID): Question
@aws_subscribe(mutations: ["createQuestion"])
onUpdateQuestion(id: ID, text: String, sectionId: ID): Question
@aws_subscribe(mutations: ["updateQuestion"])
onDeleteQuestion(id: ID, text: String, sectionId: ID): Question
@aws_subscribe(mutations: ["deleteQuestion"])
onCreateUser(
id: ID,
email: String,
jobTitle: String,
jobTitleShare: Boolean,
department: String
): User
@aws_subscribe(mutations: ["createUser"])
onUpdateUser(
id: ID,
email: String,
jobTitle: String,
jobTitleShare: Boolean,
department: String
): User
@aws_subscribe(mutations: ["updateUser"])
onDeleteUser(
id: ID,
email: String,
jobTitle: String,
jobTitleShare: Boolean,
department: String
): User
@aws_subscribe(mutations: ["deleteUser"])
input TableBooleanFilterInput
ne: Boolean
eq: Boolean
input TableFloatFilterInput
ne: Float
eq: Float
le: Float
lt: Float
ge: Float
gt: Float
contains: Float
notContains: Float
between: [Float]
input TableIDFilterInput
ne: ID
eq: ID
le: ID
lt: ID
ge: ID
gt: ID
contains: ID
notContains: ID
between: [ID]
beginsWith: ID
input TableIntFilterInput
ne: Int
eq: Int
le: Int
lt: Int
ge: Int
gt: Int
contains: Int
notContains: Int
between: [Int]
input TableQuestionFilterInput
id: TableIDFilterInput
text: TableStringFilterInput
sectionId: TableIDFilterInput
input TableScoreFilterInput
id: TableIDFilterInput
score: TableIntFilterInput
questionId: TableIDFilterInput
userId: TableIDFilterInput
input TableSectionFilterInput
id: TableIDFilterInput
title: TableStringFilterInput
input TableStringFilterInput
ne: String
eq: String
le: String
lt: String
ge: String
gt: String
contains: String
notContains: String
between: [String]
beginsWith: String
input TableUserFilterInput
id: TableIDFilterInput
email: TableStringFilterInput
jobTitle: TableStringFilterInput
jobTitleShare: TableBooleanFilterInput
department: TableStringFilterInput
level: TableIntFilterInput
yearRange: TableIntFilterInput
industry: TableStringFilterInput
orgSize: TableIntFilterInput
input UpdateQuestionInput
id: ID!
text: String
sectionId: ID
input UpdateScoreInput
id: ID!
score: Int
questionId: ID
userId: ID
input UpdateSectionInput
id: ID!
title: String
input UpdateUserInput
id: ID!
email: String
jobTitle: String
jobTitleShare: Boolean
department: String
level: Int
yearRange: Int
industry: String
orgSize: Int
type User
id: ID!
email: String
jobTitle: String
jobTitleShare: Boolean
department: String
level: Int
yearRange: Int
industry: String
orgSize: Int
type UserConnection
items: [User]
nextToken: String
请求在 AppSync 中有效:
【问题讨论】:
【参考方案1】:由于数据已正确存储在 DynamoDB 中,看起来响应映射模板中可能存在类型不匹配。请使用 ALL
作为设置为您的 API 启用 Cloudwatch 日志记录。然后,您可以检查 CloudWatch 日志以获取评估的响应映射模板,然后将 ctx.result.data
与用户类型的形状进行比较。
如果仍然无法正常工作,请在此处发布您的架构和映射模板,以便我可以尝试复制它。谢谢。
【讨论】:
谢谢。由于完全相同的查询/映射模板在 AppSync 控制台中工作,我怀疑客户端正在发生其他事情。您能否为您的 API 启用 CloudWatch logsALL
设置,然后尝试从 ReactJS 客户端运行此查询。完成此操作后,从响应标头中获取 requestId,并查看 CloudWatch 日志。请从日志中发布生成的 ResponseMapping 模板,以便我们检查响应映射中上下文的形状。
你找到解释了吗?我正在一个 Angular 应用程序中试验同样的事情。以上是关于Graphql apollo 客户端从 AppSync 返回空值的主要内容,如果未能解决你的问题,请参考以下文章
angular 的 Apollo 客户端:从 graphql 文件生成代码
如何使用 apollo 客户端从 schema.graphql 中提取 typescript 接口:codegen
GraphQL/Apollo 客户端:如果查询是先前查询的子集,则从缓存中获取数据