2

We have a RESTful API with /devices and /buttons, whereas one device may have 0 to ca. 1000 buttons. The request GET /devices/{deviceId}/buttons implements therefore pagination (with startIndex and limit). Each button has a sortSequence property, which is a number. Buttons must be sorted based on this property (there is no relation to alphabetic name or sth else, buttons are ordered based on the wishes of the end user with drag and drop in the list).

The question is, how do you handle the modification of the sortSequence? Now we have it in the PUT /devices/{deviceId}/buttons/{buttonId} Payload: [... and new sequence]. But what about other buttons? E.g. if we have four buttons with sequences 1,2,3,4 and the user drag and drops the last button on the first position, not one change, but several take place: 4->1, 1->2, 2->3, 3->4.

Who is responsible for the ensuing changes, the client or the server?

If client, than:

  • Through one drag and drop, the client has to send possibly hundreds of REST calls to modify the sequence of all buttons in between
  • As there is paging, the client cannot create a new button without querying all of them, as it needs to know the highest sequence

If server, than:

  • A PUT to one resource (button) updates a bunch of other buttons, which I see as a violation of REST principles. Also it triggers a bunch of web socket update events for each button, which slow the UI down.
  • If create/modify/delete buttons requests are coming quickly, and sequences somewhere in the middle are modified, the server shall run into concurrency exceptions, when multiple parallel request threads will try to update the same objects possibly to different values

And of course, whoever does it, if a button is created nearly at the same time from two clients, the sequence might dublicate itself.

Both approaches seem rather bad and problematic. So is there a generally accepted best practice how to handle such modifications?

Infrastructure: .net core server, signalR, web/iOS/Android clients, ms sql db

jannis
  • 4,843
  • 1
  • 23
  • 53
Maxim Zabolotskikh
  • 3,091
  • 20
  • 21
  • `which I see as a violation of REST principles` - which principles specifically? – jannis Nov 10 '19 at 00:09
  • well, REST principles are rather shady, but I understand that it's generally accepted that one REST call SHOULD modify one resource. In other cases it should be operation on collection, if it's exposed as a resource. – Maxim Zabolotskikh Nov 11 '19 at 08:10
  • You could implement a linked list of buttons (in the storage layer). But it could cause problems with pagination (depending on the type of storage). Is pagination a must? How do you implement drag-n-drop within a paginated list? What do you use for storage? – jannis Nov 12 '19 at 08:43
  • Oh didn't see that you already metnioned the stack. Anyway the other questions still stand. – jannis Nov 12 '19 at 08:54
  • Linked list is an interesting idea, which I will give some thinking. Pagination is a must, and currently not yet implemented by the UI team. I think it will be an endless scroll, as I cannot imagine drag and drop with real pages.. – Maxim Zabolotskikh Nov 12 '19 at 09:09
  • I'd start from the UI design here as it will force some important backend implementation decisions. IMHO a drag'n'drop list of ~1000 elements with infinite scroll and possibility of concurrent modification will be very confusing and uncomfortable for the end-users. I'd suggest giving some more thought on this. Identifying smaller groups/classes of buttons (that make sense from the business POV) might be a good idea. – jannis Nov 12 '19 at 09:54
  • You can look for tips on the UX StackExchage. Like here: https://ux.stackexchange.com/questions/83081/drag-and-drop-in-long-lists – jannis Nov 12 '19 at 10:01
  • And about linkedlist db implementation: https://stackoverflow.com/q/65205/4494577 https://stackoverflow.com/q/33205757/4494577 https://stackoverflow.com/q/9536262/4494577 https://stackoverflow.com/q/675117/4494577 – jannis Nov 12 '19 at 11:39

1 Answers1

0

Here is my practice.

I am using a relative change value to make the sequence change.

In HTTP request:

PATCH /buttons/:buttonId/sequence?deviceId=:deviceId

{ "$change": n }

n is allowed to be any integer or +/-'INFINITY'.

Be aware the query part will be your scope for ordering.

Then in server I make this field change in these cases:

  • If n is a number, update all n items' sequence in order by +/-1, and update the :buttonId item +/-n. The plus/minus is based on direction.
  • If n is +/-'INFINITY', means you want to put it to top or tail. Then get the max/min sequence in scope and plus/minus 1 will be the value you will set.

Any of these cases will do no more than 2 SQL query (exclude SELECT).

Most logic you could find in my JS code as a reference: ModelService.js of mytharcher/exprest.

mytharcher
  • 742
  • 7
  • 18