Representing inheritance in serialized resources

1,400 views
Skip to first unread message

erewhon

unread,
Feb 13, 2013, 1:37:52 PM2/13/13
to api-...@googlegroups.com
Suppose you have products resources (e.g. /products) that contain an inheritance hierarchy:

- videos (derived from product)
- clothing (derived from product)

When developing an API you can choose to expose the hierarchy in a couple of ways.  When talking about JSON, you might just emit type information in the result:

{[
{"$type": "com.foo.products.video", ... }, {"$type": "com.foo.products.clothing", ... }, ...
]}

Or you could explicitly model the inheritance as:

{
"video": [{...}, {...}, ...],
"clothing": [{...}, {...}, ...]
}

The first option has the benefit of being easier to manage on the server side (less changes to support new inheritance) but can get complicated and "noisy" in the serialization (e.g. many serializers treat the emission of a "type" value as an on/off switch so you end up with JSON strings that are littered with type information and usually that type information is mostly useless except for the trailing name of the type, not the fully qualified bits).

The second option addresses the noise in the JSON (though it adds another level of depth to the structure).  To be honest I think emitting type information is the preferred solution ... I've gone down the path of plumbing serializers to clean up what actually gets emitted (e.g. instead of "$type": "com.foo.products.video" we can just emit "$type": "video" and in cases where there is no inheritance do not emit "$type" at all).

I'm curious if there are some recommended best practices here or if there are strong opinions in this regard.


Felipe Sere

unread,
Feb 13, 2013, 3:48:38 PM2/13/13
to api-...@googlegroups.com
Do you have any value in aktually exposing the hierarchy? What is the client-side use case for the hierarchy?
--
You received this message because you are subscribed to the Google Groups "API Craft" group.
To unsubscribe from this group and stop receiving emails from it, send an email to api-craft+...@googlegroups.com.
Visit this group at http://groups.google.com/group/api-craft?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 


--
Gruß,
Felipe

erewhon

unread,
Feb 13, 2013, 4:43:05 PM2/13/13
to api-...@googlegroups.com
The primary objective is to facilitate the identification of different *types* of products since client parsing/display/rules for each type can be different.  In the end all we require is a means to facilitate the differentiation.

To unsubscribe from this group and stop receiving emails from it, send an email to api-craft+unsubscribe@googlegroups.com.


--
Gruß,
Felipe

Mike Kelly

unread,
Feb 13, 2013, 5:26:25 PM2/13/13
to api-...@googlegroups.com
You can use links to achieve this. i.e. create a URI for each type
and, using a media type like hal+json, link each resource to its
relative type URI.

e.g:

{
_links: { self: { href: "/catalog" },
_embedded: {
products: [
{
_links: {
self: { href: "/products/123" },
type: { href: "/product-types/video" }
},
..... video properties
},
_links: {
self: { href: "/products/123" },
type: { href: "/product-types/clothing" }
},
.... clothing properties
}
]
}
}

You could use type or profile relations for this purpose, or you could
create your own relation if you wanted. You can also provide useful
information at the type URLs too, which would help client developers.

Cheers,
M
>>> email to api-craft+...@googlegroups.com.
>>> Visit this group at http://groups.google.com/group/api-craft?hl=en.
>>> For more options, visit https://groups.google.com/groups/opt_out.
>>>
>>>
>>
>>
>>
>> --
>> Gruß,
>> Felipe
>
> --
> You received this message because you are subscribed to the Google Groups
> "API Craft" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to api-craft+...@googlegroups.com.
> Visit this group at http://groups.google.com/group/api-craft?hl=en.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>



--
Mike

http://twitter.com/mikekelly85
http://github.com/mikekelly
http://linkedin.com/in/mikekelly123

Felipe Sere

unread,
Feb 13, 2013, 5:33:38 PM2/13/13
to api-...@googlegroups.com
 Is your concept of inheritance "strongly typed" like e.g. Java? I mean with that that both "product" and "clothes" share a subset of properties and a "product-interpreter" would not crash if he got a "clothes" representation. 

If so, I'd really leave it up to the client to choose the most fitting representation and maybe provide him with the possibilities as links. Is there any other way for client to know which "Accept" types are valid? The "Vary" header tells the client that the representation changes with the specified header, but it does not tell him which values are valid IIRC. 

erewhon

unread,
Feb 13, 2013, 6:38:53 PM2/13/13
to api-...@googlegroups.com

Interesting -- we're building out a new API that is primarily M2M though we're targeting more than a single type of platform (e.g. iOS vs Android tablet).  Some platforms know how to deal with "video", others do not.

The API is almost RESTful as we haven't fully embraced the hypermedia constraint: I've chosen the application/hal+json media type (thank you for your efforts in this regard :) but I'm not linking everything in our response.  For example, when we return a paged list of results I'll use the "_links" section to specify next/prev pages as well as a template for accessing individual items, but we won't actually link every single result that is returned in the collection.  For example:

{
"links":{
"self": { "href": "/orders" },
"next": { "href": "/orders?page=2" },
"order": { "href": "/orders{?id}", "templated": true }
},
[{...order 1...}, {...order 2...}, ...}]
}

So the actual collection we return is not part of the "_embedded" object as per the specification.  Instead we return the list of orders without any link relations and let the client rely on the template to access a specific order (assuming they have out of band knowledge about the "order" relation).

To be honest I'm not sure if it makes sense to do it this way or if we should just fully adopt HAL and use the embedded resources with linking.  I'm not convinced client applications will benefit significantly from the additional linking effort...

Anyway, back to inheritance ... you mention the use of "type", which is described in the json-hal-05 draft as a means for specifying the "media type" of the "target resource".  Wouldn't I be abusing the "type" parameter by specifying something other than the actual media type of the returned representation?  It seems strange to use a link relation here.

Suppose a client application requests application/json instead of a HAL format (assuming the server supports this) ... the returned JSON will need some new set of semantics for differentiating video and apparel.  My view is that the "_links" section should facilitate the traversal of hypermedia without losing any knowledge about the resource *itself*.

Thoughts?

(thanks for the feedback)

Felipe Sere

unread,
Feb 13, 2013, 5:23:37 PM2/13/13
to api-...@googlegroups.com
Can't you use accept headers? 
To unsubscribe from this group and stop receiving emails from it, send an email to api-craft+...@googlegroups.com.


--
Gruß,
Felipe

Mike Kelly

unread,
Feb 14, 2013, 7:26:45 AM2/14/13
to api-...@googlegroups.com


On 13 Feb 2013 23:38, "erewhon" <keith....@gmail.com> wrote:
>
>
> Interesting -- we're building out a new API that is primarily M2M though we're targeting more than a single type of platform (e.g. iOS vs Android tablet).  Some platforms know how to deal with "video", others do not.
>
> The API is almost RESTful as we haven't fully embraced the hypermedia constraint: I've chosen the application/hal+json media type (thank you for your efforts in this regard :) but I'm not linking everything in our response.  For example, when we return a paged list of results I'll use the "_links" section to specify next/prev pages as well as a template for accessing individual items, but we won't actually link every single result that is returned in the collection.  For example:
>
> {
>
> "links":{
>
> "self": { "href": "/orders" },
> "next": { "href": "/orders?page=2" },
> "order": { "href": "/orders{?id}", "templated": true }
>
> },
>
> [{...order 1...}, {...order 2...}, ...}]
>
> }
>
>
> So the actual collection we return is not part of the "_embedded" object as per the specification.  Instead we return the list of orders without any link relations and let the client rely on the template to access a specific order (assuming they have out of band knowledge about the "order" relation).
>
> To be honest I'm not sure if it makes sense to do it this way or if we should just fully adopt HAL and use the embedded resources with linking.  I'm not convinced client applications will benefit significantly from the additional linking effort...
>

Its really up to you. Fwiw, by breaking with hal conventions your responses will be less suited to consuming with all of the hal client libraries out there

> Anyway, back to inheritance ... you mention the use of "type", which is described in the json-hal-05 draft as a means for specifying the "media type" of the "target resource".  Wouldn't I be abusing the "type" parameter by specifying something other than the actual media type of the returned representation?  It seems strange to use a link relation here.
>

I meant use the type link relation which is different from the type link property.

Hope that makes sense?

Cheers,
M

erewhon

unread,
Feb 14, 2013, 8:35:44 AM2/14/13
to api-...@googlegroups.com


On Thursday, February 14, 2013 7:26:45 AM UTC-5, Mike Kelly wrote:
 

Its really up to you. Fwiw, by breaking with hal conventions your responses will be less suited to consuming with all of the hal client libraries out there

Yeah, there is definitely some risk in the decision.  Depending on how much benefit we think can be gained with hypermedia semantics we'll continue pushing for full adoption.

 

> Anyway, back to inheritance ... you mention the use of "type", which is described in the json-hal-05 draft as a means for specifying the "media type" of the "target resource".  Wouldn't I be abusing the "type" parameter by specifying something other than the actual media type of the returned representation?  It seems strange to use a link relation here.
>

I meant use the type link relation which is different from the type link property.

Hope that makes sense?

Heh, my bad. :)

But I'm still not sure that we'd want to define the type inside of the links section.  Appreciate the suggestion though, it gives me another option!



Mike Schinkel

unread,
Feb 14, 2013, 2:15:30 PM2/14/13
to api-...@googlegroups.com
On Feb 13, 2013, at 3:48 PM, Felipe Sere <felip...@gmail.com> wrote:
The first option has the benefit of being easier to manage on the server side (less changes to support new inheritance) but can get complicated and "noisy" in the serialization (e.g. many serializers treat the emission of a "type" value as an on/off switch so you end up with JSON strings that are littered with type information and usually that type information is mostly useless except for the trailing name of the type, not the fully qualified bits).

The second option addresses the noise in the JSON (though it adds another level of depth to the structure).  To be honest I think emitting type information is the preferred solution ... I've gone down the path of plumbing serializers to clean up what actually gets emitted (e.g. instead of "$type": "com.foo.products.video" we can just emit "$type": "video" and in cases where there is no inheritance do not emit "$type" at all).

I read this with interest. Can you elaborate on this? 

"Many serializers treat the emission of a "type" value as an on/off switch so you end up with JSON strings that are littered with type information and usually that type information is mostly useless except for the trailing name of the type, not the fully qualified bits"

What serializers are you referring to, what happens when they see "type"; do they transform?  And is it if they see type anywhere or just at the top level?  And what exactly do they the serializers think are representing?

-Mike

erewhon

unread,
Feb 16, 2013, 7:13:45 PM2/16/13
to api-...@googlegroups.com
Hi Mike,

What I meant in the below is that you can configure serializers to emit "$type" properties (e.g. the Newtonsoft JSON.NET serializer).  This allows a client to differentiate between two different "types" of products that a client must understand.  The client deserialization process must take the type information into account.  On the server side we customize the serializer to control how that type information is actually emitted, so instead of publishing a fully-qualified name like "Foo.Products.Video, Foo.Models" we just emit "Video".  The fully qualified information is usually unnecessary, so we just emit a "_type" property (e.g. Products: [{_type: "Video", Title: "...", ...}, {...}]).

Usually, our link relations refer to the abstract resource type (e.g. "product" instead of "video").  To me this kind of modelling is very important because it translates to out of band information you have to share with the client.  I want to control/minimize that information.

I suppose inheritance could be modelled as part of the link relation.  But then correct interpretation of the response requires an understanding of your hypermedia (i.e. with HAL understanding the structure of "_links").  I feel like it might be useful to decouple that dependency and be more flexible so that your resource can be understood with or without hypermedia.

To be honest I'm not sure if this makes good sense or if we're thinking about hypermedia/inheritance in the wrong way.

Mike Schinkel

unread,
Feb 16, 2013, 7:26:52 PM2/16/13
to api-...@googlegroups.com
Hi Keith,

Thanks for clarifying.  

So over the weekend I've been re-re-reading (yes, that's not a typo) Roy's Rules of REST[1] and this time I think I managed to grok more than I had in prior reads. However I'm still trying to decipher the exact meaning of "typed resources" and also "irrelevant and invisible to the client") in this context:

A REST API should never have “typed” resources that are significant to the client. Specification authors may use resource types for describing server implementation behind the interface, but those types must be irrelevant and invisible to the client. The only types that are significant to a client are the current representation’s media type and standardized relation names.

But it sounds like what you are doing might be in conflict with that? (And saying "Yes, but it doesn't matter as we don't intend to be doing REST" is an okay answer too.)

-Mike
P.S. Does anyone else really know what Roy meant by that paragraph, ideally with examples to illustrate?

erewhon

unread,
Feb 17, 2013, 8:36:32 AM2/17/13
to api-...@googlegroups.com
Actually thanks for bringing up that quote from Fielding.  It seems relevant.  I've also been troubling over the preceding point from the same article:

A REST API must not define fixed resource names or hierarchies (an obvious coupling of client and server). Servers must have the freedom to control their own namespace.

So if we return a collection of different "types" of products, according to Fielding the way to deal with it is by "standardized relation names".  I'm not sure how I would accomplish that in my case (returning a collection of products that could be of different "types").

If we expose a collection that contains "video" and "clothing" items and we expose a "_type" property as part of the resource itself maybe we should additionally provide information about each of those types in a link relation (like Mike Kelly's suggestion earlier in this thread).

I've been giving that approach serious thought, but concerned about adding unnecessary complexity.  Either we exchange out of band information about the structural differences between video and clothing items or we expose a schema resource (e.g. /types/video).  What would a GET /types/video return?

I suppose if our documentation is simply a description of the resource we could return that documentation in an expected format at /types/video.  But then the client needs to know how to parse our schema definitions and I'm questioning how valuable that really is: when you codify your client application you would bake in knowledge of how to deal with various types of products.  If we added a new product and the client application doesn't change, the best we could hope for is a generic handling of the new product type (that is, the client app might be able to identify that there is a new product in the returned collection and it may be able to further identify some common information such as price, title, description).  What additional value do we bring to clients by exposing a /types/video resource?

Mike Schinkel

unread,
Feb 17, 2013, 4:07:34 PM2/17/13
to api-...@googlegroups.com
Hi Keith,

So this bring up a lot of thoughts I'm still trying to grapple with re:REST.

Let's define some terms so we can make sure we talking about the same thing.

- Server: That device which servers your JSON files and responds to HTTP requests.
- User-Agent: The client software that download and interprets the JSON and takes action on the products it contains.
- User: A human that is somehow ultimately involved in your process (or maybe not?)

So your Server serves your JSON files and they contain reference to "video" and "clothing."  What automated actions do you expect your User-Agent to take on those entities?  Can you give some examples?

Assuming the following as a simple data example, what would your User-Agent need to do differently with each product?  Is there something you need to do with these attributes that differs from SKU, QtyOnHand or QtyOrdered and Price?

{
{ "type":"video", "runtime":"15:00", "format":"mp4", ... },
{ "type":"clothing", "color":"red", "size":"XL", ... }
}

Who is the User in your system?  Is this API to support a shopping cart or some totally automated process such as restocking? 

I guess I'm trying to understand how the User-Agent would use the information Foo.Products.Video and Foo.Products.Clothing? That seems like it is Server-side concern?

-Mike

erewhon

unread,
Feb 17, 2013, 4:50:17 PM2/17/13
to api-...@googlegroups.com

So your Server serves your JSON files and they contain reference to "video" and "clothing."  What automated actions do you expect your User-Agent to take on those entities?  Can you give some examples?

The details of the use cases are going to vary; it might be useful to display video products differently from clothing.  The complexity of this increases when you have more than one target platform (we have at least 5 platforms that provide some continuity but not perfect parity in application features).

Either way, I'm thinking about the more abstract notion of how to deal with this scenario.  If there is a general pattern/practice to addressing the desire to expose a single URL that can serve more than one "type" of resource.

I guess I'm trying to understand how the User-Agent would use the information Foo.Products.Video and Foo.Products.Clothing? That seems like it is Server-side concern?

Oh sorry maybe my earlier post wasn't clear.  I specifically built out serializer customizations to hide the type information and publish names instead.  So yes, it's entirely a server side concern and the user agent shouldn't have any knowledge of this.  But the client application does need to understand how to differentiate between different resources that are closely related.  Basically using properties of the resource as logical input to application behaviour.

What I don't want to do is map each of "video" and "clothing" to their own URLs:

/products/video
/products/clothing

The single address "/products" is more maintainable as our product hierarchy expands and facilitates things like searching.  So I think it becomes necessary to share the "type" of product with the client application.  We could express a collection of different products by introducing a partitioning scheme: "{products: {video: [{...},{...}], clothing: [{...},{...}]}}" but this doesn't really change that the client needs to understand these types if they want to deal with the information and that layout is ugly and less natural than embedding the type information right into the JSON result: "[{_type:"video",...},{_type:"clothing", ...}]".  This JSON layout is far easier to work with in other scenarios such as ordering a list.

So I think where I'm left in all this is:
  • A "_type" in the resource is a good idea, particularly if you need to return representations in non-hypermedia formats.
  • A client application may be able to handle all product types generically but requires out of band knowledge to provide custom behaviours to particular types of products.
  • A "type" relation may be included in the "_links" section of the HAL response (assuming HAL).  The type relation may point to a resource that provides documentation about the types provided by the /products resource.  I'm not sure if this kind of documentation could be used to improve/reduce the out of band knowledge shared with clients.  I'd be curious to hear more thoughts on this if anyone has insight.

Thanks.

K

Mike Schinkel

unread,
Feb 17, 2013, 6:00:53 PM2/17/13
to api-...@googlegroups.com
On Feb 17, 2013, at 4:50 PM, erewhon <keith....@gmail.com> wrote:
The details of the use cases are going to vary; it might be useful to display video products differently from clothing.  
<snip>
But the client application does need to understand how to differentiate between different resources that are closely related.  Basically using properties of the resource as logical input to application behaviour.

For example?  Sorry if I'm pushing so hard for details but it's the details that can validate if a solution can work or not.  Can you give my two hypotheticals for video vs. clothing?

Either way, I'm thinking about the more abstract notion of how to deal with this scenario.  If there is a general pattern/practice to addressing the desire to expose a single URL that can serve more than one "type" of resource.

Based on another read of R3 (Roy's Rules of REST) I'm thinking that to be RESTful your User-Agent has to natively understand what "video" and "clothing" mean OR you need content types that are specific to each of your product types and you either have your User-Agent upgraded to know what those mean and/or you do code-on-demand to provide the intelligence need for clients to process (though I currently think code-on-demand is mostly idealistic vs. practical on the modern web, though more practical today with the rise of Javascript than it was 10+ years ago.)

I think Roy's comment here[1] is probably the most insightful thing I've read from him (insightful for me, emphasis mine):

The media type identifies a specification that defines how a representation is to be processed. That is out-of-band information (all communication is dependent on some prior knowledge). What you are missing is that each representation contains the specific instructions for interfacing with a given service, provided in-band. The media type is a generic processing model that every agent can learn if there aren’t too many of them (hence the need for standards). The representation is specific to the application being performed by the agent. Each representation therefore provides the transitions that are available at that point in the application.

So for media type you might instead use:

List: application/vnd.erewhon.product
Video: application/vnd.erewhon.product 
Clothing: application/vnd.erewhon.product 

OR you might use:

List: application/hal+json
Video: application/vnd.erewhon.video
Clothing: application/vnd.erewhon.clothing

What I don't want to do is map each of "video" and "clothing" to their own URLs:

/products/video
/products/clothing

The single address "/products" is more maintainable as our product hierarchy expands and facilitates things like searching.  So I think it becomes necessary to share the "type" of product with the client application.  We could express a collection of different products by introducing a partitioning scheme: "{products: {video: [{...},{...}], clothing: [{...},{...}]}}" but this doesn't really change that the client needs to understand these types if they want to deal with the information and that layout is ugly and less natural than embedding the type information right into the JSON result: "[{_type:"video",...},{_type:"clothing", ...}]".  This JSON layout is far easier to work with in other scenarios such as ordering a list.

Okay, so based on this your preference is: 

application/vnd.erewhon.product

And not:

application/hal+json

This tells me that if you put "video" or "clothing" into a "generic media type" you are doing it wrong according to R3.  To wit[2] (emphasis mine):

In terms of testing a specification, the hardest part is identifying when a RESTful protocol is actually dependent on out-of-band information or if the authors are just overspecifying things for the purpose of documentation. What I look for are requirements on processing behavior that are defined outside of the media type specification. One of the easiest ways to see that is when a protocol calls for the use of a generic media type (like application/xml or application/json) and then requires that it be processed in a way that is special to the protocol/API. If they are keying off of something unique within the content (like an XML namespace declaration that extends the semantics of a generic type), then it’s okay. Usually, however, what they do is assume that the response has a specific structure beyond that defined by the media type. When the structure changes, the client will break.

So I think in your use-case the media type "application/hal+json" would be considered a generic media type because HAL doesn't understand "video" or "clothing." Your media type could be *based* on HAL if you wanted it to be, but to be RESTful I still think it needs to be it's own media type with it's own "Content-Type" string.  Consider Roy's comment[3]:

Every media type defines a default processing model. For example, HTML defines a rendering process for hypertext and the browser behavior around each element. 


So I think where I'm left in all this is:
  • A "_type" in the resource is a good idea, particularly if you need to return representations in non-hypermedia formats.
  • A client application may be able to handle all product types generically but requires out of band knowledge to provide custom behaviours to particular types of products.
  • A "type" relation may be included in the "_links" section of the HAL response (assuming HAL).  The type relation may point to a resource that provides documentation about the types provided by the /products resource.  I'm not sure if this kind of documentation could be used to improve/reduce the out of band knowledge shared with clients.  I'd be curious to hear more thoughts on this if anyone has insight.

Hmm. Consider the following; rather than define "types" for "video" and "clothing" what if you instead define "traits" that are "known" aspects of your media type and that your clients are able to understand. For example:

- Overview Video; for a video that's a trailer, for a clothing item it might be a video so a model wearing the clothes.
- Images; For a video they might be screencaps, actor headshots, etc. For clothing "Front View", "Read View", "L/R Side Views", etc. So images would have a generic value "imageType" that the would allow the agent to show the User what types of images are available and to show the images by image type.
- Color & Size: Applicable for clothing but probably not for video.
- And so on.

Now you one generic media type that simply describes the traits of your products and then your client apps can know what to do with those traits.  If it has an Overview Video then your client can offer to let them view it.  If it has multiple Colors then the client can allow the user to select a color and possible view an image of the product in that color.

I think one of the ways you'd discover traits is to think about what you want your clients to do with the product information, and then tease the traits out of that insight.  If you want to be able to view a product using a 3D 360 degree viewer then the data and images you need to enable that viewer becomes part of your set of product traits. 

Traits as fundamental, unchanging aspects of your products; "types" are really a somewhat arbitrary grouping that we humans use to divide and conquer too much information to grok at one time. This insight is coming from someone who built and grew an early e-commerce retailer that made it into the Inc 500 where much of what I spent my time on in the early days was product categorization.  I learned that categorization changes based on the perspective of the observer and you can never get categorization fully correct. On the other hand, traits are fundamental and do not change (or at least should not.  I wish I had had this insight in 1994.)

In addition to the above you can also include the string of "video" or "clothing" as a 'category' attribute of a project but those become just labels and not processing instructions.  Adding new "types" really just means describing in meta-data on your Server what traits those new types have and then serving the information about those traits. If you discover the need for new traits you evolve your media type in a backward compatible way.

Does that analysis change what you are thinking about tackling this problem?

-Mike

erewhon

unread,
Feb 17, 2013, 7:10:32 PM2/17/13
to api-...@googlegroups.com
Thanks for your feedback Mike.
 
For example?  Sorry if I'm pushing so hard for details but it's the details that can validate if a solution can work or not.  Can you give my two hypotheticals for video vs. clothing?

To be honest it's a contrived scenario but it could be as simple as "for clothing the client application uses layout 'X' and for video the client uses layout 'Y'", where X and Y are two different user interface constructions.  There are probably other behavioural differences as well that are yet unclear to me in my real use case at work.  Sorry, maybe my examples suck. :\

 Okay, so based on this your preference is: 
application/vnd.erewhon.product 
 
And not:
application/hal+json

No, I'm using application/hal+json.  The JSON examples I provided were just snippets to show how one might represent a list of products that are differentiated.  The choice of differentiating our products into distinct groups is a key aspect of our business that we have modelled right through our system.  It's definitely not arbitrary and it's important that clients *know* about this differentiation.

rather than define "types" for "video" and "clothing" what if you instead define "traits" that are "known" aspects of your media type and that your clients are able to understand.

That's exactly what the "_type" property is allowing me to do.  You call it a "trait" but the key here is conveying this information as part of the resource.  Whether I call it "_type", "ProductType", "Category", etc ... it's a means for publishing a model that can be differentiated.

Suppose, for example, that you're an online music company and your product searches can turn up both vinyl record results along with entire compilations (like a multi-CD collection).  I can imagine such a company might want to present the multi-CD collection in a different way, possibly highlighting the collection name and a specialized layout for options relating to how the user can access the digital content (if any).

The client application needs to understand the "type" of the product because it's a key aspect to the application logic of the client.  It's also core to the business.  You might imagine that a client application simply searches for a property that exists only for collections (e.g. "CollectionName").  But why let the client make up its own rules when we can inject something reliable into the resource that allows the client to make an unambiguous and predictable choice about its handling?

Different client apps can choose to use different rules, but facilitating the identification of these resources seems like an important design decision.

"types" are really a somewhat arbitrary grouping that we humans use to divide and conquer too much information to grok at one time

Oh I don't know, typing is a pretty useful and necessary exercise if you're going to make sense of your domain...! ;)

But if it helps, change "_type" to "Category".  We still have the same problem of modelling differentiated resources: how do we provide enough information to the client so that they can use the result effectively?

There might be a corollary here: should inherited models be their own resource?  (so /products/clothing, /products/videos rather than everything under /products).  This still leaves you with the requirement that your link relations will need to differentiate clothing and videos, but I'm not sure this has actually achieved anything.  Your response to a search under /products will still return a collection of embedded resources (assuming HAL) that distinguish between the types.  My suggestion is simply that we promote the inheritance into the resource directly.

I'm *still* thinking about Mike Kelly's suggestion though.

K

Mike Schinkel

unread,
Feb 17, 2013, 10:00:16 PM2/17/13
to api-...@googlegroups.com
On Feb 17, 2013, at 7:10 PM, erewhon <keith....@gmail.com> wrote:
To be honest it's a contrived scenario but it could be as simple as "for clothing the client application uses layout 'X' and for video the client uses layout 'Y'", where X and Y are two different user interface constructions.  There are probably other behavioural differences as well that are yet unclear to me in my real use case at work.  Sorry, maybe my examples suck. :\

Who will be building the client applications?  Your company and/or potentially anybody?

 Okay, so based on this your preference is: 
application/vnd.erewhon.product 
 
And not:
application/hal+json

No, I'm using application/hal+json.  

Sorry, I think I mis-explained. What I was saying was I think that if RESTfulness is important then according to my reading of R3 you really should be using a custom media type and not a generic one like HAL. IOW you may be using HAL but I'm now questioning if that's really the best solution for your use-case.

The JSON examples I provided were just snippets to show how one might represent a list of products that are differentiated.  The choice of differentiating our products into distinct groups is a key aspect of our business that we have modelled right through our system.  It's definitely not arbitrary and it's important that clients *know* about this differentiation.

If the product groups are indeed not arbitrary then is sounds like you should be defining a new media type for each of your product groups and that your use of HAL should only be used to capture the common elements.

BTW, I think you misunderstood my use of the term "arbitrary."  I meant it in the grand scheme, not specific.  I might have a category called SUV for my vehicle but over time new subcategories emerge and new cross-over categories emerge that muddy the initial categorization.  

We used to buy "records" on vinyl but today with iTunes single song purchases the concept of a "record" is arbitrary. IOW, I was not saying that your categories are arbitrary as I'm sure your categorization was based on external factors but that instead basic nature of human categorization is arbitrary and it morphs and evolves over time. I was comparing that with traits like number of wheels or time length of recording; these are much less likely to morph over time.


rather than define "types" for "video" and "clothing" what if you instead define "traits" that are "known" aspects of your media type and that your clients are able to understand.

That's exactly what the "_type" property is allowing me to do.  You call it a "trait" but the key here is conveying this information as part of the resource.  Whether I call it "_type", "ProductType", "Category", etc ... it's a means for publishing a model that can be differentiated.

Hmm. Maybe it's me misunderstanding but as I read that I think that I must not have really explained what I meant by a trait.  A trait is something like "color", not "clothing."

Suppose, for example, that you're an online music company and your product searches can turn up both vinyl record results along with entire compilations (like a multi-CD collection).  I can imagine such a company might want to present the multi-CD collection in a different way, possibly highlighting the collection name and a specialized layout for options relating to how the user can access the digital content (if any).

For that I would say you have a trait of a "collection" which can be comprised of dependent products (things you can only get in the compilation) and independent products (things that can be sold separately.)

Also I would see other traits and being physical products with things like medium (vinyl vs. cd), size, weight, qty in stock, and digital with a filesize.

And of course I would see traits for labels where you can describe then as "Multi-CD compilations" and possibly even meta-data on the server end where you can say what traits that a grouping might have.

The client application needs to understand the "type" of the product because it's a key aspect to the application logic of the client.  It's also core to the business.  You might imagine that a client application simply searches for a property that exists only for collections (e.g. "CollectionName").  But why let the client make up its own rules when we can inject something reliable into the resource that allows the client to make an unambiguous and predictable choice about its handling?

The reason not to is to avoid coupling to existing ideas about types that may change over time. 

Different client apps can choose to use different rules, but facilitating the identification of these resources seems like an important design decision.

"types" are really a somewhat arbitrary grouping that we humans use to divide and conquer too much information to grok at one time

Oh I don't know, typing is a pretty useful and necessary exercise if you're going to make sense of your domain...! ;)

Yes, types are very helpful for us humans to grok things but it's an unreliable basis for which to architect software. Categories evolve which means that the software is structured around categories has to evolve or it's not longer useful.  And since you are architecting a distributed solution I think it would be especially important that you formats be as reliable over time as reasonably possible.

But if it helps, change "_type" to "Category".  We still have the same problem of modelling differentiated resources: how do we provide enough information to the client so that they can use the result effectively?

I come back to "traits" identified in your media type as being the solution.  Your clients can operate against these media-type specific traits, and if you've identified your traits in a manner that they don't change over time (although I think you could add to them in a manner that old clients could ignore) then you'll have a more resilient API.

There might be a corollary here: should inherited models be their own resource?  (so /products/clothing, /products/videos rather than everything under /products).  

I think asking about inheritance is serendipitous because in OOP the "fragile base class" problem and the need for but problems with multiple inheritance are two of the reasons so many have realized OOP is not a panacea. It's really hard to model classes such that they don't need to change and I think that's what you are trying to do with your types/categories.

Two things I've noticed recently that are evolving to address the issues in OOP are Structural Typing[1] which I learned about because of TypeScript [2] and Traits in PHP[3] which is where I stole the name I used above. The idea of both are to identify the independent aspects of an object and allow them to be mixed & matched as opposed to creating a single rigid named class.  I think that collective learning can apply to your use-case too.

This still leaves you with the requirement that your link relations will need to differentiate clothing and videos, but I'm not sure this has actually achieved anything.  Your response to a search under /products will still return a collection of embedded resources (assuming HAL) that distinguish between the types.  My suggestion is simply that we promote the inheritance into the resource directly.

My current understanding based on my reading of R3 is that you can do one of those things IF you want to still be RESTful:

1.) A single media type that understands all potential product types; i.e. 'video' and 'clothing'.  This by definition cannot be application/hal+json but would instead need to be something like application/vnd.erewhon.products. The obvious downside is that you have to evolve this and evolve your clients over time to know more and more about your product types.

2.) Use application/hal+json for your list and then use a potentially unlimited set of other media types like application/vnd.erewhon.video and application/vnd.erewhon.clothing to represent your different product types. In your HAL document you would *not* include any reference to your media type other than "rel='type'" and not have any type-specific behavior because doing so would not be RESTful. Instead you would include URLs to the products which when requested would return media types that represent the product type. This also has the issue that you have to update your clients as time evolves but you could potentially do it in a module or even code-on-demand fashion where each module aligns to a media type and clients that don't have the required module to recognize a media type simply treat it as a generic product. 

3.) Use another form of application/vnd.erewhon.products that uses traits instead of types. Client behavior could change based on the traits (i.e. is there an Overview video?  Does it have multiple colors?  etc.) and if you add new traits the media type would need to be revised but clients could be instructed to ignore what they don't understand.  In this case your "types" would be used to label attributes and/or collections but it would be the traits that would drive behavior, not types.

IMO the best solution is #3 as I can see it being the most resilient to change and evolution over time but again, if RESTful is not important these concerns are less important; it all depends how much you value the attributes a RESTful system provides.

-Mike
P.S. FYI, I'm engaging with you on this in part to be helpful but also because its helping me come to a better understanding regarding how REST applies in real world scenarios and hopefully I will be able to leverage that learning with[4].

[4] https://github.com/wai2/wai2

erewhon

unread,
Feb 18, 2013, 1:55:40 PM2/18/13
to api-...@googlegroups.com
Thanks for all your thoughts.

I still think my problem is solved if I embed information about what *kind* of product it is.  You can call it a trait but it's effectively the same thing: a property of the Product representation that allow clients to make particular decisions about the representation's handling.  My only requirement is to model differentiated products as collections.

A search result needs to provide enough detail about the product so that the client doesn't have to go back to the server for details.  The primary interaction for us is M2M where device power consumption is a concern (and we are possibly expanding to H2M).  I think that HAL offers a solution in the form of its "_embedded" concept, but we do need a way to differentiate the collection of items returned in the _embedded section.

The reason not to is to avoid coupling to existing ideas about types that may change over time. 

A music store differentiates album and artist because the business has decided that they are different concepts.  Likewise some products in our business are conceptually distinct: video content will never be confused with clothing, but they are importantly all "products you can pay for".  As such, modelling these products in a generic way is important for functionality like product searches, shopping carts, order lists, etc.

We want to return the entire representation of products in many of our responses, so we need a way to tell the client how to differentiate.  I can see a few ways it can be done, both with and without specifying a "type" property in the response.  Perhaps "type" is an unfortunate choice of name.  And if we simply didn't tell a client about the "types" we would still need to tell them about the various *representations* they can expect.  Otherwise how do they encode their application with the right knowledge to deal with the known product formats?

This kind of modelling exercise usually lands people in one of a few categories that are laid out pretty nicely in Mike Amundsen's "Building Hypermedia APIs with HTML5 and Node".  My approach would probably be characterized as a "domain-general" design ... here's a brief entry from the book:

/* domain-general design */

{  "order":
{
"id" : "...",
"address" : { "type" : "shipping", "street-address" : "..."},
"address" : {"type" : "billing",  "street-address" : "..."}
}
}
You can see that the domain-specific address elements from the first example have been replaced by general “address” elements carry a “type” indicator to provide additional domain-specific information.  The advantage of this design style is that the “address” elements could be applied to many other use cases within the problem domain (customer address, user address, supplier address, etc.) without having to modify the actual message design itself. In this way, your design takes on a level of modularity and reuse that makes supporting new domain-specific elements easier over time. In addition, client applications can create code that: 1) supports reusing these modular elements of your message design, and 2) is able to adjust to evolving use cases in the domain space more easily.

Somewhat equivalently our resource modelling relies on a common "product" concept (necessary for various business interactions) but relies on a type property to specialize.  I'm pretty sure such a design is still aligned with REST/Hypermedia principles.  The client can choose to interact generically with a "product" or handle the specific cases if they support it.  We now have the freedom to expand on our product types without breaking existing clients and the "type" concept introduces a general semantic for dealing with specializations.  Problem solved, no?

How would you accomplish this?

K

Mike Schinkel

unread,
Feb 18, 2013, 9:09:32 PM2/18/13
to api-...@googlegroups.com
Hi Keith,

Thanks for the dialog.  Even though it's your use-case I'm learning a lot being able to discuss it.

I think we are converging to a similar understanding.  I believe the issue here is "Pure REST" and "Pragmatic REST" although I'm sure Roy would argue that there is no such thing as the latter.  To me the latter emerges when the real-world implementation concerns conflict with Pure REST.  I was actually in the process of learning if you really can have Pure REST in the real world, beyond trivial use-cases of course.

Looking at Pure REST my *current* understanding is that the only type information should be the media type specified in the Content-Type header except that "rel" attributes can indicate type ASSUMING that the client understand that those "rel" types are associated with the media type and the client understands them.  That's why I was saying I using a generic type like HAL might not be Pure REST (but I could still be misreading R3.) 

But pragmatically using HAL and having your client understand the types in your representations might be just fine; it's certainly "more" RESTful (*cough* *cough*, sorry Roy) than most APIs that use "applications/json" and that do not provide links.

This kind of modelling exercise usually lands people in one of a few categories that are laid out pretty nicely in Mike Amundsen's "Building Hypermedia APIs with HTML5 and Node".

I've been eyeballing that book but haven't pulled the trigger yet because I've got so many other books in my "to read soon" pile. I think you've just convinced me to part with $15 and read it sooner than the others. :)

My approach would probably be characterized as a "domain-general" design ... here's a brief entry from the book:

/* domain-general design */

{  "order":
{
"id" : "...",
"address" : { "type" : "shipping", "street-address" : "..."},
"address" : {"type" : "billing",  "street-address" : "..."}
}
}

Did Mike's book really have that example, or did you para-type and misquote as that's not valid JSON? Did Mike maybe present the example in XML where the same layout would be valid?  You can however turn the "address" property into an array but the sad part of that is it complicates your structure in cases where the is often just one:

{  "order":
{
"id" : "...",
"address" : [
{ "type" : "shipping", "street-address" : "..."},
{"type" : "billing",  "street-address" : "..."}
]
}
}

You could also do it this way with property names if you like but then your user agent needs to understand which properties are a collection of the same:

{  "order":
{
"id" : "...",
"shippingAddress" : { "type" : "shipping", "street-address" : "..."},
"billingAddress" : { "type" : "billing", "street-address" : "..."}
}
}

I think one of the things that we as a community collectively need to do[1] is start to create standard media types for well-known use-cases that can be used across APIs and across individual projects, and they could be based on HAL or Siren or Cj or just be standalone JSON. People could always extend them in non-RESTful ways but at least we'd have interoperability at the 80% level and we wouldn't each have to reinvent so much. 

And I'm thinking that Roy would support this idea as RESTful, a least I believe that's what this quote[2] means (emphasis mine):

The media type is a generic processing model that every agent can learn if there aren’t too many of them (hence the need for standards). The representation is specific to the application being performed by the agent. 


Felipe Sere

unread,
Feb 19, 2013, 1:20:24 AM2/19/13
to api-...@googlegroups.com
Hi Mike, Keith,

I am convinced you can use HAL because you are misunderstanding Roy. 

Looking at Pure REST my *current* understanding is that the only type information should be the media type specified in the Content-Type header except that "rel" attributes can indicate type ASSUMING that the client understand that those "rel" types are associated with the media type and the client understands them.  That's why I was saying I using a generic type like HAL might not be Pure REST (but I could still be misreading R3.) 
 
This is where I think you are wrong. 
You can use HAL as the base format, meaning that you take HAL, and define which properties (or key/value pairs) are LEGAL within 
Your specific media-type. You would create a application/vnd.products.video+Hal. 

This way the processing rules (links etc) are described in the base format and you only have to describe the specifics of YOUR media-type (e.g. a "type" property MUST be present and what it means). 
Any HAL client can understand and interact with your API, but only clients that understand your media-type will be efficient at it. 

This is what I believe Roy means with standards for processing rules and what you called "prgmatic" or "standing onnthenshulders of giants" in another thread. 

On the "type" or inheritance topic:
Can't you provide the same logical resource with multiple representation? (media-types)
If the client is just peocessing "products", he can just set "Accept: application/vnd.prodduct+HAL" and whatever he is requesting will be returned "as a product" or be a 406 if its not a product. That is the whole point of "content negotiation". 

Cheers!
Felipe

--
You received this message because you are subscribed to the Google Groups "API Craft" group.
To unsubscribe from this group and stop receiving emails from it, send an email to api-craft+...@googlegroups.com.
Visit this group at http://groups.google.com/group/api-craft?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 


--
Gruß,
Felipe

Mike Schinkel

unread,
Feb 19, 2013, 2:32:43 AM2/19/13
to api-...@googlegroups.com
Hi Felipe,

Thanks for the comments.   

On Feb 19, 2013, at 1:20 AM, Felipe Sere <felip...@gmail.com> wrote:
I am convinced you can use HAL because you are misunderstanding Roy. 

Looking at Pure REST my *current* understanding is that the only type information should be the media type specified in the Content-Type header except that "rel" attributes can indicate type ASSUMING that the client understand that those "rel" types are associated with the media type and the client understands them.  That's why I was saying I using a generic type like HAL might not be Pure REST (but I could still be misreading R3.) 
 
This is where I think you are wrong. 

Nope.  Read below.

You can use HAL as the base format, meaning that you take HAL, and define which properties (or key/value pairs) are LEGAL within 
Your specific media-type. You would create a application/vnd.products.video+Hal. 

Seems you either misread what I wrote or you didn't read all of what I wrote (which is okay, I wrote a lot!) What you propose is effectively exactly what I said, I just didn't provide an explicit media type example:

On Feb 18, 2013, at 9:09 PM, Mike Schinkel <mi...@newclarity.net> wrote:
I think one of the things that we as a community collectively need to do[1] is start to create standard media types for well-known use-cases that can be used across APIs and across individual projects, and they could be based on HAL or Siren or Cj or just be standalone JSON.

On Feb 17, 2013, at 6:00 PM, Mike Schinkel <mi...@newclarity.net> wrote:
So I think in your use-case the media type "application/hal+json" would be considered a generic media type because HAL doesn't understand "video" or "clothing." Your media type could be *based* on HAL if you wanted it to be, but to be RESTful I still think it needs to be it's own media type with it's own "Content-Type" string.  

In my original emails I didn't emphasize those points like I did here; maybe that's why you missed them?

So looks like we agree. :)

-Mike


Felipe Sere

unread,
Feb 19, 2013, 3:56:19 AM2/19/13
to api-...@googlegroups.com
Oh now I see! I did read the entire mail but I guess the main points were spread a bit. 
So yes, we agree :-D
--
You received this message because you are subscribed to the Google Groups "API Craft" group.
To unsubscribe from this group and stop receiving emails from it, send an email to api-craft+...@googlegroups.com.
Visit this group at http://groups.google.com/group/api-craft?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 


--
Gruß,
Felipe

erewhon

unread,
Feb 19, 2013, 10:40:29 AM2/19/13
to api-...@googlegroups.com

On Tuesday, February 19, 2013 1:20:24 AM UTC-5, Felipe S. wrote:

On the "type" or inheritance topic:
Can't you provide the same logical resource with multiple representation? (media-types)
If the client is just peocessing "products", he can just set "Accept: application/vnd.prodduct+HAL" and whatever he is requesting will be returned "as a product" or be a 406 if its not a product. That is the whole point of "content negotiation". 



So if I need to return both a video and a clothing item, how would that be done with the given accept header?  And how does using such a specific media type help?  My understanding from what I've read on the subject is that the media type should dictate the processing model which includes hypermedia controls and methods that can be applied to resources.  I don't believe that the media type should provide instructions or hints as to the structural nature of the resource representation.  This seems like a reasonable boundary because the alternative is a media type explosion that no longer becomes scalable in the way Roy Fielding originally suggests in his paper.


Kevin Swiber

unread,
Feb 19, 2013, 11:20:38 AM2/19/13
to api-...@googlegroups.com
I'm not sure where to weigh-in on this thread, so I'll do the frowned-upon top-posting at a random point.  :)  Hopefully, this contributes something useful.

We analyze these blog blurbs to a point of near-insanity.  (I'm guilty, too. ;)

So, first off… regarding this Fielding quote…

"A REST API should never have “typed” resources that are significant to the client. Specification authors may use resource types for describing server implementation behind the interface, but those types must be irrelevant and invisible to the client. The only types that are significant to a client are the current representation’s media type and standardized relation names."

What does "typed" really mean in this context?  As an API consumer, if I have no idea what fields exist, how do I actually write code to consume a message?

Let's look at all the pieces.

Media Type: The media type defines the structure of a message and sometimes protocol semantics (though this could be left to a separate specification).
Link Relations: These define the application semantics.  Within a link relation's documentation, we can certainly find field names and even "type" information.

The key point here is that it is either the media type or the link relation defining this, not the resource.

_Elements may have different traits, even within a single link relation._

We have solved this problem in HTML.  We use the "class" attribute liberally.  This exact problem is why Siren has a "class" attribute, as well[1].  In HTML, you might have a class value of "order high-priority first."  We use this for a number of reasons: a significant one being it makes the markup easy to consume with JavaScript.  Similarly, we can use this in the API world to help clients process messages.  We can define the class semantics in the link relation documentation and consume responses appropriately at the client level.

_This is still RESTful._  Don't worry.  I think we can still keep our badges.

On to my next point…

There is no pure vs. pragmatic; there is only REST.  REST is only a base architectural style.  Adding additional constraints to it is a-okay.  Not using it at all is a-okay.  We should absolutely understand the REST constraints, because they are significant to this particular style, but it's a big world out there, and we're only getting started..  The best is yet to come in the API space, whether or not is has a foundation in Representational State Transfer.  Again, this is where open, free, generally agreed-upon guidance regarding REST would be helpful to the community.  Consensus is not easy, but achieving it might remove a giant roadblock to progress.  I'd be happy to see that.  :)


Cheers,

-- 
Kevin Swiber
@kevinswiber

On Feb 18, 2013, at 9:09 PM, Mike Schinkel <mi...@newclarity.net> wrote:

Felipe Sere

unread,
Feb 19, 2013, 4:39:29 PM2/19/13
to api-...@googlegroups.com
Hmm… I guess a type/trait/class identifying what something is within a collection is one way of telling the client which "processing rules apply".
Then again, from a use-case standpoint I would try to model the problem in such a way that I don't have "mixed" collections.
It might be pragmatic, but I'd behave like a strong typed language. Java has List<Videos>, which tells me that all elements in there behave like a Video. Now, if I do List<Product> and Video extends Product, I can still stick the same video in there, but I will only see Product behaviour.
Looking at elements within a collection individually  and doing different things based on the type "feels" like doing List<Object> and typecasting… or a long if( … instance of …) else if … And that is a code-smell (may I coin the phrase "API-smell" when the API does something unexpected/wierd or forces me as a client to do something unexpected/weird…?)

At work we only use the media type to convey the "type" and yes it leads to an explosion of media-types.
But all media-types behave the same. We have rules for "links {…}" and don't mix elements in collections etc.

erewhon

unread,
Feb 19, 2013, 9:04:13 PM2/19/13
to api-...@googlegroups.com
I'm not sure where to weigh-in on this thread, so I'll do the frowned-upon top-posting at a random point.  :)  Hopefully, this contributes something useful.

The more the merrier. :)  Particularly in such a nascent community.


The key point here is that it is either the media type or the link relation defining this, not the resource.

Sorry I think I missed something here: why can't we define a "type" in the resource?  Let me add a further restriction: what happens when you have an API that needs to be consumed in two ways: the first by clients that understand hal+json and the other group that only understands json?

I think we can model the response to a product search request in one of three distinct ways...

(1) as Mike Kelly suggested:

  "_embedded": {
    "product": [
      {
        "_links": {
          "self": {
            "href": "/products/1001"
          },
          "type": {
            "href": "/types/products/video"
          }
        },
        "Description": "Video Item",
        "Price": 9.99,
        "Thumbnail": "/products/thumbnails/1001.jpg"
      },
      {
        "_links": {
          "self": {
            "href": "/products/1001"
          },
          "type": {
            "href": "/types/products/clothing"
          }
        },
        "Description": "Clothing Item",
        "Price": 45.00,
        "Thumbnail": "/products/thumbnails/1002.jpg"
      }
    ]
  }

(2) breaking the embedded resources into specific relation names:

  "_embedded": {
    "video": [
      {
        "_links": {
          "self": {
            "href": "/products/1001",
          }
        },
        "Description": "Video Item",
        "Price": 9.99,
        "Thumbnail": "/products/thumbnails/1001.jpg"
      }],
    "clothing": [
      {
        "_links": {
          "self": {
            "href": "/products/1002",
          }
        },
        "Description": "Clothing Item",
        "Price": 45.00,
        "Thumbnail": "/products/thumbnails/1002.jpg"
      }
    ]
  }

(3) or finally, specifying a "type" in the resource itself (I'm going to call it "ProductClass" just for fun):

  "_embedded": {
    "product": [
      {
        "_links": {
          "self": {
            "href": "/products/1001",
          }
        },
        "ProductClass": "video",
        "Description": "Video Item",
        "Price": 9.99,
        "Thumbnail": "/products/thumbnails/1001.jpg"
      },
      {
        "_links": {
          "self": {
            "href": "/products/1002",
          }
        },
        "ProductClass": "clothing",
        "Description": "Clothing Item",
        "Price": 45.00,
        "Thumbnail": "/products/thumbnails/1002.jpg"
      }
    ]
  }

So...

  • Option (1) and (2) become problematic if our target consumers only know how to consume application/json media types.  We would need additional server-side logic to move the type information into the resource itself.
  • Option (3) provides no differentiation at the link relation level, requiring clients to know how to differentially treat each "type" of product.
  • Option (1) has the potential to be more self-describing (the type link relation may facilitate discovery).
  • Option (2) is dangerous if we want clients to handle all products in a generic way and specialize when they have implementations for a specific type.
I could implement the search to return a generic type of product and then force the client to issue GET requests for additional details (which we could provide in link relations for "video", etc).  The problem here is that this becomes pretty chatty and forcing this on some of our power-conscious clients seems like a bad idea.

The way I'm thinking about this is that the "type" is not really a type in the object definition sense, but a structural property of the resource itself.  Usually client applications implement logic based on properties of your resources (e.g. if value is this then display in red, otherwise blue).  Why can't we do the same for a "type"?  (e.g. if type is video then display download link and render in this view model, else if type is clothing then display sizing chart and render in other view model).

I've toyed with other ideas to get around all of this.  One that only recently occurred to me is something like this (option (4)):

  "_embedded": {
    "product": [
      {
        "_links": {
          "self": {
            "href": "/products/1001",
          }
        },
        "Description": "Video Item",
        "Price": 9.99,
        "Thumbnail": "/products/thumbnails/1001.jpg"
        "Video": { ...[video-specific content]... }
      },
      {
        "_links": {
          "self": {
            "href": "/products/1002",
          }
        },
        "Description": "Clothing Item",
        "Price": 45.00,
        "Thumbnail": "/products/thumbnails/1002.jpg",
        "Clothing": { ...[clothing-specific content]... }
      }
    ]
  }

In this case, we still require the client to search for a "type", but this time we just encapsulate the details of the properties inside a nested property of the resource (e.g. "Video" or "Clothing").  This only seems to add complexity to the JSON (and to our serialization/aggregation models on the server) and doesn't reduce the amount of out of band information we have to share with clients.

Maybe I'm thinking about this the wrong way.  Feedback is always appreciated. :)

K
Reply all
Reply to author
Forward
0 new messages