Dans ce module, vous mettez en service une base de données Amazon DynamoDB et apprenez comment utiliser DynamoDB pour stocker des informations sur votre jeu au tour par tour.

Durée du module : 30 minutes


Amazon DynamoDB est un service entièrement géré de bases de données NoSQL fourni par AWS. Il fournit des temps de réponse de quelques millisecondes et une scalabilité quasi infinie. DynamoDB est utilisé par une grande variété d’applications et de secteurs, des paniers d’achat Amazon.com au service de géolocalisation de Lyft, en passant par un vaste choix de jeux en ligne.

Toutes les interactions avec DynamoDB s’effectuent via le protocole HTTPS et utilisent AWS Identity and Access Management (IAM) comme outil d’authentification et d’autorisation. En général, vous utilisez le kit AWS SDK pour votre choix de langue pour interagir avec DynamoDB. Si vous utilisez des options de calcul AWS pour votre application, par exemple Amazon Elastic Compute Cloud (Amazon EC2) ou AWS Lambda, alors votre application peut utiliser les informations d’identification AWS contenues dans votre environnement de calcul pour envoyer des requêtes vers DynamoDB.

Dans les prochaines étapes, vous allez d’abord mettre en service une base de données DynamoDB. Ensuite, vous apprendrez comment interagir avec votre base de données DynamoDB en utilisant le kit AWS SDK pour JavaScript dans Node.js.


  • Étape 1 : mettre en service une base de données Amazon DynamoDB

    Pour commencer, mettons en service une base de données DynamoDB. Une base de données DynamoDB est encore appelée une table.

    Lors de la création d’une base de données DynamoDB, vous devez spécifier l’attribut ou les attributs qui constitueront la clé principale de votre table. Chaque enregistrement que vous écrivez dans votre table DynamoDB est appelé élément, et chaque élément doit inclure la clé principale de votre table.

    La modélisation des données DynamoDB et la conception de votre clé principale sont des aspects très importants. Cependant, votre jeu dispose d’un modèle d’accès simple qui ne nécessite pas un processus de modélisation des données de pointe. Par conséquent, ce didacticiel n’abordera pas les sujets complexes liés à la modélisation des données DynamoDB. Pour en savoir plus sur la modélisation des données dans DynamoDB, vous pouvez lire les didacticiels consacrés à la Conception d’une base de données pour une application mobile avec Amazon DynamoDB ou à la Modélisation des données d’une application de jeu avec Amazon DynamoDB.

    Dans votre application, vous utilisez DynamoDB comme un simple magasin clé-valeur. Chaque jeu possède un attribut gameId permettant de l’identifier de manière unique. L’attribut gameId est utilisé en tant que clé principale pour votre table.

    Le répertoire scripts/ contient un fichier dénommé create-table.sh, qui crée votre table DynamoDB table à l’aide de l’interface de ligne de commande AWS (AWS CLI). Le contenu du fichier est le suivant :
     

    aws dynamodb create-table \
      --table-name turn-based-game \
      --attribute-definitions '[
        {
          "AttributeName": "gameId",
          "AttributeType": "S"
        }
      ]' \
      --key-schema '[
        {
          "AttributeName": "gameId",
          "KeyType": "HASH"
        }
      ]' \
      --provisioned-throughput '{
        "ReadCapacityUnits": 5,
        "WriteCapacityUnits": 5
      }'

    Pour commencer, il fournit à la table un nom de jeu au tour par tour. Ensuite, il déclare les attributs qui sont utilisés dans la clé principale de la table. Étant donné que dans le présent exemple vous utilisez une clé principale simple, vous ne déclarez qu’un seul attribut, gameId, qui est de type chaîne de données. Puis, vous spécifiez le schéma de votre clé principale en indiquant que l’attribut gameId sera utilisé comme clé de hachage de votre table.

    Pour finir, vous spécifiez le nombre d’unités de capacité en lecture et en écriture que vous souhaitez affecter à votre table. DynamoDB comporte un mode de tarification à la demande, qui vous permet de payer pour chaque requête en lecture et en écriture envoyée à votre table. Toutefois, le mode de débit alloué convenant à l’offre gratuite AWS, vous pouvez l’utiliser ici.

    Créez votre table en exécutant la commande suivante dans votre terminal :

    bash scripts/create-table.sh

    Vous obtiendrez la sortie suivante dans votre terminal :

    {
        "TableDescription": {
            "AttributeDefinitions": [
                {
                    "AttributeName": "gameId",
                    "AttributeType": "S"
                }
            ],
            "TableName": "turn-based-game",
            "KeySchema": [
                {
                    "AttributeName": "gameId",
                    "KeyType": "HASH"
                }
            ],
            "TableStatus": "CREATING",
            "CreationDateTime": 1574086642.07,
            "ProvisionedThroughput": {
                "NumberOfDecreasesToday": 0,
                "ReadCapacityUnits": 5,
                "WriteCapacityUnits": 5
            },
            "TableSizeBytes": 0,
            "ItemCount": 0,
            "TableArn": "arn:aws:dynamodb:us-east-1:955617200811:table/turn-based-game",
            "TableId": "c62cb86a-211e-4a50-a160-4a616c8f3445"
        }
    }
  • Étape 2 : enregistrer un élément d’un exemple de jeu dans votre table

    À présent que vous avez créé votre table, vous pouvez y ajouter des éléments. Chaque jeu est représenté par un élément simple dans votre table.

    Le schéma de chaque élément de jeu est le suivant :

    Chaque jeu comporte un attribut GameId, qui est un identifiant unique pour le jeu en question. Les attributs User1 et User2 stockent les noms d’utilisateur des deux utilisateurs qui jouent au jeu. Les attributs Heap1, Heap2 et Heap3 stockent le nombre d’objets contenus dans chacun des trois tas. Pour finir, l’attribut LastMoveBy indique le joueur qui a effectué le déplacement le plus récent.

    Le répertoire scripts/ contient un fichier dénommé createGame.js, qui ajoute un exemple de jeu à votre table. Le contenu du fichier est le suivant :

    const AWS = require('aws-sdk')
    const documentClient = new AWS.DynamoDB.DocumentClient()
    
    const params = {
      TableName: 'turn-based-game',
      Item: {
        gameId: '5b5ee7d8',
        user1: 'myfirstuser',
        user2: 'theseconduser',
        heap1: 5,
        heap2: 4,
        heap3: 5,
        lastMoveBy: 'myfirstuser'
      }
    }
    
    documentClient.put(params).promise()
      .then(() => console.log('Game added successfully!'))
      .catch((error) => console.log('Error adding game', error))

    Vous importez le kit AWS SDK, puis créez une instance du client de document DynamoDB. Le client de document est une abstraction de plus haut niveau par rapport à l’API DynamoDB de niveau inférieur ; il facilite le travail avec les éléments DynamoDB. Une fois le client créé, le script regroupe les paramètres pour un appel d’API PutItem, notamment le nom de la table et les attributs de l’élément. Le script appelle ensuite la méthode put() sur le client de document et déconnecte les informations concernant le succès ou l’échec.

    Vous pouvez exécuter le script pour insérer un jeu dans votre table en exécutant la commande ci-dessous dans votre terminal :

    node scripts/createGame.js

    Vous obtiendrez la sortie suivante dans votre terminal :

    Game added successfully!

    Remarque : si vous exécutez trop rapidement la commande, vous pourriez obtenir un message d’erreur indiquant que la table n’est pas encore disponible. Patientez une minute, puis réessayez la commande.

    Bravo ! Vous avez à présent ajouté un seul jeu dans votre table. Dans l’étape suivante, vous allez apprendre comment mettre à jour cet élément de jeu pour simuler un déplacement de la part d’un utilisateur.

  • Étape 3 : mettre à jour un élément de jeu dans votre table

    Maintenant que l’élément de jeu se trouve dans votre table, vous pouvez apprendre à simuler un joueur qui effectue un déplacement dans un jeu en cours.

    Cette opération peut se faire de deux manières. Dans la première méthode, vous récupérez l’élément à l’aide de l’API GetItem. Ensuite, vous mettez à jour l’élément de jeu dans votre application suivant le déplacement effectué par le joueur. Pour finir, vous remplacez l’élément existant dans DynamoDB en utilisant l’API PutItem. Bien qu’elle soit efficace, cette méthode nécessite plusieurs requêtes vers votre table DynamoDB et risque d’écraser tous les changements intervenus entre la récupération et la réécriture de votre élément de jeu.

    La seconde méthode consiste à utiliser l’appel d’API UpdateItem dans DynamoDB. Avec l’API UpdateItem, vous pouvez mettre à jour votre élément DynamoDB en place via une seule requête. Pour ce faire, vous spécifiez l’élément et les attributs que vous souhaitez modifier, ainsi que les conditions que vous désirez déclarer sur l’élément. Cette option est la plus indiquée pour modifier un élément, car elle ne nécessite pas plusieurs appels à votre base de données.

    Le répertoire scripts/ comprend un fichier dénommé performMove.js, dont le contenu est le suivant :

    const AWS = require('aws-sdk')
    const documentClient = new AWS.DynamoDB.DocumentClient()
    
    const performMove = async ({ gameId, user, changedHeap, changedHeapValue }) => {
      if (changedHeapValue < 0 ) {
        throw new Error('Cannot set heap value below 0')
      }
      const params = {
        TableName: 'turn-based-game',
        Key: { 
          gameId: gameId
        },
        UpdateExpression: `SET lastMoveBy = :user, ${changedHeap} = :changedHeapValue`,
        ConditionExpression: `(user1 = :user OR user2 = :user) AND lastMoveBy <> :user AND ${changedHeap} > :changedHeapValue`,
        ExpressionAttributeValues: {
          ':user': user,
          ':changedHeapValue': changedHeapValue,
        },
        ReturnValues: 'ALL_NEW'
      }
      try {
        const resp = await documentClient.update(params).promise()
        console.log('Updated game: ', resp.Attributes)
      } catch (error) {
        console.log('Error updating item: ', error.message)
      }
    }
    
    performMove({ gameId: '5b5ee7d8', user: 'theseconduser', changedHeap: 'heap1', changedHeapValue: 3 })

    Ce script est légèrement compliqué. Procédons donc étape par étape.

    À l’instar du script précédent, vous importez le kit AWS SDK et créez une instance de client de document DynamoDB.

    Ensuite, vous définissez une méthode appelée performMove. Cette méthode est similaire à une méthode interne que vous emploieriez dans votre application lorsqu’un utilisateur demande à effectuer un déplacement. Le script regroupe les paramètres pour un appel d’API UpdateItem. Pour commencer, il modifie deux attributs sur le jeu, à savoir le dernier utilisateur à avoir effectué un déplacement et le nombre d’éléments formant le tas modifié.

    Les paramètres de l’API UpdateItem effectuent ensuite quelques déclarations concernant l’état actuel du jeu. Le paramètre ConditionExpression est évalué avant la mise à jour de l’élément pour confirmer que ce dernier est dans l’état désiré. Vous effectuez les trois déclarations suivantes dans votre expression de condition :

    1. L’utilisateur qui souhaite effectuer un déplacement est l’un des deux utilisateurs du jeu.
    2. Le tour actuel revient à l’utilisateur souhaitant effectuer le déplacement.
    3. La valeur actuelle du tas d’objets en cours de modification est supérieure à la valeur de modification en cours.

    Pour finir, les paramètres indiquent une valeur ReturnValue de ALL_NEW, ce qui signifie que DynamoDB renvoie l’élément intégral après la mise à jour de ses valeurs. Une fois que vous possédez cette sortie, votre application peut évaluer le jeu pour vérifier s’il y a un gagnant.

    Au bas de ce fichier se trouve un exemple d’appel de cette méthode dans votre application. Vous pouvez exécuter le script avec la commande ci-dessous :

    node scripts/performMove.js

    Vous obtiendrez la sortie suivante dans votre terminal :

    Updated game:  { heap2: 4,
      heap1: 3,
      heap3: 5,
      gameId: '5b5ee7d8',
      user2: 'theseconduser',
      user1: 'myfirstuser',
      lastMoveBy: 'theseconduser' }

    Comme vous pouvez le voir, l’écriture est réussie, et le jeu a été mis à jour.

    Essayez d’exécuter à nouveau le script dans votre terminal. Vous obtiendrez la sortie suivante :

    Error updating item:  The conditional request failed

    Vos requêtes conditionnelles ont échoué cette fois. L’utilisateur demandeur, theseconduser, est le joueur qui a effectué le déplacement le plus récent. Par ailleurs, le tas modifié, heap1, possédait déjà une valeur 3, ce qui signifie que l’utilisateur n’a rien modifié. En conséquence, la requête a été rejetée.


Dans ce module, vous avez mis en service une base de données Amazon DynamoDB pour stocker vos données de jeu. Vous vous êtes familiarisé avec les clés principales dans DynamoDB relativement à la modélisation de vos données. Après avoir créé une table, vous avez appris comment y insérer des éléments en vue de stocker l’état initial du jeu. Pour finir, vous avez appris comment mettre à jour des éléments dans vos données afin d’éviter de multiplier les requêtes vers DynamoDB dans une seule requête.

Dans le prochain module, vous allez apprendre comment utiliser Amazon Simple Notification Service (Amazon SNS) pour envoyer des SMS pour informer vos utilisateurs des événements importants survenant dans le jeu.