Tyler Grinn
Tyler Grinn

Reputation: 41

RESTful solution for user to reorder resources

How would one go about allowing a user to reorder resources manually using a RESTful api?

I'm using mysql with an 'sequence' column that can be updated manually. The resources returned from a GET request will be sorted by that column ASC. Is it a good idea to have the front end responsible for determining what each 'sequence' value is and then sending multiple PUT requests to update each resource, or is there a way to provide a single endpoint specifically to reorder resources in one request?

This is the current setup for the part of my express app that needs to allow reordering.

apiRouter.route('/products/:product')
  .get(getProduct)
  .put(updateProduct)
  .delete(removeProduct)

apiRouter.route('/products')
  .get(getProducts)
  .post(addProduct)

And this is my mysql query for getting products:

SELECT
  id, name, width, depth, productId, category
FROM products
WHERE user = :user
ORDER BY sequence ASC

I'm thinking about adding another route like

apiRouter.put('/products/reorder', reorderProducts)

But I'm not sure what the payload should be or what the response should be.

Upvotes: 1

Views: 742

Answers (2)

Tschitsch
Tschitsch

Reputation: 1338

A valid restful approeach would be to update the whole collection:

PUT /products
[
  {...}, {...}
]

But here you need to send all products data in the payload. If you have a big collection its probably nothing you'd like to do.

Personally I'd patch the whole collection instead:

PATCH /products
[
  {"id": 1, "sequence": 1},
  {"id": 4, "sequence": 2},
  {"id": 3, "sequence": 3},
  {"id": 2, "sequence": 4}
]

But you'd need to handle errors for each resource you are about to update and respond with 207 Multi-Status, but well this is not very restful afaik.

Patching each resource would do the trick in a restful way, but you'd need to perform all the requests to your API, what you most likely dont want to do, when you have a huge set of products.

Upvotes: 0

Tyler Grinn
Tyler Grinn

Reputation: 41

I've decided to use just return a 200 status code for now. The request only includes a number array called 'ids' which is looped through and the index set as the 'sequence' column value:

export const reorderProducts: RequestHandler = async (req, res) => {
  await products.reorderProducts(req.user.id, req.body.ids)
  res.sendStatus(200)
}
      // in model function 'reorderProducts'
      for (let index = 0; index < ids.length; index++) {
        await query(`
          UPDATE products
          SET sequence = :index
          WHERE
            user = :user
            AND id = :id
        `, {
          user,
          index,
          id: ids[index],
        })
      }  

Upvotes: 0

Related Questions