1
votes

API REST pour mettre à jour les informations avec des valeurs vides ou nulles

J'ai une question générale sur la meilleure façon de créer une API capable de modifier les enregistrements dans une base de données.

Supposons que nous ayons une table avec 10 colonnes et que nous puissions interroger ces 10 colonnes en utilisant REST (GET). La réponse JSON contiendra les 10 champs. C'est facile et fonctionne sans problème.

La prochaine étape est que quelqu'un souhaite créer un nouvel enregistrement via POST. Dans ce cas, la personne n'envoie que 8 des 10 champs de la demande JSON. Nous ne remplirions alors que les 8 champs de la base de données (le reste serait NULL). Cela fonctionne également sans problème.

Mais que se passe-t-il si quelqu'un veut mettre à jour un enregistrement? Nous voyons ici différentes possibilités avec des avantages et des inconvénients.

  1. Seul ce qui doit être mis à jour est envoyé. Problème: Comment pouvez-vous explicitement vider / supprimer un champ? Si un "NULL" est passé dans le JSON, nous obtenons NULL dans l'objet, mais tout autre champ qui n'est pas passé est également NULL. Par conséquent, nous ne pouvons pas distinguer quel champ peut être supprimé et quel champ ne peut pas être touché.

  2. L'objet complet est envoyé. Problème: Ici, l'objet pouvait être récupéré via un GET auparavant, modifié en conséquence et renvoyé via PUT. Maintenant, nous récupérons toutes les informations et pouvons les réécrire directement dans la base de données. Parce que les champs vides étaient déjà vides auparavant ou ont été effacés par l'utilisateur.

Que se passe-t-il si les objets sont étendus par une mise à jour de l'API. Supposons que nous étendions la base de données de cinq champs supplémentaires. L'utilisateur de l'API fait un GET, récupère les 15 champs, mais ne peut lire que les 10 champs qu'il connaît sur sa page (car il n'a pas encore mis à jour son côté). Ensuite, il modifie certains des 10 champs et les renvoie via PUT. Nous ne mettrions alors à jour que les 10 champs de notre site et les 5 nouveaux champs seraient vidés de la base de données.

Ou devez-vous créer un point de terminaison distinct pour chaque champ? Nous avons également pensé à créer une carte avec clé / valeur, ce qui doit exactement être changé.

À propos de la technique: Nous utilisons le Wildfly 15 avec Resteasy et Jackson . P >

Par exemple:

Base de données au début

{
   "id" : 3,
   "name" : "Person 3",
   "country" : "Cananda",
   "age" : 52,
   "weight" :102,
   "phone" : null
}


+----+----------+---------------+-----+--------+--------+-------+
| ID | Name     | Country       | Age | Weight | Salery | Phone |
+----+----------+---------------+-----+--------+--------+-------+
| 1  | Person 1 | Germany       | 22  | 60     | 1929   | 12345 |
| 2  | Person 2 | United States | 32  | 78     | 2831   | NULL  |
| 3  | Person 3 | Canada        | 52  | 102    | NULL   | NULL  |
+----+----------+---------------+-----+--------+--------+-------+

GET ... / person / 2 p>

+----+----------+---------------+-----+--------+--------+-------+
| ID | Name     | Country       | Age | Weight | Salery | Phone |
+----+----------+---------------+-----+--------+--------+-------+
| 1  | Person 1 | Germany       | 22  | 60     | 1929   | 12345 |
| 2  | Person 2 | United States | 32  | 78     | 2831   | NULL  |
| 3  | Person 3 | Canada        | 52  | 102    | 3921   | 99999 |
+----+----------+---------------+-----+--------+--------+-------+

Maintenant, je veux mettre à jour son poids et supprimer le numéro de téléphone

PUT ... / person / 2

+----+----------+---------------+-----+--------+-------+
| ID | Name     | Country       | Age | Weight | Phone |
+----+----------+---------------+-----+--------+-------+
| 1  | Person 1 | Germany       | 22  | 60     | 12345 |
| 2  | Person 2 | United States | 32  | 78     | NULL  |
| 3  | Person 3 | Canada        | 52  | 102    | 99999 |
+----+----------+---------------+-----+--------+-------+


2 commentaires

vous devez valider la demande avant de frapper la base de données .. Il faut également avoir des contraintes NOT NULL sur les colonnes qui n'autorisent pas les valeurs nulles ou vides. Cela garantirait que seules les demandes valides peuvent passer.


Je ne sais pas si j'ai bien rédigé la question. J'ai ajouté un exemple ci-dessous


5 Réponses :


1
votes

Une technique courante consiste à suivre les modifications sur l'entité POJO.

  1. Charger le chien avec couleur = noir, taille = null et age = null
  2. Définissez size sur null (le setter marquera ce champ comme modifié)
  3. Exécuter la mise à jour SQL

Le POJO aura un état interne sachant que la taille a été modifiée, et inclura donc ce champ dans la MISE À JOUR. L ' age , par contre, n'a jamais été défini et est donc laissé inchangé. jOOQ fonctionne comme ça, je suis sûr qu'il y en a d'autres.


0 commentaires

0
votes

Vous pouvez contrôler les valeurs vides ou nulles comme ci-dessous

{
   "id" : 2,
   "weight" :78,
   "phone" : null  
}

i) Lorsque vous mettez à jour le poids et supprimez le numéro de téléphone, demandez au client d'envoyer les champs qui doivent être mis à jour avec l'identifiant d'enregistrement c'est-à-dire id dans ce cas

public class Person{

    @JsonInclude(JsonInclude.Include.NON_NULL) 
    private BigDecimal salary;  // this will make sure salary can't be null or empty//

    private String phone;   //allow phone Number to be empty
    // same logic for other fields
}

ii) Comme vous ajoutez le salaire comme une colonne supplémentaire qui est un champ obligatoire et le client doit en être conscient .. peut-être que vous devez contrat de refonte


0 commentaires

0
votes
  1. Seul ce qui doit être mis à jour est envoyé. Problème: Comment pouvez-vous explicitement vider / supprimer un champ? Si un "NULL" est passé dans le JSON, nous obtenons NULL dans l'objet, mais tout autre champ qui n'est pas passé est également NULL. Par conséquent, nous ne pouvons pas distinguer quel champ peut être supprimé et quel champ ne peut pas être touché.

Le problème que vous avez identifié est authentique; J'ai fait face à cela aussi. Je pense qu'il est raisonnable de ne pas fournir de solution technique pour cela, mais plutôt de documenter l'utilisation de l'API pour informer l'appelant de l'impact de l'omission d'un champ ou de son envoi sous la forme null . Bien sûr, en supposant que les validations côté serveur sont serrées et garantissent la cohérence.

  1. L'objet complet est envoyé. Problème: Ici, l'objet pouvait être récupéré via un GET auparavant, modifié en conséquence et renvoyé via PUT. Maintenant, nous récupérons toutes les informations et pouvons les réécrire directement dans la base de données. Parce que les champs vides étaient déjà vides auparavant ou ont été effacés par l'utilisateur.

Ceci est "plus droit" et doit être documenté dans l'API.

Que se passe-t-il si les objets sont étendus par une mise à jour de l'API.

Avec la responsabilité de l'appelant par le biais de la documentation, cela est également traité implicitement.

Ou devez-vous créer un point de terminaison distinct pour chaque champ?

Encore une fois, il s'agit d'un problème de conception, dont la solution varie d'une personne à l'autre. Je préférerais conserver l'API à un niveau record plutôt qu'au niveau de la valeur individuelle. Cependant, il peut y avoir des cas où ils doivent être de cette façon. Par exemple, des mises à jour de statut.


0 commentaires

1
votes

Supposons que nous étendions la base de données de cinq champs supplémentaires. L'utilisateur de l'API fait un GET, récupère les 15 champs, mais ne peut lire que les 10 champs qu'il connaît sur sa page (car il n'a pas encore mis à jour son côté). Ensuite, il modifie certains des 10 champs et les renvoie via PUT. Nous ne mettrions alors à jour que les 10 champs de notre site et les 5 nouveaux champs seraient vidés de la base de données.

Commençons donc par un exemple - ce qui se passerait sur le Web, où les clients interagissent avec votre API via HTML rendu dans les navigateurs. Le client obtiendrait un formulaire et ce formulaire aurait des contrôles d'entrée pour chacun des champs. Le client met à jour les champs du formulaire, le soumet et vous appliquez ces modifications à votre base de données.

Lorsque vous souhaitez étendre l'API pour inclure plus de champs, vous ajoutez ces champs au formulaire. Le client ne connaît pas ces champs. Alors que se passe-t-il?

Une façon de gérer cela est de vous assurer que vous incluez dans le formulaire les valeurs par défaut correctes pour les nouveaux champs; puis, si le client ignore les nouveaux champs, la valeur correcte sera renvoyée lors de la soumission du formulaire.

Plus généralement, les représentations que nous échangeons dans nos charges utiles HTTP sont des messages ; si nous voulons prendre en charge d'anciens clients, nous avons besoin de la discipline de faire évoluer le schéma de message d'une manière rétrocompatible, et nos clients doivent être écrits en sachant que le schéma de message peut être étendu avec des champs supplémentaires.

La personne utilisant l'API ne sait pas qu'il existe un nouveau champ dans JSON pour le salaire.

La même idée est valable ici - la nouvelle représentation inclut un champ "salaire" que le client ne connaît pas, il est donc de la responsabilité du client de vous renvoyer ces données inchangées , plutôt que de simplement le laisser tomber sur le sol en supposant que ce n'est pas important.

Il y a de nombreux antécédents à ce sujet, il y a 15 à 20 ans, parce que les gens qui écrivaient des messages en XML étaient confrontés exactement au même genre de problèmes. Ils ont laissé certaines de leurs connaissances derrière eux. Le moyen le plus simple de le trouver est de rechercher certaines phases clés; par exemple, doit ignorer ou doit transférer .

Voir:

Les événements d'un magasin d'événements présentent les mêmes types de problèmes. Livre de Greg Young La gestion des versions dans un système basé sur des événements couvre une grande partie du même terrain (les représentations d'événements sont également des messages).


0 commentaires

2
votes

Vous pouvez désérialiser votre JSON en une carte. De cette façon, si une propriété n'a pas été envoyée, la propriété n'est pas présente dans la carte. Si sa valeur est nulle, son à l'intérieur de la carte aura une valeur nulle.

  ObjectMapper mapper = new ObjectMapper();
  TypeReference<HashMap<String, Object>> typeReference = new TypeReference<>() {};
  HashMap<String, Object> jsonMap = mapper.readValue(json, typeReference);
  jsonMap.entrySet().stream().map(Map.Entry::getKey).forEach(System.out::println);

Ce n'est pas une solution très pratique, mais cela pourrait fonctionner pour vous.


0 commentaires