AWS AppSync: Retornando valores nullables em resolvers aninhados
Tags: ptbr, aws, appsync, serverless
Published: 2020-04-05 05:08:55

Enquanto trabalhava em um projeto de um cliente, encontrei um problema interessante com o AppSync, que não consegui encontrar uma resposta depois de pesquisar bastante. Espero que este artigo possa te poupar a mesma dor, caso você encontre o mesmo problema.

O problema é que, quando você tem um campo aninhado anulável, e que você deseja expandir seu tipo, precisamos manipular os valores nulos no modelo VTL e ignorá-los. Não era óbvio como fazer isso em um sistema gerenciado como o AppSync.

Para ter uma idéia melhor do que estou falando, aqui está uma versão drasticamente simplificada do esquema GraphQL.

```graphql
type University {
  name: String!
  categories: [Category!]
}

type Category {
  name: String!
  sports: [CategorySport!]
}

type CategorySport {
  name: String!
  description: String
  coach: Coach # in the DynamoDB table, this is stored as a String
}

type Coach {
  id: ID!
  firstName: String!
  lastName: String!
}
```

![](https://res.cloudinary.com/practicaldev/image/fetch/s--XekLC1vt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://theburningmonk.com/wp-content/uploads/2020/04/img_5e87cea7436bb.png)

Na tabela DynamoDB, as universidades são armazenadas na tabela `University` e os usuários na tabela `User`. Categorias e esportes são modelados como propriedades de uma universidade para minimizar o número de leituras no DynamoDB. E o campo `CategorySport.coach` é o ID do perfil de um usuário na tabela `User`.

![](https://res.cloudinary.com/practicaldev/image/fetch/s--O5kRxqu3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://theburningmonk.com/wp-content/uploads/2020/04/img_5e87d1c215d56.png)

Para tornar mais fácil para a interface do usuário consumir os dados, expandimos o campo `CategorySport.coach` para ser um tipo `Coach` completo.

Então, configurei o resolver para esse campo aninhado e apontei para a tabela `User`.

**Nota:** Estou usando Serverless Framework com o excelente plugin [serverless-appsync](https://github.com/sid88in/serverless-appsync-plugin) para me ajudar a configurar tudo isso.

```yml
mappingTemplates:
  - type: CategorySport
    field: coach
    dataSource: userTable
      
dataSources:
  - type: AMAZON_DYNAMODB
    name: userTable
    config:
      tableName: !Ref UserTable
```

E eu configurei os modelos de VTL para a solicitação e resposta.

Solicitação:

```vtl
{
  "version" : "2017-02-28",
  "operation" : "GetItem",
  "key": {
    "id": $util.dynamodb.toDynamoDBJson($context.source.coach)
  }  
}
```

Resposta:

```vtl
$util.toJson($context.result)
```

E tudo funciona muito bem, exceto quando `CategorySport.coach` é `null`.

![](https://res.cloudinary.com/practicaldev/image/fetch/s--5sXVNKQS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://theburningmonk.com/wp-content/uploads/2020/04/img_5e87d4d02045d.png)

O que eu precisava era de uma maneira de fazer um curto-circuito na solicitação `DynamoDB.GetItem` quando `CategorySport.coach` for `null`. Depois de muita pesquisa, meu googling não deu em nada e eu me virei para o meu bom amigo [Heitor Lessa](https://twitter.com/heitor_lessa). Ele me indicou [este útil artigo](https://adrianhall.github.io/cloud/2019/01/03/early-return-from-graphql-resolvers/), que mencionava a palavra-chave `#return` que permite fazer um curto-circuito na execução do resolver e retornar mais cedo.

> O uso de #return no modelo de mapeamento de uma função retornará esses dados da função. Se você usá-lo em um modelo de mapeamento de solicitação, o modelo de mapeamento de resposta será ignorado. Da mesma forma, o uso de #return no modelo de mapeamento de um resolver retornará esses dados do resolver, encerrando prematuramente a execução do resolver.

Com isso, pude solucionar o problema adicionando apenas 3 linhas de código ao meu modelo de solicitação.

```vtl
#if ($util.isNullOrEmpty($context.source.coach))
  #return
#end

{
  "version" : "2017-02-28",
  "operation" : "GetItem",
  "key": {
    "id": $util.dynamodb.toDynamoDBJson($context.source.coach)
  }
}
```

Uma coisa a observar é que você não pode ter `#return(null)` mas `#return` seria `null` como resultado do resolver e pula a operação do `DynamoDB.GetItem` e o modelo de resposta por completo.

Gostou deste artigo? [Apoie-me no Patreon](https://www.patreon.com/bePatron?u=905909) e obtenha ajuda direta de mim por meio de um canal privado do Slack ou por 1-2-1.

# Créditos

- [AppSync: skipping nullable nested resolvers by returning early](https://dev.to/theburningmonk/appsync-skipping-nullable-nested-resolvers-by-returning-early-3lg9), escrito originalmente por [Yan Cui](https://dev.to/theburningmonk)