2

I hope I can explain what is troubling me.

Example: I have an object basket with a list of product objects. So normally I would build my routes like this baskets/{basketId}/products/{productId). But product is an interface and there are different implementations like cds and books that all require their own resource representation.

So how do I build my routes now?

Like one of those?:

baskets/{basketId}/products/{productId)/cds,
baskets/{basketId}/products/{productId)/books

and so on

baskets/{basketId}/products/{productId)/cds/{productId} , 
baskets/{basketId}/products/{productId)/books/{productId}
baskets/{basketId}/cds/{productId},
baskets/{basketId}/books/{productId}

What would be the restful way?

matt freake
  • 4,877
  • 4
  • 27
  • 56
Tarken
  • 2,112
  • 2
  • 23
  • 42
  • About rest hierarchy structure see https://stackoverflow.com/questions/20951419/what-are-best-practices-for-rest-nested-resources – Grigory Kislin Mar 25 '19 at 16:42

4 Answers4

2
URI + Resource should define any Rest Endpoint.

In your case URI is

basket/{basketId}/product/{productId)

and Resource is product

CDs and Books are just the type of resource. Its important you understand this.

So it could be defined like

/basket/{basketId}/product/{productId)?type=CD
/basket/{basketId}/product/{productId)?type=Book
Vineet Singla
  • 1,609
  • 2
  • 20
  • 34
1

I think that next manner can be used. We have a basket with products, so each product can be identified by url: baskets/{basket_id}/products/{product_id} and this url will represent common product (in form of json/form/etc), if you want to specify concrete product type, than you should provide query parameter that defines product type, for example:baskets/{basket_id}/products/{product_id}?type=book, etc. Any product will have unique identifier, but you should control that product with provided id has type that you have requested. Hope this helps.


Edit:

Another approach is when you querying basket products you can return some kind of shortcuts list, each item of that list will contain product id an product type id. Then, to get concrete product, you should build concrete product url with concrete product id. For example (if we use json): get /baskets/{basket_id}/products, got [{ id: 1, type: "book"}, ...], then get /books/1, but this approach will need two server calls.

nndru
  • 2,057
  • 21
  • 16
  • Hi thanks for your answer. But doing it that way I wouldn't I have to do a lot of if/switch inside the prodcuts resource to find the matching business/validation logic? – Tarken Mar 06 '14 at 15:03
  • You should introduce some kind of registry where you can specify product type as a key and some kind of validation logic (function, class, etc) as a value. Hence, client code will be stable and only new registry items will be added. This approach can be used bot at client or server side. – nndru Mar 06 '14 at 15:08
  • I like the idea you introduced with your edit. Just return ref info or something like a link to the actual resource. Seems like a good restful solution. – Tarken Mar 06 '14 at 15:19
  • Okay next question how would you do create/update of products for the basket? – Tarken Mar 06 '14 at 15:37
  • Product creation/updating within basket consists from two steps: 1) create product of concrete type, e.g. `post books/` request body: `{ }`, you will get `book_id`, 2) assign product with concrete basket, e.g. `post basket/{basket_id}/products` request body: `{ product_id: , type: "book" }` Hence, relation between basket and products should be treated as resource to, so you can perform any CRUD manipulations on it. – nndru Mar 07 '14 at 08:33
1

Think more dynamic, don't get stuck in thinking in static languages: I would keep baskets/{basketId}/products/{productId} and return polymorphic types.

This can be implemented in java like this:

public class BasketResponse {
   private Product product;
}

public class Product {
   private long id;
   private String type;
}

public class CD extends Product {
   private String albumName;
   
   public CD() {
      super.setType("CD");
   }
}

This will only work of course with a dynamic datatype like JSON. Jackson serializes the object with the properties of the actual type not the declared type.

On the client side, if you are using a dynamic language like JavaScript than this is no problem since you just have to check the type to see what properties you will expect. If you are using a static language like java you have to cast the types according to the type field. Usually JSON frameworks can assist you in correct casting your types (again see Jackson doc)

Patrick
  • 33,984
  • 10
  • 106
  • 126
  • Hi thanks for your answers. I am using json and a js client. How would you build a create route for a new cd product? Would you use post baskets/{basketId}/products/{productId)?type=cd? – Tarken Mar 06 '14 at 15:36
  • No, Jackson can handle polymorphy with a little help (see this: http://programmerbruce.blogspot.co.at/2011/05/deserialize-json-with-jackson-into.html) or you could do it manually by checking the "type" before serializing it to a static type. Let the client just also send the CD Object and cast it on the server side accordingly. – Patrick Mar 06 '14 at 15:39
  • Its really freeing once you stop thinking of objects in a static way :) – Patrick Mar 06 '14 at 15:41
  • :-) so you would just post to baskets/{basketId}/products/{productId). – Tarken Mar 06 '14 at 15:43
  • How would you handle the different validations for each class? – Tarken Mar 06 '14 at 15:49
  • Jackson creates the correct static type, so not different than usual (on the serverside)? – Patrick Mar 06 '14 at 16:00
  • I meant custom validations ;-) and additional logic. If that's all in one resource that might get pretty big. – Tarken Mar 06 '14 at 16:13
  • I dont think thats a problem specific to this issue, or I dont understand what you exactly imply by "validation"? – Patrick Mar 06 '14 at 16:28
  • For example an cd has an attribute like artist where I have to make a check if that artist is already in my database and than do something accordingl (Just some example). And if I have to do that for every product inside the product resource it would get bloated and with a lot of ifs. When I am thinking about it again I could create some factory that does all that for me. – Tarken Mar 06 '14 at 16:45
1

Roy Fielding gives the following advice regarding REST APIs:

A REST API must not define fixed resource names or hierarchies (an obvious coupling of client and server).

So there is no "RESTful" URI structure beside this one: Don't depend on URI structures!

Also have a look at this answer to a similar question.

I think your interface / implementation should be reflected in the media type and not the uri path.

Community
  • 1
  • 1
xwoker
  • 3,105
  • 1
  • 30
  • 42