Débutant5 min de lecture

JSON DynamoDB & marshalling

La première fois que tu lis des données brutes depuis l'API DynamoDB, ça ne ressemble pas au JSON que tu as mis. Un objet ordinaire comme {"status": "open", "priority": 3} revient sous la forme {"status": {"S": "open"}, "priority": {"N": "3"}}. Chaque valeur est enveloppée dans un objet à une clé nommant son type. Cet emballage, c'est le JSON DynamoDB, et convertir vers et depuis lui s'appelle le marshalling.

Ce n'est pas du bruit — c'est ainsi que DynamoDB garde les types non ambigus sur le fil. Mais ça déroute quiconque s'attend à du JSON ordinaire, et l'écrire à la main est sujet aux erreurs.

Qu'est-ce que le JSON DynamoDB ?

Le JSON DynamoDB est le format filaire à descripteurs de type qu'utilise DynamoDB, où chaque valeur est enveloppée dans un objet à une clé nommant son type — {"S": "open"} pour une chaîne, {"N": "3"} pour un nombre. Convertir du JSON ordinaire vers ce format (et inversement) s'appelle le marshalling. Il garde les types non ambigus, car le JSON ordinaire ne peut pas exprimer les sets, le binaire, ni distinguer "3" de 3.

  • Le JSON DynamoDB étiquette chaque valeur avec son type{"S": "..."} pour une chaîne, {"N": "..."} pour un nombre, et ainsi de suite.
  • Le marshalling = JSON ordinaire → JSON DynamoDB. L'unmarshalling = l'inverse.
  • Les nombres sont des chaînes sur le fil{"N": "3"}, pas {"N": 3} — pour préserver la précision.
  • Les étiquettes de type sont le système de types de données que tu modélises déjà : S, N, B, BOOL, NULL, L, M, SS, NS, BS.
  • Ne l'écris pas à la main. Le document client du SDK (ou un convertisseur) marshale pour toi ; ne le fais manuellement que pour déboguer ou construire des expressions.

Le problème : le JSON ordinaire ne suffit pas

Le JSON n'a que trois sortes de scalaires — chaîne, nombre, booléen — plus null, les tableaux et les objets. DynamoDB en a plus : le binaire, et trois types de set (set de chaînes, set de nombres, set de binaires) que le JSON ne peut pas exprimer du tout. Le JSON ne peut pas non plus distinguer une chaîne "3" d'un nombre 3, ou une liste d'un set.

DynamoDB ne peut donc pas simplement stocker ton JSON tel quel — il a besoin que le type exact de chaque valeur soit énoncé explicitement. Le descripteur de type est sa façon de le faire, sans perte, à chaque requête et réponse.

Comment fonctionne l'encodage

Chaque valeur d'attribut devient un objet à une seule clé dont la clé est un descripteur de type :

DescripteurTypeExemple
SChaîne{"S": "open"}
NNombre (en tant que chaîne){"N": "3"}
BBinaire{"B": "dGV4dA=="}
BOOLBooléen{"BOOL": true}
NULLNull{"NULL": true}
LListe{"L": [{"S": "a"}, {"N": "1"}]}
MMap{"M": {"k": {"S": "v"}}}
SS / NS / BSSet de chaînes / nombres / binaires{"SS": ["a", "b"]}

Les listes et les maps imbriquent les mêmes descripteurs jusqu'au plus profond, donc un item profondément structuré devient profondément enveloppé. Les nombres voyagent sur le fil sous forme de chaînes exprès — ça laisse DynamoDB préserver une précision arbitraire qu'un nombre JSON (un double IEEE-754) arrondirait discrètement. Ce sont les mêmes types de données avec lesquels tu modélises ; le JSON DynamoDB n'est que leur forme explicite sur le fil, définie dans la référence de l'API bas niveau AWS.

Exemple travaillé : une entrée de journal d'audit

Le JSON ordinaire que tu écrirais dans ton app :

{
  "actor": "u-204",
  "action": "ticket.close",
  "ticketId": 8842,
  "tags": ["billing", "urgent"],
  "redacted": false
}

Marshalé en JSON DynamoDB pour l'API :

{
  "actor": {"S": "u-204"},
  "action": {"S": "ticket.close"},
  "ticketId": {"N": "8842"},
  "tags": {"SS": ["billing", "urgent"]},
  "redacted": {"BOOL": false}
}

Note les choix faits par le marshaller : ticketId est devenu N avec une valeur chaîne ; tags est devenu un set de chaînes (SS), pas une liste — une décision délibérée, parce qu'un set déduplique et est non ordonné. Que tags doive être SS ou L est un choix de modélisation que le convertisseur ne peut pas faire à ta place, ce qui est précisément pourquoi comprendre l'encodage compte.

Convertir dans DynoTable

Tu as rarement besoin de lire ou d'écrire ça à la main. Colle du JSON ordinaire dans le convertisseur JSON DynamoDB pour le marshaler (et inversement), et quand tu assembles une requête, le constructeur d'expressions DynamoDB émet la map de valeurs d'attributs correctement marshalée à côté de l'expression. Dans l'app elle-même, DynoTable affiche les items comme des valeurs ordinaires et lisibles, et les marshale pour toi à l'écriture.

DynoTable affichant un item en valeurs ordinaires, avec le JSON DynamoDB brut disponible.
DynoTable affichant un item en valeurs ordinaires, avec le JSON DynamoDB brut disponible.

Pièges et étapes suivantes

  • Les nombres sont des chaînes en JSON DynamoDB{"N": "3"}. Les guillemets comptent ; n'émets pas un nombre nu.
  • Set vs liste est une décision de modélisation que l'encodage rend visible — choisis délibérément (voir les types de données).
  • Préfère le document client du SDK au marshalling manuel dans le code applicatif ; réserve le JSON DynamoDB manuel au débogage et aux expressions.
  • Les chaînes vides sont autorisées dans les items mais ont historiquement fait trébucher l'outillage — valide les cas limites.

Envie de parcourir les items comme des valeurs ordinaires plutôt que de décoder les étiquettes de type à l'œil ? Télécharge DynoTable et travaille avec tes données directement.

Mis à jour