

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

# Esecuzione di transazioni DynamoDB in AWS AppSync
<a name="tutorial-dynamodb-transact"></a>

**Nota**  
Ora supportiamo principalmente il runtime APPSYNC\$1JS e la relativa documentazione. [Prendi in considerazione l'utilizzo del runtime APPSYNC\$1JS e delle relative guide qui.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

AWS AppSync supporta l'utilizzo di operazioni di transazione Amazon DynamoDB su una o più tabelle in una singola regione. Le operazioni supportate sono `TransactGetItems` e `TransactWriteItems`. Utilizzando queste funzionalità in AWS AppSync, puoi eseguire attività come:
+ Passare un elenco di chiavi in una singola query e restituire i risultati da una tabella
+ Leggere i record da una o più tabelle in un'unica query
+ Scrivi i record della transazione su una o più tabelle in qualsiasi all-or-nothing modo
+ Eseguire transazioni quando alcune condizioni sono soddisfatte

## Permissions
<a name="permissions"></a>

Come altri resolver, è necessario creare un'origine dati in AWS AppSync e creare un ruolo o utilizzarne uno esistente. Poiché le operazioni di transazione richiedono autorizzazioni diverse sulle tabelle DynamoDB, è necessario concedere ai ruoli configurati le autorizzazioni per le azioni di lettura o scrittura:

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Action": [
                "dynamodb:DeleteItem",
                "dynamodb:GetItem",
                "dynamodb:PutItem",
                "dynamodb:Query",
                "dynamodb:Scan",
                "dynamodb:UpdateItem"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:dynamodb:us-east-1:111122223333:table/TABLENAME",
                "arn:aws:dynamodb:us-east-1:111122223333:table/TABLENAME/*"
            ]
        }
    ]
}
```

------

 **Nota**: i ruoli sono legati alle fonti di dati in AWS AppSync e i resolver sui campi vengono richiamati su un'origine dati. Le fonti di dati configurate per il recupero con DynamoDB hanno solo una tabella specificata, per semplificare la configurazione. Pertanto, quando si esegue un'operazione di transazione su più tabelle in un singolo resolver, che è una delle attività più avanzate, è necessario concedere il ruolo sull'accesso all'origine dati a tutte le tabelle con cui interagirà il resolver. Questo potrebbe essere fatto nel campo **Risorsa** nella policy di IAM indicata in precedenza. Viene effettuata la configurazione delle chiamate di transazione nelle tabelle nel modello di resolver, che verrà descritto di seguito.

## Origine dati
<a name="data-source"></a>

Per semplicità, useremo la stessa origine dati per tutti i resolver usati in questo tutorial. Nella scheda **Sorgenti dati**, crea una nuova origine dati DynamoDB e assegnale un nome. **TransactTutorial** Per la tabella è possibile specificare un qualsiasi nome, perché i nomi delle tabelle sono specificati come parte del modello di mappatura delle richieste per le operazioni di transazione. La tabella si chiamerà `empty`.

Avremo due tabelle denominate **SavingAccounts** e **CheckingAccounts**, entrambe con `accountNumber` come chiave di partizione e una tabella **transactionHistory** con `transactionId` come chiave di partizione.

Per questo tutorial, funzionerà qualsiasi ruolo con le seguenti policy inline: Sostituisci `region` e `accountId` con la tua regione e l'ID dell'account:

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Action": [
                "dynamodb:DeleteItem",
                "dynamodb:GetItem",
                "dynamodb:PutItem",
                "dynamodb:Query",
                "dynamodb:Scan",
                "dynamodb:UpdateItem"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:dynamodb:us-east-1:111122223333:table/savingAccounts",
                "arn:aws:dynamodb:us-east-1:111122223333:table/savingAccounts/*",
                "arn:aws:dynamodb:us-east-1:111122223333:table/checkingAccounts",
                "arn:aws:dynamodb:us-east-1:111122223333:table/checkingAccounts/*",
                "arn:aws:dynamodb:us-east-1:111122223333:table/transactionHistory",
                "arn:aws:dynamodb:us-east-1:111122223333:table/transactionHistory/*"
            ]
        }
    ]
}
```

------

## Transazioni
<a name="transactions"></a>

Per questo esempio, il contesto è una classica transazione bancaria, in cui useremo `TransactWriteItems` per:
+ Trasferire denaro dai conti di deposito ai conti correnti
+ Generare nuovi record di transazione per ogni transazione

Quindi, useremo `TransactGetItems` per recuperare i dettagli dai conti di deposito ai conti correnti.

**avvertimento**  
`TransactWriteItems`non è supportato se utilizzato per il rilevamento e la risoluzione dei conflitti. Queste impostazioni devono essere disabilitate per evitare possibili errori.

Definiamo il nostro schema GraphQL come segue:

```
type SavingAccount {
    accountNumber: String!
    username: String
    balance: Float
}

type CheckingAccount {
    accountNumber: String!
    username: String
    balance: Float
}

type TransactionHistory {
    transactionId: ID!
    from: String
    to: String
    amount: Float
}

type TransactionResult {
    savingAccounts: [SavingAccount]
    checkingAccounts: [CheckingAccount]
    transactionHistory: [TransactionHistory]
}

input SavingAccountInput {
    accountNumber: String!
    username: String
    balance: Float
}

input CheckingAccountInput {
    accountNumber: String!
    username: String
    balance: Float
}

input TransactionInput {
    savingAccountNumber: String!
    checkingAccountNumber: String!
    amount: Float!
}

type Query {
    getAccounts(savingAccountNumbers: [String], checkingAccountNumbers: [String]): TransactionResult
}

type Mutation {
    populateAccounts(savingAccounts: [SavingAccountInput], checkingAccounts: [CheckingAccountInput]): TransactionResult
    transferMoney(transactions: [TransactionInput]): TransactionResult
}

schema {
    query: Query
    mutation: Mutation
}
```

### TransactWriteItems - Compila gli account
<a name="transactwriteitems-populate-accounts"></a>

Al fine di trasferire denaro tra gli account, abbiamo bisogno di popolare la tabella con i dettagli. Per farlo, useremo l'operazione GraphQL `Mutation.populateAccounts`.

Nella sezione Schema, fai clic su **Allega** accanto all'`Mutation.populateAccounts`operazione. Vai a VTL Unit Resolvers, quindi scegli la stessa fonte di dati. `TransactTutorial`

Usa modello di mappatura della richiesta seguente:

 **Modello di mappatura della richiesta** 

```
#set($savingAccountTransactPutItems = [])
#set($index = 0)
#foreach($savingAccount in ${ctx.args.savingAccounts})
    #set($keyMap = {})
    $util.qr($keyMap.put("accountNumber", $util.dynamodb.toString($savingAccount.accountNumber)))
    #set($attributeValues = {})
    $util.qr($attributeValues.put("username", $util.dynamodb.toString($savingAccount.username)))
    $util.qr($attributeValues.put("balance", $util.dynamodb.toNumber($savingAccount.balance)))
    #set($index = $index + 1)
    #set($savingAccountTransactPutItem = {"table": "savingAccounts",
        "operation": "PutItem",
        "key": $keyMap,
        "attributeValues": $attributeValues})
    $util.qr($savingAccountTransactPutItems.add($savingAccountTransactPutItem))
#end

#set($checkingAccountTransactPutItems = [])
#set($index = 0)
#foreach($checkingAccount in ${ctx.args.checkingAccounts})
    #set($keyMap = {})
    $util.qr($keyMap.put("accountNumber", $util.dynamodb.toString($checkingAccount.accountNumber)))
    #set($attributeValues = {})
    $util.qr($attributeValues.put("username", $util.dynamodb.toString($checkingAccount.username)))
    $util.qr($attributeValues.put("balance", $util.dynamodb.toNumber($checkingAccount.balance)))
    #set($index = $index + 1)
    #set($checkingAccountTransactPutItem = {"table": "checkingAccounts",
        "operation": "PutItem",
        "key": $keyMap,
        "attributeValues": $attributeValues})
    $util.qr($checkingAccountTransactPutItems.add($checkingAccountTransactPutItem))
#end

#set($transactItems = [])
$util.qr($transactItems.addAll($savingAccountTransactPutItems))
$util.qr($transactItems.addAll($checkingAccountTransactPutItems))

{
    "version" : "2018-05-29",
    "operation" : "TransactWriteItems",
    "transactItems" : $util.toJson($transactItems)
}
```

E il seguente modello di mappatura della risposta:

 **Modello di mappatura della risposta** 

```
#if ($ctx.error)
    $util.appendError($ctx.error.message, $ctx.error.type, null, $ctx.result.cancellationReasons)
#end

#set($savingAccounts = [])
#foreach($index in [0..2])
    $util.qr($savingAccounts.add(${ctx.result.keys[$index]}))
#end

#set($checkingAccounts = [])
#foreach($index in [3..5])
    $util.qr($checkingAccounts.add(${ctx.result.keys[$index]}))
#end

#set($transactionResult = {})
$util.qr($transactionResult.put('savingAccounts', $savingAccounts))
$util.qr($transactionResult.put('checkingAccounts', $checkingAccounts))

$util.toJson($transactionResult)
```

Salva il resolver e vai alla sezione **Queries** della console per popolare gli account. AWS AppSync 

Eseguire la mutazione seguente:

```
mutation populateAccounts {
  populateAccounts (
    savingAccounts: [
      {accountNumber: "1", username: "Tom", balance: 100},
      {accountNumber: "2", username: "Amy", balance: 90},
      {accountNumber: "3", username: "Lily", balance: 80},
    ]
    checkingAccounts: [
      {accountNumber: "1", username: "Tom", balance: 70},
      {accountNumber: "2", username: "Amy", balance: 60},
      {accountNumber: "3", username: "Lily", balance: 50},
    ]) {
    savingAccounts {
      accountNumber
    }
    checkingAccounts {
      accountNumber
    }
  }
}
```

Abbiamo popolato 3 conti di deposito e 3 conti correnti in una mutazione.

****Utilizza la console DynamoDB per verificare che i dati vengano visualizzati nelle tabelle SavingAccounts e CheckingAccounts.****

### TransactWriteItems - Trasferimento di denaro
<a name="transactwriteitems-transfer-money"></a>

Allegare un resolver alla mutazione `transferMoney` con il seguente **Modello di mappatura della richiesta**. Tenere presente che i valori di `amounts`, `savingAccountNumbers` e `checkingAccountNumbers` sono gli stessi.

```
#set($amounts = [])
#foreach($transaction in ${ctx.args.transactions})
    #set($attributeValueMap = {})
    $util.qr($attributeValueMap.put(":amount", $util.dynamodb.toNumber($transaction.amount)))
    $util.qr($amounts.add($attributeValueMap))
#end

#set($savingAccountTransactUpdateItems = [])
#set($index = 0)
#foreach($transaction in ${ctx.args.transactions})
    #set($keyMap = {})
    $util.qr($keyMap.put("accountNumber", $util.dynamodb.toString($transaction.savingAccountNumber)))
    #set($update = {})
    $util.qr($update.put("expression", "SET balance = balance - :amount"))
    $util.qr($update.put("expressionValues", $amounts[$index]))
    #set($index = $index + 1)
    #set($savingAccountTransactUpdateItem = {"table": "savingAccounts",
        "operation": "UpdateItem",
        "key": $keyMap,
        "update": $update})
    $util.qr($savingAccountTransactUpdateItems.add($savingAccountTransactUpdateItem))
#end

#set($checkingAccountTransactUpdateItems = [])
#set($index = 0)
#foreach($transaction in ${ctx.args.transactions})
    #set($keyMap = {})
    $util.qr($keyMap.put("accountNumber", $util.dynamodb.toString($transaction.checkingAccountNumber)))
    #set($update = {})
    $util.qr($update.put("expression", "SET balance = balance + :amount"))
    $util.qr($update.put("expressionValues", $amounts[$index]))
    #set($index = $index + 1)
    #set($checkingAccountTransactUpdateItem = {"table": "checkingAccounts",
        "operation": "UpdateItem",
        "key": $keyMap,
        "update": $update})
    $util.qr($checkingAccountTransactUpdateItems.add($checkingAccountTransactUpdateItem))
#end

#set($transactionHistoryTransactPutItems = [])
#foreach($transaction in ${ctx.args.transactions})
    #set($keyMap = {})
    $util.qr($keyMap.put("transactionId", $util.dynamodb.toString(${utils.autoId()})))
    #set($attributeValues = {})
    $util.qr($attributeValues.put("from", $util.dynamodb.toString($transaction.savingAccountNumber)))
    $util.qr($attributeValues.put("to", $util.dynamodb.toString($transaction.checkingAccountNumber)))
    $util.qr($attributeValues.put("amount", $util.dynamodb.toNumber($transaction.amount)))
    #set($transactionHistoryTransactPutItem = {"table": "transactionHistory",
        "operation": "PutItem",
        "key": $keyMap,
        "attributeValues": $attributeValues})
    $util.qr($transactionHistoryTransactPutItems.add($transactionHistoryTransactPutItem))
#end

#set($transactItems = [])
$util.qr($transactItems.addAll($savingAccountTransactUpdateItems))
$util.qr($transactItems.addAll($checkingAccountTransactUpdateItems))
$util.qr($transactItems.addAll($transactionHistoryTransactPutItems))

{
    "version" : "2018-05-29",
    "operation" : "TransactWriteItems",
    "transactItems" : $util.toJson($transactItems)
}
```

Avremo 3 transazioni bancarie in una singola operazione `TransactWriteItems`. Utilizzare il seguente **modello di mappatura della risposta**:

```
#if ($ctx.error)
    $util.appendError($ctx.error.message, $ctx.error.type, null, $ctx.result.cancellationReasons)
#end

#set($savingAccounts = [])
#foreach($index in [0..2])
    $util.qr($savingAccounts.add(${ctx.result.keys[$index]}))
#end

#set($checkingAccounts = [])
#foreach($index in [3..5])
    $util.qr($checkingAccounts.add(${ctx.result.keys[$index]}))
#end

#set($transactionHistory = [])
#foreach($index in [6..8])
    $util.qr($transactionHistory.add(${ctx.result.keys[$index]}))
#end

#set($transactionResult = {})
$util.qr($transactionResult.put('savingAccounts', $savingAccounts))
$util.qr($transactionResult.put('checkingAccounts', $checkingAccounts))
$util.qr($transactionResult.put('transactionHistory', $transactionHistory))

$util.toJson($transactionResult)
```

Passare ora alla sezione **Query** della console AWS AppSync ed eseguire la mutazione **transferMoney** come segue:

```
mutation write {
  transferMoney(
    transactions: [
      {savingAccountNumber: "1", checkingAccountNumber: "1", amount: 7.5},
      {savingAccountNumber: "2", checkingAccountNumber: "2", amount: 6.0},
      {savingAccountNumber: "3", checkingAccountNumber: "3", amount: 3.3}
    ]) {
    savingAccounts {
      accountNumber
    }
    checkingAccounts {
      accountNumber
    }
    transactionHistory {
      transactionId
    }
  }
}
```

Abbiamo inviato 2 transazioni bancarie in una mutazione. ****Utilizza la console DynamoDB per verificare che i dati vengano visualizzati nelle tabelle **SavingAccounts**, CheckingAccounts e TransactionHistory.****

### TransactGetItems - Recupera account
<a name="transactgetitems-retrieve-accounts"></a>

Al fine di recuperare i dettagli dai conti di deposito ai conti correnti in una singola richiesta transazionale, allegheremo un resolver all'operazione GraphQL `Query.getAccounts` sul nostro schema. Seleziona **Allega**, vai a VTL Unit Resolvers, quindi nella schermata successiva, scegli la stessa fonte di `TransactTutorial` dati creata all'inizio del tutorial. Configurare i modelli come segue:

 **Modello di mappatura della richiesta** 

```
#set($savingAccountsTransactGets = [])
#foreach($savingAccountNumber in ${ctx.args.savingAccountNumbers})
    #set($savingAccountKey = {})
    $util.qr($savingAccountKey.put("accountNumber", $util.dynamodb.toString($savingAccountNumber)))
    #set($savingAccountTransactGet = {"table": "savingAccounts", "key": $savingAccountKey})
    $util.qr($savingAccountsTransactGets.add($savingAccountTransactGet))
#end

#set($checkingAccountsTransactGets = [])
#foreach($checkingAccountNumber in ${ctx.args.checkingAccountNumbers})
    #set($checkingAccountKey = {})
    $util.qr($checkingAccountKey.put("accountNumber", $util.dynamodb.toString($checkingAccountNumber)))
    #set($checkingAccountTransactGet = {"table": "checkingAccounts", "key": $checkingAccountKey})
    $util.qr($checkingAccountsTransactGets.add($checkingAccountTransactGet))
#end

#set($transactItems = [])
$util.qr($transactItems.addAll($savingAccountsTransactGets))
$util.qr($transactItems.addAll($checkingAccountsTransactGets))

{
    "version" : "2018-05-29",
    "operation" : "TransactGetItems",
    "transactItems" : $util.toJson($transactItems)
}
```

 **Modello di mappatura della risposta** 

```
#if ($ctx.error)
    $util.appendError($ctx.error.message, $ctx.error.type, null, $ctx.result.cancellationReasons)
#end

#set($savingAccounts = [])
#foreach($index in [0..2])
    $util.qr($savingAccounts.add(${ctx.result.items[$index]}))
#end

#set($checkingAccounts = [])
#foreach($index in [3..4])
    $util.qr($checkingAccounts.add($ctx.result.items[$index]))
#end

#set($transactionResult = {})
$util.qr($transactionResult.put('savingAccounts', $savingAccounts))
$util.qr($transactionResult.put('checkingAccounts', $checkingAccounts))

$util.toJson($transactionResult)
```

**Salva il resolver e vai alle sezioni Queries della console.** AWS AppSync Per recuperare i conti di deposito ai conti correnti, eseguire la seguente query:

```
query getAccounts {
  getAccounts(
    savingAccountNumbers: ["1", "2", "3"],
    checkingAccountNumbers: ["1", "2"]
  ) {
    savingAccounts {
      accountNumber
      username
      balance
    }
    checkingAccounts {
      accountNumber
      username
      balance
    }
  }
}
```

Abbiamo dimostrato con successo l'uso delle transazioni DynamoDB utilizzando. AWS AppSync