← Tous les articles

JSON Patch vs JSON Merge Patch : RFC 6902 vs 7396

JSON Patch (RFC 6902) envoie des opérations explicites ; JSON Merge Patch (RFC 7396) superpose un objet partiel. Comparez les deux avec des exemples et choisissez le bon.

Quand une API HTTP doit mettre à jour une partie d'une ressource, deux standards IETF se disputent le job : JSON Merge Patch (RFC 7396) et JSON Patch (RFC 6902). Ils se ressemblent mais fonctionnent très différemment —— Merge Patch superpose un objet partiel, tandis que JSON Patch envoie une liste explicite d'opérations. Ce guide montre comment chacun fonctionne, les compare tête à tête et t'aide à choisir le bon.

Le problème : mises à jour partielles

Une requête PUT remplace une ressource entière, ce qui est gaspilleur et risqué quand tu ne veux changer qu'un seul champ. La méthode HTTP PATCH existe pour les mises à jour partielles —— mais PATCH ne définit pas de format de body. C'est ce que ces deux standards fournissent.

JSON Merge Patch (RFC 7396)

Un Merge Patch est simplement une version partielle du document cible. Le serveur le superpose : les clés du patch sont définies, les clés mises à null sont supprimées, et les clés non mentionnées restent intactes.

// Original
{ "title": "Hello", "author": "Ada", "tags": ["a", "b"], "draft": true }

// Merge Patch body (Content-Type: application/merge-patch+json)
{ "title": "Hello World", "draft": null }

// Résultat
{ "title": "Hello World", "author": "Ada", "tags": ["a", "b"] }
//   ^ title mis à jour      ^ author intouché         ^ draft supprimé (était null)

C'est intuitif et compact. Le piège : parce que null signifie « supprimer », tu ne peux pas utiliser Merge Patch pour mettre une valeur à null, et les tableaux ne peuvent être remplacés qu'entièrement —— il n'y a aucun moyen de changer un seul élément de tableau.

JSON Patch (RFC 6902)

Un JSON Patch est un tableau ordonné d'opérations, chacune ciblant un emplacement avec un chemin JSON Pointer. C'est explicite et précis :

// JSON Patch body (Content-Type: application/json-patch+json)
[
  { "op": "replace", "path": "/title", "value": "Hello World" },
  { "op": "remove",  "path": "/draft" },
  { "op": "add",     "path": "/tags/-", "value": "c" },
  { "op": "test",    "path": "/author", "value": "Ada" }
]

Les six opérations :

opEffet
addAjouter une valeur (ou append à un tableau avec /-)
removeSupprimer la valeur à un chemin
replaceRemplacer la valeur à un chemin
moveDéplacer une valeur d'un chemin à un autre
copyCopier une valeur vers un autre chemin
testAssertion sur une valeur (abandon de tout le patch si échec)

L'op test permet des mises à jour sûres et atomiques : si le document n'est pas dans l'état attendu, tout le patch est rejeté —— utile pour le contrôle de concurrence optimiste.

Comparaison tête à tête

JSON Merge PatchJSON Patch
RFC73966902
Content-Typeapplication/merge-patch+jsonapplication/json-patch+json
LisibilitéHaute —— ressemble aux donnéesMoindre —— liste d'opérations
Peut mettre une valeur à nullNon (null signifie supprimer)Oui
Modifier un seul élément de tableauNon (remplacer tout le tableau)Oui (par index)
Mises à jour conditionnelles / atomiquesNonOui (op test)
Move / copyNonOui
Mieux pourMises à jour simples de champs d'objetÉditions précises, conscientes des tableaux, atomiques

Quand utiliser lequel

  • JSON Merge Patch —— quand les clients mettent surtout à jour des champs d'objet de niveau supérieur et que tu valorises un body qui se lit comme la ressource. Excellent pour des réglages simples et des mises à jour de profil. Souviens-toi juste que tu ne peux pas mettre de champs à null ni éditer des items de tableau.
  • JSON Patch —— quand tu dois éditer des éléments de tableau, déplacer ou copier des valeurs, mettre des champs à null, ou appliquer des changements atomiquement avec une précondition. Le choix standard pour l'édition collaborative et les change sets compatibles avec l'audit.

Sémantique de HTTP PATCH : idempotence et headers

Deux détails HTTP qui attrapent souvent les équipes qui livrent un endpoint PATCH :

  • PATCH n'est pas tenu d'être idempotent (contrairement à PUT). Un JSON Patch avec {"op":"add","path":"/items/-","value":...} fait append —— l'appliquer deux fois ajoute deux fois. Si tu veux des retries sûrs, soit utilise une op test pour asserter l'état d'abord, soit conçois tes ops pour que la ré-application soit un no-op (utilise replace sur un chemin fixe au lieu de add sur /items/-).
  • Utilise le bon Content-Type. RFC 6902 = application/json-patch+json ; RFC 7396 = application/merge-patch+json. Les serveurs branchent généralement là-dessus.
  • Concurrence optimiste. Combine une op test de JSON Patch (ou un header If-Match avec ETag) pour que les writers concurrents ne puissent pas s'écraser silencieusement.

Librairies à connaître

Pour JSON Patch, fast-json-patch est le paquet npm de facto —— il applique, génère (diff de deux documents pour produire un patch) et observe (suit les changements d'un objet observé). Pour JSON Merge Patch, les règles sont assez petites pour être inlinées, mais json-merge-patch les implémente en gérant les cas limites de suppression par null.

Appliquer des patches en code

// JavaScript —— fast-json-patch implémente RFC 6902
import { applyPatch } from 'fast-json-patch';
const updated = applyPatch(document, patchOps).newDocument;

// JSON Merge Patch est trivial à appliquer par récursion, mais une lib
// (par ex. json-merge-patch) gère correctement les règles de suppression par null.

Après avoir appliqué un patch, tu peux confirmer que le changement est exactement ce que tu voulais en diffeant l'avant et l'après —— voir Comment comparer deux fichiers JSON ou colle les deux dans JSON Diff.

Foire aux questions

Quelle est la différence entre JSON Patch et JSON Merge Patch ?

JSON Merge Patch (RFC 7396) est une copie partielle du document où null supprime une clé. JSON Patch (RFC 6902) est un tableau explicite d'opérations (add, remove, replace, move, copy, test) ciblant des chemins JSON Pointer. Merge Patch est plus simple ; JSON Patch est plus puissant.

Pourquoi JSON Merge Patch ne peut-il pas mettre un champ à null ?

Parce qu'en Merge Patch null est le signal pour supprimer une clé. Si tu dois stocker une vraie valeur null, utilise JSON Patch avec une op replace.

Quel Content-Type devrais-je utiliser ?

application/merge-patch+json pour Merge Patch et application/json-patch+json pour JSON Patch, tous deux envoyés avec la méthode HTTP PATCH.

Comment éditer un élément d'un tableau ?

Utilise JSON Patch avec un chemin comme /items/2, ou append avec /items/-. Merge Patch ne peut remplacer que tout le tableau.

Outils & lectures liés