AWS AppSync: передача аргументов от родительского преобразователя дочерним элементам

В AWS AppSync аргументы, отправляемые по основному запросу, не перенаправляются всем дочерним преобразователям.

type Query {
  article(id: String!, consistentRead: Boolean): Article
  book(id: String!, consistentRead: Boolean): Book
}

type Article {
  title: String!
  id: String!
}

type Book {
  articleIds: [String]!
  articles: [Article]!
  id: String!
}

когда я звоню:

query GetBook {
  book(id: 123, consistentRead: true) {
    articles {
      title
    }
  }
}

первый запрос на получение книги получает параметр consistentRead в $context.arguments, а последующий запрос на получение статьи - нет. ($context.arguments пусто)

Я также пробовал articles(consistentRead: Boolean): [Article]! внутри book, но безуспешно.

Кто-нибудь знает, можно ли в AppSync передавать аргументы всем запросам, входящим в один и тот же запрос?


person joshblour    schedule 26.09.2018    source источник
comment
Этот обходной путь с использованием заголовков запросов работает с конвейером или без него stackoverflow.com/a/58093410/1480391, это некрасиво, но это единственное решение Я знаю, что это позволяет передавать информацию ВСЕМ суб-преобразователям   -  person Yves M.    schedule 07.10.2019


Ответы (6)


Через ответ можно передавать аргументы от родителя к потомку. Позволь мне объяснить ...

AppSync имеет несколько контейнеров внутри $context:

  • аргументы
  • тайник
  • источник

arguments и stash всегда очищаются перед вызовом дочернего преобразователя, как видно из этих журналов Cloudwatch:

В самом конце родительского выполнения - присутствуют данные arguments и stash.

{
    "errors": [],
    "mappingTemplateType": "After Mapping",
    "path": "[getLatestDeviceState]",
    "resolverArn": "arn:aws:appsync:us-east-1:xxx:apis/yyy/types/Query/fields/getLatestDeviceState",
    "context": {
        "arguments": {
            "device": "ddddd"
        },
        "prev": {
            "result": {
                "items": [
                    {
                        "version": "849",
                        "device": "ddddd",
                        "timestamp": "2019-01-29T12:18:34.504+13:00"
                    }
                ]
            }
        },
        "stash": {"testKey": "testValue"},
        "outErrors": []
    },
    "fieldInError": false
}

а затем в самом начале дочернего преобразователя - arguments и stash всегда пустые.

{
"errors": [],
"mappingTemplateType": "Before Mapping",
"path": "[getLatestDeviceState, media]",
"resolverArn": "arn:aws:appsync:us-east-1:yyy:apis/xxx/types/DeviceStatePRODConnection/fields/media",
"context": {
    "arguments": {},
    "source": {
        "items": [
            {
                "version": "849",
                "device": "ddddd",
                "timestamp": "2019-01-29T12:18:34.504+13:00"
            }
        ]
    },
    "stash": {},
    "outErrors": []
},
"fieldInError": false
}

Обходной путь 1 - получить аргумент из предыдущего результата.

В приведенном выше примере device всегда присутствует в ответе родительского преобразователя, поэтому я вставил

#set($device = $util.defaultIfNullOrBlank($ctx.args.device, $ctx.source.items[0].device))

в шаблон сопоставления запросов дочернего преобразователя. Он попытается получить нужный идентификатор из аргументов, а затем вернется к предыдущему результату.

Обходной путь 2 - добавьте аргумент к родительскому ответу

Измените шаблон ответа родительского преобразователя, включив в него аргументы:

{
    "items": $utils.toJson($context.result.items),
    "device": "${ctx.args.device}"
}

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

person max    schedule 30.01.2019
comment
@joshblour - Какое решение вы нашли? Пожалуйста, отметьте это как правильный ответ, если вы согласны. Эта область все еще очень плохо документирована в AWS. Это может помочь другим сэкономить время. - person max; 30.01.2019
comment
Вдобавок к этому по умолчанию журналы cloudwatch не активируются в appsync. После того, как вы активировали его и для уровня журнала преобразователя полей было установлено значение ВСЕ, вы можете четко видеть содержимое объекта контекста, к которому документы не могут детально обратиться. Оттуда вы можете делать многое другое. - person Warren Wang; 15.07.2021

Обеспечить доступность для всех связанных преобразователей (вложенных или связанных с объектами коллекции) для меня было нормально Обходной путь 2 (tnx Max за такой хороший ответ), но только для дочерних преобразователей. В другом случае, когда мне нужно было разрешить сущности из запроса коллекции (содержит другие поля, кроме сущности), свойство, добавленное в шаблон сопоставления ответов, больше не было доступно. Итак, мое решение заключалось в том, чтобы настроить его на запрос заголовков:

##Set parent query profile parameter to headers to achieve availability accross related resolvers.
#set( $headers = $context.request.headers )
$util.qr($headers.put("profile", $util.defaultIfNullOrBlank($context.args.profile, "default")))

И прочтите это значение из ваших вложенных / других шаблонов сопоставления запросов:

#set($profile = $ctx.request.headers.profile)

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

person SunZe    schedule 25.09.2019
comment
Хорошая находка! Но это похоже на взлом. Я не уверен, что изменение заголовков запросов - это предназначенная функция AWS. Но благодаря этому обходному пути я могу передавать значения суб-преобразователям - person Yves M.; 07.10.2019
comment
См. github.com/aws/aws-appsync-community/issues. / - person Yves M.; 07.10.2019
comment
Рад, что это помогло. Я отчаянно пытался добиться этого, но пока не мог найти лучшего обходного пути, поэтому надеюсь, что AWS скоро реализует соответствующий способ решения этой проблемы. - person SunZe; 07.10.2019
comment
Прелесть этого ответа в том, что он будет работать не только для детей, но и для великих детей :) .. И это тоже без передачи аргументов с одного уровня на другой. Просто молодец! - person Ashootosh Bhardwaj; 20.12.2020

Добавьте это в шаблон сопоставления ответов BookQuery

#set( $book = $ctx.result )
#set($Articles = []);
#foreach($article in $book.articles)
    #set( $newArticle = $article )
    $util.qr($newArticle.put("bookID", $book.id))
    $util.qr($Articles.add($newArticle))
#end
$util.qr($book.put("articles", $Articles))
$util.toJson($book)

Теперь у каждой статьи будет bookID.

person Naveen Kumar    schedule 02.02.2020

Вы должны найти consistentRead в $context.info.variables ($context.info.variables.consistentRead): https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference.html#aws-appsync-resolver-context-reference-info

person webjay    schedule 01.12.2020

Вам не нужно передавать аргументы подзапросу. Основываясь на вашей схеме и сценарии использования, я думаю, вы можете настроить свою схему, как показано ниже, чтобы иметь связь между Author и Book

type Author {
    # parent's id
    bookID: ID!
    # author id
    id: ID!
    name: String!
}

type Book {
    id: ID!
    title: String!
    author: [Author]!
}

type Mutation {
    insertAuthor(bookID: ID!, id: ID!, name: String!): Author
    insertBook(id: ID!, title: String!): Book
}

type Query {
    getBook(id: ID!): Book
}

- Создать автора таблицы с Author.bookID в качестве первичного ключа и Author.id в качестве ключа сортировки
- Создать книгу таблицы с Book.id в качестве первичного ключа

Затем вам нужно подключить резолвер для Book.author

введите описание изображения здесь

А вот преобразователь для мутации insertAuthor

{
    "version" : "2017-02-28",
    "operation" : "PutItem",
    "key" : {
        "bookID" : $util.dynamodb.toDynamoDBJson($ctx.args.bookID),
        "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id)
    },
    "attributeValues" : {
        "name" : $util.dynamodb.toDynamoDBJson($ctx.args.name)
    }
}

И когда вы выполните запрос getBook, вы получите список авторов с тем же идентификатором книги, что и ниже.

введите описание изображения здесь

person KoingDev    schedule 26.09.2018

Просто в дочернем элементе используйте $ctx.source.id, где id - параметр, на который вам нужна ссылка от родителя.

person Phil    schedule 09.05.2019