I have an AppSync api set-up, with a specific mutation set-up. Which works fine when I test that mutation in AppSync. However when I try to use the same query in a react app, I'm getting a null value. However when I look in the network tab in my browser, the correct data is being returned from AppSync.
I have the following mutation in my React app:
import gql from 'graphql-tag';
export default gql`
mutation CreateUser(
$email: String!,
$name: String
) {
createUser(input: {
email: $email
name: $name
}) {
__typename
id
}
}
`;
My React component (slightly redacted for brevity):
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);
When I inspect the query in the network tab, I see:
{"data":{"createUser":{"__typename":"User","id":"860b7cec-e882-4242-aca0-d4865154b640"}}}
However, in my React component, I see:
{ "data": { "createUser": "null" } }
I'm not sure if I'm missing something around how the component is set-up with Apollo which means the data isn't being loaded proprely. But the query itself seems to work fine.
The data is also correctly stored in DynamoDB as expected.
Here is my request mapping:
{
"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",
},
},
}
My response mapping:
$util.toJson($ctx.result)
And finally my schema:
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
}
The request works in AppSync: