As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.
Referência do modelo de mapeamento do resolvedor do Lambda para o AWS AppSync
nota
Agora, oferecemos suporte principalmente ao runtime do APPSYNC_JS e sua documentação. Considere usar o runtime do APPSYNC_JS e seus guias disponíveis aqui.
Você pode usar funções e resolvedores do AWS AppSync para invocar funções do Lambda localizadas em sua conta. Você pode moldar suas cargas úteis de solicitação e a resposta de suas funções do Lambda antes de devolvê-las aos seus clientes. Os modelos de mapeamento também permitem que você ofereça dicas ao AWS AppSync sobre a natureza da operação a ser invocada. Esta seção descreve os diferentes modelos de mapeamento para as operações do Lambda compatíveis.
Modelo de mapeamento de solicitações
O modelo de mapeamento de solicitações do Lambda manipula campos relacionados à sua função do Lambda:
{ "version": string, "operation": Invoke|BatchInvoke, "payload": any type, "invocationType": RequestResponse|Event }
Esta é a representação do esquema JSON do modelo de mapeamento de solicitações do Lambda quando resolvido:
{ "definitions": {}, "$schema": "https://json-schema.org/draft-06/schema#", "$id": "https://aws.amazon.com/appsync/request-mapping-template.json", "type": "object", "properties": { "version": { "$id": "/properties/version", "type": "string", "enum": [ "2018-05-29" ], "title": "The Mapping template version.", "default": "2018-05-29" }, "operation": { "$id": "/properties/operation", "type": "string", "enum": [ "Invoke", "BatchInvoke" ], "title": "The Mapping template operation.", "description": "What operation to execute.", "default": "Invoke" }, "payload": {}, "invocationType": { "$id": "/properties/invocationType", "type": "string", "enum": [ "RequestResponse", "Event" ], "title": "The Mapping template invocation type.", "description": "What invocation type to execute.", "default": "RequestResponse" } }, "required": [ "version", "operation" ], "additionalProperties": false }
Aqui está um exemplo que usa uma operação invoke
com seus dados de carga útil sendo o campo getPost
de um esquema GraphQL junto com seus argumentos do contexto:
{ "version": "2018-05-29", "operation": "Invoke", "payload": { "field": "getPost", "arguments": $util.toJson($context.arguments) } }
Todo o documento de mapeamento é passado como entrada para sua função do Lambda; assim, o exemplo anterior agora tem esta aparência:
{ "version": "2018-05-29", "operation": "Invoke", "payload": { "field": "getPost", "arguments": { "id": "postId1" } } }
Version (Versão)
Comum a todos os modelos de mapeamento de solicitação, version
define a versão usada pelo modelo. O version
é obrigatório e é um valor estático:
"version": "2018-05-29"
Operation
A fonte de dados do Lambda permite que você defina duas operações no campo operation
: Invoke
e BatchInvoke
. A Invoke
permite que o AWS AppSync saiba chamar sua função do Lambda para cada resolvedor do campo GraphQL, enquanto BatchInvoke
instrui o AWS AppSync para solicitações em lote do campo GraphQL atual. O campo operation
é obrigatório.
Para Invoke
, o modelo de mapeamento da solicitação resolvido corresponde à carga útil de entrada da função do Lambda. Vamos modificar o exemplo acima:
{ "version": "2018-05-29", "operation": "Invoke", "payload": { "arguments": $util.toJson($context.arguments) } }
Isso é resolvido e passado para a função do Lambda, que poderá ser mais ou menos assim:
{ "version": "2018-05-29", "operation": "Invoke", "payload": { "arguments": { "id": "postId1" } } }
Para BatchInvoke
, o modelo de mapeamento é aplicado a cada resolvedor do campo no lote. Para concisão, o AWS AppSync mescla todos os valores de payload
do modelo de mapeamento resolvido em uma lista dentro de um único objeto correspondente ao modelo de mapeamento. O exemplo de modelo a seguir mostra a mesclagem:
{ "version": "2018-05-29", "operation": "BatchInvoke", "payload": $util.toJson($context) }
Esse modelo é resolvido para o seguinte documento de mapeamento:
{ "version": "2018-05-29", "operation": "BatchInvoke", "payload": [ {...}, // context for batch item 1 {...}, // context for batch item 2 {...} // context for batch item 3 ] }
Cada elemento da lista payload
corresponde a um único item de lote. Também se espera que a função do Lambda retorne uma resposta em forma de lista correspondente à ordem dos itens enviados na solicitação:
[ { "data": {...}, "errorMessage": null, "errorType": null }, // result for batch item 1 { "data": {...}, "errorMessage": null, "errorType": null }, // result for batch item 2 { "data": {...}, "errorMessage": null, "errorType": null } // result for batch item 3 ]
Carga útil
O campo payload
é um contêiner usado para passar qualquer JSON bem formado para a função do Lambda. Se o campo operation
estiver definido como BatchInvoke
, o AWS AppSync envolverá os valores de payload
existentes em uma lista. O campo payload
é opcional.
Tipo de invocação
A fonte de dados do Lambda permite que você defina dois tipos de invocação: RequestResponse
e Event
. Os tipos de invocação são sinônimos dos tipos de invocação definidos na API do Lambda. O tipo de invocação RequestResponse
permite que o AWS AppSync chame sua função do Lambda de forma síncrona para aguardar uma resposta. A invocação Event
permite que você invoque sua função do Lambda de forma assíncrona. Para obter mais informações sobre como o Lambda lida com solicitações de tipo de invocação Event
, consulte Invocação assíncrona. O campo invocationType
é opcional. Se esse campo não for incluído na solicitação, o AWS AppSync usará como padrão o tipo de invocação RequestResponse
.
Para qualquer campo invocationType
, a solicitação resolvida corresponde à carga útil de entrada da função do Lambda. Vamos modificar o exemplo acima:
{ "version": "2018-05-29", "operation": "Invoke", "invocationType": "Event" "payload": { "arguments": $util.toJson($context.arguments) } }
Isso é resolvido e passado para a função do Lambda, que poderá ser mais ou menos assim:
{ "version": "2018-05-29", "operation": "Invoke", "invocationType": "Event", "payload": { "arguments": { "id": "postId1" } } }
Quando a operação BatchInvoke
é usada em conjunto com o campo do tipo de invocação Event
, o AWS AppSync mescla o resolvedor de campo da mesma forma mencionada acima, e a solicitação é passada para sua função do Lambda como um evento assíncrono, sendo payload
uma lista de valores. Recomendamos que você desative o cache do resolvedor para resolvedores do tipo de invocação Event
, pois eles não seriam enviados ao Lambda se houvesse um acerto do cache.
Modelo de mapeamento de respostas
Assim como ocorre com outras fontes de dados, sua função do Lambda envia uma resposta ao AWS AppSync que precisa ser convertida em um tipo do GraphQL.
O resultado da função do Lambda será definido no objeto context
que está disponível por meio da propriedade $context.result
do Velocity Template Language (VTL).
Se a forma da resposta da função do Lambda corresponder exatamente à forma do tipo do GraphQL, você pode encaminhar a resposta usando o seguinte modelo de mapeamento da resposta:
$util.toJson($context.result)
Não existem campos obrigatórios ou restrições de forma que se aplicam ao modelo de mapeamento da resposta. No entanto, como o GraphQL tem vários tipos, o modelo de mapeamento resolvido deve corresponder ao tipo do GraphQL esperado.
Resposta em lote da função do Lambda
Se o campo operation
estiver definido como BatchInvoke
, o AWS AppSync espera de volta uma lista de itens da função do Lambda. Para que o AWS AppSync mapeie cada resultado de volta ao item da solicitação original, a lista da resposta deve corresponder em tamanho e ordem. É válido ter itens null
na lista de respostas; $ctx.result
será adequadamente definido como nulo.
Resolvedores diretos do Lambda
Se você quiser contornar totalmente o uso de modelos de mapeamento, o AWS AppSync poderá fornecer uma carga útil padrão para sua função do Lambda e uma resposta padrão da função do Lambda para um tipo GraphQL. Você pode optar por fornecer um modelo de solicitação, um modelo de resposta ou nenhum dos dois, e o AWS AppSync vai lidar com isso adequadamente.
Modelo de mapeamento da solicitação direta do Lambda
Quando o modelo de mapeamento da solicitação não for fornecido, o AWS AppSync enviará o objeto Context
diretamente para sua função do Lambda como uma operação Invoke
. Para obter mais informações sobre a estrutura do código-fonte do objeto Context
, consulte Referência de contexto do modelo de mapeamento do resolvedor do AWS AppSync.
Modelo de mapeamento da resposta direta do Lambda
Quando o modelo de mapeamento de resposta não é fornecido, o AWS AppSync executa uma das duas ações ao receber a resposta da sua função do Lambda. Se você não forneceu um modelo de mapeamento de solicitação ou forneceu um modelo de mapeamento de solicitação com a versão 2018-05-29
, a resposta será equivalente ao seguinte modelo de mapeamento de resposta:
#if($ctx.error) $util.error($ctx.error.message, $ctx.error.type, $ctx.result) #end $util.toJson($ctx.result)
Se você forneceu um modelo com a versão 2017-02-28
, a lógica de resposta funcionará de forma equivalente ao seguinte modelo de mapeamento de resposta:
$util.toJson($ctx.result)
Superficialmente, o desvio do modelo de mapeamento opera de forma semelhante ao uso de determinados modelos de mapeamento, conforme mostrado nos exemplos anteriores. No entanto, nos bastidores, a avaliação dos modelos de mapeamento é totalmente contornada. Como a etapa de avaliação do modelo é ignorada, em alguns cenários, as aplicações podem ter menos sobrecarga e latência durante a resposta em relação a uma função do Lambda com um modelo de mapeamento de resposta que precisa ser avaliado.
Tratamento personalizado de erros nas respostas do resolvedor direto do Lambda
Você pode personalizar as respostas de erro das funções do Lambda que os resolvedores diretos do Lambda invocam gerando uma exceção personalizada. O exemplo a seguir demonstra como criar uma exceção personalizada usando JavaScript:
class CustomException extends Error { constructor(message) { super(message); this.name = "CustomException"; } } throw new CustomException("Custom message");
Quando exceções são geradas, errorType
e errorMessage
é name
emessage
, respectivamente, do erro personalizado que é gerado.
Se errorType
for UnauthorizedException
, o AWS AppSync retornará a mensagem padrão ("You are not authorized to make this
call."
) em vez de uma mensagem personalizada.
Este é um exemplo de resposta do GraphQL que demonstra um errorType
personalizado:
{ "data": { "query": null }, "errors": [ { "path": [ "query" ], "data": null, "errorType": "CustomException", "errorInfo": null, "locations": [ { "line": 5, "column": 10, "sourceName": null } ], "message": "Custom Message" } ] }
Resolvedores diretos do Lambda: agrupamento em lotes ativado
Você pode habilitar o agrupamento em lotes para seu resolvedor direto do Lambda configurando maxBatchSize
no seu resolvedor. Quando maxBatchSize
é definido como um valor maior que 0
para um resolvedor direto do Lambda, o AWS AppSync envia solicitações em lotes para sua função do Lambda com até maxBatchSize
.
Definir maxBatchSize
como 0
em um resolvedor direto do Lambda desativa o agrupamento em lotes.
Para obter mais informações sobre como funciona o agrupamento em lotes com os resolvedores do Lambda, consulte Caso de uso avançado: agrupamento em lotes.
Modelo de mapeamento de solicitações
Quando agrupamento em lote está habilitado e o modelo de mapeamento de solicitação não é fornecido, o AWS AppSync envia uma lista de objetos Context
como uma operação BatchInvoke
diretamente para sua função do Lambda.
Modelo de mapeamento de respostas
Quando o agrupamento em lote está ativado e o modelo de mapeamento de resposta não é fornecido, a lógica de resposta é equivalente ao seguinte modelo de mapeamento de resposta:
#if( $context.result && $context.result.errorMessage ) $utils.error($context.result.errorMessage, $context.result.errorType, $context.result.data) #else $utils.toJson($context.result.data) #end
A função do Lambda deve retornar uma lista de resultados na mesma ordem da lista de objetos Context
que foram enviados. É possível retornar erros individuais fornecendo errorMessage
e errorType
para um resultado específico. Cada resultado na lista deve estar no seguinte formato:
{ "data" : { ... }, // your data "errorMessage" : { ... }, // optional, if included an error entry is added to the "errors" object in the AppSync response "errorType" : { ... } // optional, the error type }
nota
Outros campos no objeto de resultado são ignorados.
Manuseio de erros do Lambda
Você pode retornar um erro para todos os resultados lançando uma exceção ou um erro na sua função do Lambda. Se a solicitação de payload ou o tamanho da resposta para sua solicitação em lote for muito grande, o Lambda retornará um erro. Nesse caso, você deve considerar reduzir maxBatchSize
ou o tamanho do payload da resposta.
Para obter informações sobre como lidar com erros individuais, consulte Retornar erros individuais.
Amostra de função do Lambda
Usando o esquema abaixo, você pode criar um resolvedor direto do Lambda para o resolvedor de campo Post.relatedPosts
e habilitar o agrupamento em lote definindo maxBatchSize
acima de 0
:
schema { query: Query mutation: Mutation } type Query { getPost(id:ID!): Post allPosts: [Post] } type Mutation { addPost(id: ID!, author: String!, title: String, content: String, url: String): Post! } type Post { id: ID! author: String! title: String content: String url: String ups: Int downs: Int relatedPosts: [Post] }
Na consulta a seguir, a função do Lambda será chamada com lotes de solicitações para resolver relatedPosts
:
query getAllPosts { allPosts { id relatedPosts { id } } }
Confira abaixo uma implementação simples de uma função do Lambda:
const posts = { 1: { id: '1', title: 'First book', author: 'Author1', url: 'https://amazon.com/', content: 'SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1', ups: '100', downs: '10', }, 2: { id: '2', title: 'Second book', author: 'Author2', url: 'https://amazon.com', content: 'SAMPLE TEXT AUTHOR 2 SAMPLE TEXT AUTHOR 2 SAMPLE TEXT', ups: '100', downs: '10', }, 3: { id: '3', title: 'Third book', author: 'Author3', url: null, content: null, ups: null, downs: null }, 4: { id: '4', title: 'Fourth book', author: 'Author4', url: 'https://www.amazon.com/', content: 'SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4', ups: '1000', downs: '0', }, 5: { id: '5', title: 'Fifth book', author: 'Author5', url: 'https://www.amazon.com/', content: 'SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT', ups: '50', downs: '0', }, } const relatedPosts = { 1: [posts['4']], 2: [posts['3'], posts['5']], 3: [posts['2'], posts['1']], 4: [posts['2'], posts['1']], 5: [], } exports.handler = async (event) => { console.log('event ->', event) // retrieve the ID of each post const ids = event.map((context) => context.source.id) // fetch the related posts for each post id const related = ids.map((id) => relatedPosts[id]) // return the related posts; or an error if none were found return related.map((r) => { if (r.length > 0) { return { data: r } } else { return { data: null, errorMessage: 'Not found', errorType: 'ERROR' } } }) }