2

You have the following situation:

  1. You have an SQL database containing two tables product and product_images
  2. You would like the user to be able to add, remove, or move around existing images
  3. They can perform those actions from a form which downloads the current state of the product and displays each picture in order.
  4. When a user select a new picture and uploads it, the frontend 1) sends the picture to backend at /upload-picture, 2) backend saves it to S3 and responds with the location of the picture, 4) when user clicks submit the picture URLs are included in the edit product request

What is the usual or good approach to perform the changes?

I thought of the followings ways:

Solution 1: delete then recreate

  1. Frontend sends an array containing both existing and new URLs, something like this:

    {
        "pictures": ['old1', 'old2', 'new1', 'old3', 'new2']
    }
    
  2. Backend deletes all product_images rows of the product and recreates from that pictures array.

Solution 2: compare old and new array, send a diff

  1. Frontend sends an array containing a diff of the form (added, removed, same). For example:

    {
        "pictures": {
        "added": [{"url": "new1", "index": 2}, {"url": "new2", "index": 1}],
        "removed": [{"url": "old1", "oldIndex": 1}],
        "same": [{"url": "old2", "oldIndex": 2, "newIndex": 0}],
        }
    }
    

It seems like the first solution is easier to implement. What do you think?

2
  • for #1, why stop at the pictures? We could delete the entire product and then create a new product containing different pictures. Or, we could delete the entire products table, and then create a new products table where this product has different pictures. Commented Aug 4, 2021 at 11:31
  • well it is different because for a product it is easy to do with a simple update on a single row (for example in sequelize.js) but when it comes to an array of pictures the order can change, the number of product_images can change etc.. deleting a few rows then recreating them doesnt sound so bad since after all a product contains at most 15 images let's say. Commented Aug 4, 2021 at 11:39

1 Answer 1

5

Keep it RESTy. Have the client indicate the desired state, and let the server figure out how to achieve that state. So I would suggest that you stick with approach #1, which would be the desired array of image IDs.

You suggest that this is implemented by first deleting all rows in the database and then re-adding the desired state. This probably works, but the backend can likely compare the current and new state to find a more efficient update strategy (if this is has a relevant performance impact in the context of this application). In particular, the backend can calculate the representation in solution #2 by itself.

Since solution #2 involves a more complex data model, it is easier to arrive at an invalid state – and note that input from clients must not be trusted. For example, a client might specify have an index collision, or might silently drop old images without adding them as "removed".

"pictures": {
  "added": [{"url": "new1", "index": 0}],
  "same": [{"url": "old1", "oldIndex": 1, "newIndex": 0}]
}

Properly validating this would likely require assembling an array as in solution #1. This alone is a strong indication that the data model in solution #1 should be preferred, but as discussed this has no impact on how the server actually performs the update.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.