Comment concevoir une ressource de liste ordonnée dans un service reposant?


11

J'ai rencontré ce même problème encore et encore et je n'ai pas trouvé de solution que je ressentais vraiment comme optimale.

Dites dans une application, vous avez une liste ordonnée et vous laissez l'utilisateur changer cet ordre par glisser-déposer ou quelque chose. Vous souhaitez que les modifications de l'ordre persistent. Comment modélisez-vous cela?

Comment dois-je concevoir un service reposant d'une ressource de liste ordonnée?

En particulier, comment concevoir le listet le itemmodèle d'une ressource reposante? La conception la plus courante que j'ai vue est l' itementité ayant une propriété orderou position. Une autre approche que j'ai entendue est une liste doublement liée sur les articles.

Qu'est-ce qu'une approche qui n'écrit pas trop dans la base de données et qui est généralement rapide à mettre à jour et à lire pour les clients? Comment les points de terminaison doivent-ils être exposés?


Par curiosité, pourquoi est-il important de renvoyer une liste ordonnée spécifiquement?
Adam Wells

Eh bien, je suppose que je ne cherche pas spécialement à renvoyer une ressource de liste ordonnée, mais simplement à conserver l'ordre / la position de la ressource qui peut faire partie d'une ressource de liste réelle ou simplement implicitement d'une liste. Je veux dire à l'utilisateur de modifier l'ordre des tâches dans une liste de tâches. Mais peu importe ce qu'il y a encore une liste où l'ordre est important. Ce que je ne trouve pas, c'est un bon moyen de concevoir cela
Rico Kahler

Réponses:


14

La représentation d'une liste ordonnée est l'un des problèmes difficiles des bases de données relationnelles. L'ajout d'une propriété de position à la relation liste-appartenance est le moyen le plus courant de le faire, car vous pouvez facilement récupérer la liste ordonnée en l'ajoutant ORDER BY positionà votre requête SQL et parce que vous pouvez facilement insérer des éléments au milieu de la liste en faisant la moyenne de la valeurs du membre de liste précédent et suivant, en supposant que la position est un flottant plutôt qu'un entier.

L'utilisation de listes doublement liées doit être évitée, car il est facile de rendre accidentellement les liens incohérents et de se retrouver avec un graphique ou un arbre cyclique à la place.

Cependant, les API RESTful ne souffrent pas des restrictions des bases de données relationnelles. Vous pouvez simplement faire quelque chose qui semble naturel, plutôt que d'utiliser un hack comme une propriété de position.

Si vous n'avez que quelques centaines d'éléments dans la liste, transférez simplement la liste entière dans une demande. En supposant que nous voulons réorganiser [1, 2, 3, 4]où les membres de la liste sont des identifiants, nous pourrions

POST /url/of/the/list
Content-type: application/json
...

[1, 2, 4, 3]

Le backend peut ensuite traduire cela dans la technologie de base de données que vous utilisez, mais l'utilisateur de l'API n'a pas à prendre en compte ces détails.

Si la liste est grande et que les éléments sont généralement demandés individuellement, vous pouvez autoriser un index dans l'url:

GET /page/7

Si vous êtes dans HATEOAS, la réponse peut inclure des liens précédent / suivant pour simplifier la navigation, si la ressource est généralement consommée comme ça. Cependant, cela ne signifie pas nécessairement que votre base de données contient également cette liste doublement liée.

Si la liste est très volumineuse, vous souhaiterez peut-être exposer des ArrayListopérations similaires à / insertou . Je pourrais imaginer un appel commepushappend

POST /url/of/the/list?at=1357;mode=insert
...

description of the item to insert

Si la réorganisation est un cas d'utilisation courant et que la réorganisation doit être validée immédiatement, vous pouvez proposer un point de terminaison approprié dans votre API:

POST /url/of/the/list/reorder-item?from=783;to=1357

Si la liste réorganisée doit être validée explicitement, il sera plus facile de transférer la nouvelle commande en tant que document JSON, voir ci-dessus.

Maintenant, ce n'est pas tout à fait vrai que vous pouvez voir votre API comme complètement séparée de la technologie de base de données que vous utilisez. Cependant, il est préférable de garder l'API externe aussi libre que possible des détails d'implémentation. Si une réorganisation touche environ 30 lignes juste pour mettre à jour une colonne d'ordre entier, ce n'est pas grave. Faites simplement la chose la plus simple possible et mettez toujours à jour toute la liste. Si votre évolutivité nécessite une utilisation plus sophistiquée de votre base de données, préférez capturer cette sophistication dans le backend, où il est plus facile de maintenir la cohérence.


1
Notez que l'approche "remplacer la liste entière" peut devenir problématique si plusieurs clients apportent des modifications. Si vous ne prenez aucune précaution, vous pouvez finir par écraser les modifications de quelqu'un d'autre ("le dernier à écrire gagne").
oefe

Les opérations de type liste ne devraient pas avoir ce problème, à condition que les paramètres (at, from, to) soient des identifiants, pas des index de liste
oefe

2

Je pense que la viabilité des différentes approches dépend fortement de la base de données sous-jacente utilisée.

Cette approche a suggéré de déplacer un article dans la commande:

POST / url / of / the / list / reorder-item? From = 783; to = 1357

Cela peut être soumis à des conditions de concurrence, sauf si vous avez une transactionnalité SERIALISABLE. Le niveau par défaut de READ_COMMITTED dans la plupart des bases de données n'éliminera pas une condition de concurrence critique!

En fait, je pense que dans la plupart des cas - tant que la liste est relativement petite - alors l'approche de remplacement de la liste complète a moins de problèmes avec les conditions de concurrence et ne peut pas corrompre les données. Si l'ensemble des éléments a changé depuis que le client a fait la demande, vous pouvez renvoyer un 409 (Conflit).

Il souffre des dernières victoires en écriture, mais c'est vrai de littéralement N'IMPORTE QUELLE api. Quelle que soit l'API que vous implémentez, un autre client peut avoir mis à jour la chose pendant que vous consultez une page.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.