Jonathan Livni
Jonathan Livni

Reputation: 107202

RESTful reordering of nested objects

I have a RESTful API that supports two objects so as object A contains an ordered list of nested objects B:

Create object A               - POST  /a
Create object B and add to A  - POST  /a/<id>/b
Update object B in A          - PATCH /a/<id>/b/<id>

What would be a RESTful way to update the order of B objects in a specific A?

Option 1: PATCH /a/<id> with json content that replaces A.Bs
A has a list of embedded Bs, namely A.Bs so you can replace that list in its entirety also changing the order on the way. This relies on the client to resubmit the entire list correctly.

Option 2: PATCH /a/<id> with json content that replaces A.B_order
Add a separate list of B ids and have the client update it. This is similar to Option 1 but does not rely on the client resubmitting all the objects. It does require the server to manage the list, updating it upon B creation, and validating the update contains all the required B ids on list order update.

Option 3: PATCH /a/<id>/b with json content that replaces A.Bs
The same as Option 1, but with a different URL

Which would be most RESTful and clear?
Any other options?

Upvotes: 3

Views: 1130

Answers (3)

Evert
Evert

Reputation: 99717

The question I would ask myself is: "What does 'order' mean in this case".

The specific instances of B don't have an order between them. They're all independent resources that are not really 'aware' of each order.

Given that, it's not really the B resource that you are changing. What are you changing?

Presumably there is a collection of B's somewhere. You do a GET request on that collection to get an ordered list of B's. Do you get that list on /a/<id> or on /a/<id>/b ?.

Wherever that ordered list is, I would also do the operation to change the order because the order is a 'property' of the collection.

So for the sake of the argument, lets assume that your 'collection of B lives on /a/<id>b. What format should that be?

Well, a good REST service will replace the entire state. So as a default I would do a PUT request on that resource and do a full replace of the entire thing.

If you don't like that idea and want to use PATCH to update only a part of the collection (and nothing else), I think I would opt for one of these:

  1. Use a standard format, like json-patch.
  2. Come up with your own syntax to describe this.

Option 2 will likely be a lot simpler to implement, and I would also keep the format as simple as possible.

If you use a format like HAL, a collection is probably a list of links. In that case I would use a syntax like:

{
  "_links": {
     "item": [
        { "href": "/a/<id>/b/ordered-item-1" },
        { "href": "/a/<id>/b/ordered-item-2" }
      ]
  }
}

If you don't have a hypermedia-style API, you probably use id's and force the client to expand id's in urls. In that case, I'd imagine the format could look like:

{
   "items": [ 1, 3, 5, 2]
}

In each case, it's a Good Idea to define your own media type for this, because this format for PATCH has special meaning to your api. For example:

application/vnd.jonathan.patch+json

Upvotes: 0

Andrey Usov
Andrey Usov

Reputation: 1597

Given Foo has Bars and Bars are resources (have ID or link), when you need to reorder foo.bars then I would suggest:

’PUT /foos/:id/bars’ with array of IDs or links in the body.

But if Bars are not resources (have no ID), then:

’PATCH /foos/:id’ with body of Foo including complete new array of Foo.bars in the ’bars’ property.

Upvotes: 0

Eric Stein
Eric Stein

Reputation: 13682

I would suggest using the proposed standard defined in RFC 6902. Specifically, the "move" op would seem to be what you're looking for.

Upvotes: 2

Related Questions