Клиент Graphql Apollo, возвращающий нулевое значение из AppSync

У меня есть настройка 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
  }
}
`;

Компонент My 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.info('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:

Клиент Graphql Apollo, возвращающий нулевое значение из AppSync

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
4
0
1 289
1

Ответы 1

Поскольку данные правильно хранятся в DynamoDB, похоже, что в шаблоне сопоставления ответов могло быть несоответствие типов. Пожалуйста, включите ведение журнала Cloudwatch для вашего API с ALL в качестве настройки. Затем вы можете проверить журналы CloudWatch на наличие оцененного шаблона сопоставления ответов, а затем сравнить ctx.result.data с формой типа «Пользователь».

Если это по-прежнему не работает, опубликуйте здесь свою схему и шаблоны сопоставления, чтобы я мог попытаться воспроизвести их со своей стороны. Спасибо.

Спасибо. Поскольку тот же самый шаблон запроса / сопоставления работает из консоли AppSync, я подозреваю, что на стороне клиента происходит что-то еще. Не могли бы вы включить настройки ALL журналов CloudWatch для вашего API, а затем попробуйте выполнить этот запрос из клиента ReactJS. Как только вы это сделаете, возьмите requestId из заголовков ответов и просмотрите журналы CloudWatch. Опубликуйте сгенерированный шаблон ResponseMapping из журналов, чтобы мы проверили, какова форма контекста в сопоставлении ответов.

Shankar Raju 30.07.2018 07:26

Вы нашли объяснение? Я экспериментирую с тем же в приложении Angular.

Tom 28.09.2018 15:00

Другие вопросы по теме