How to add an embedded sub resource array

523 views
Skip to first unread message

Derek Gebhard

unread,
Jul 30, 2013, 4:24:28 PM7/30/13
to halbuil...@googlegroups.com
I noticed when I add multiple representations in a loop using halRepresentation.withRepresentation("subResourceArrayName", representation) it automatically creates an embedded sub resource array.  

However I am hitting a few issues:
1) How do I specify an empty array for "subResourceArrayName" if I have nothing to return?  It looks like withRepresentation does not take an Array or List?
2) How do I specify a single item for "subResourceArrayName" with it still being returned as an array? It seems like if only 1 item is specified it uses an object.


Mark Derricutt

unread,
Jul 30, 2013, 6:33:48 PM7/30/13
to halbuil...@googlegroups.com
The current behaviour is:

 - if there is only 1 link, or embedded representation for a given rel, then it is rendered as an object
 - if there is more than 1 link, or embedded representation for a given rel, then it is rendered as an array

This is per spec. The spec however is grey on whether or not a single element should ALWAYS just be an object, or a single element list.

As for 1) - if there's no links/representations against a rel, then it's simply not included. I could see a minor reason to include the empty array, but IMHO if theres nothing there - don't even include it.  You're right tho, withRepresentation doesn't take an array, or a list - as that's to add a SINGLE representation.

2) You can't - without changing/subclassing the JsonRepresentationWriter and injecting that into your RepresentationFactory. Someone else was asking for something similar the other day, so I'll think on it and push out a change maybe later this week which adds a configuration flag for that.

Mark




--
You received this message because you are subscribed to the Google Groups "HALBuilder Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to halbuilder-de...@googlegroups.com.
To post to this group, send email to halbuil...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/halbuilder-dev/9ec7e1dc-207d-4c42-9203-5eab80f9a375%40googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Derek Gebhard

unread,
Jul 30, 2013, 8:26:36 PM7/30/13
to halbuil...@googlegroups.com
I think there is a common scenario here that HAL doesn't support very well.  It is the case where you are dynamically returning a list of resources in the HAL+JSON response and the list can be of varying length (0 to N).  A common case for this is search or listing sub resources.

From a developer experience perspective for the client consuming the HAL service, it seems pretty poor that you have to account for a number of different cases when parsing the HAL+JSON even though you are expecting search results or a collection of sub resources:

1) You need to check if the embedded resource exist.  If not, then you can assume there are no results.
2) You need to check if the embedded resource is of type Object.  Then there is 1 result or sub object.
3) You need to check if the embedded resource is of type Array.  Then there is multiple results or sub objects.

Instead it would be great to just have one success code path that assumes Array and be able to document the Service API as such.

I will look into extending JsonRepresentationWriter and injecting that into my RepresntationFactory.

PS: Thanks for all the great work on this project. It is greatly appreciated and I am a big fan!

Mark Derricutt

unread,
Jul 30, 2013, 8:54:27 PM7/30/13
to halbuil...@googlegroups.com
On 31/07/2013, at 12:26 PM, Derek Gebhard <derek...@gmail.com> wrote:

I think there is a common scenario here that HAL doesn't support very well.  It is the case where you are dynamically returning a list of resources in the HAL+JSON response and the list can be of varying length (0 to N).  A common case for this is search or listing sub resources.

I can definitely see it from a client perspective, and is one of the things that irked me about the JSON variant, the XML one doesn't suffer this as everything is a child element.

Altho, on the flip side I see this also manifesting as a problem mostly for Javascript client authors, who simply eval/read the JSON representation in an object and use that directly, rather than - deserialize it into a useful object model. Using the raw JSON view seems fraught with issues, unless you take a more functional aspect to it and say have a function ( pseudo code ):

forEachEmbeddedRepresentation(representation, rel, callback) { … }

your call back function/lambda would only be called for any found embed, you the forEach… function checks for its existence and it contained in a single spot.

From a developer experience perspective for the client consuming the HAL service, it seems pretty poor that you have to account for a number of different cases when parsing the HAL+JSON even though you are expecting search results or a collection of sub resources:

From the HalBuilder client side, again - I have functions on the ReadableRepresentation which return the list, or empty list for you. I see these things also already being handled by various JS client HAL libraries, rather than having you recreate it all the time.

That being said, it'd be VERY easy for me to add a Flag for "PREFER-ARRAYS" or something, much like how the last change for stripping nulls was added.

Steven Bakhtiari

unread,
Aug 15, 2014, 4:28:09 AM8/15/14
to halbuil...@googlegroups.com
I'm sorry to drag this one back from the dead, but was there ever any implemented change to allow this? The HAL spec is not very specific on the concept of having empty collections inside the _embedded field, but it makes sense, not just from a client's point of view, but also from a good practice point of view (not to mention the benefits it brings in terms of self-documenting).

For example, even when using a HAL client (in our case, specifically, the AngularJS HAL client), we can't do something like:
 
someResource.$get('someSubResource')

Instead, we're forced to do

if (someResource.$has('someSubResource')) someResource.$get('someSubResource')

You could argue that this is an abstraction leak by the client code (and perhaps I wouldn't argue that point), but even then, the code the client would have to implement would be equally messy. Fortunately, HALBUILDER has the SINGLE_ELEM_ARRAYS option to avoid making clients jump through even more hoops (so thanks for putting that in!) but I think this problem is related/similar.

If it helps, somebody asked a similar question to the HAL group. Mike Kelly even responded in the thread, but didn't (unfortunately) state an opinion on this one way or the other, but he didn't disagree with the unanimous message from the rest of the posters that an empty array > no array.


So, do HAL builder support this now, or is there any chance of requesting it as a feature?

Thanks!
Steven

Mark Derricutt

unread,
Aug 21, 2014, 6:40:33 AM8/21/14
to halbuil...@googlegroups.com

On 15 Aug 2014, at 20:28, Steven Bakhtiari wrote:

Fortunately, HALBUILDER has
the SINGLE_ELEM_ARRAYS option to avoid making clients jump through even

As as of the 4.x series it no longer has that ( its on by default, with a COALESCE_ARRAYS and to drop down to a single object if there's only one ( the self link is ALWAYS coalesced tho ).

So, do HAL builder support this now, or is there any chance of requesting
it as a feature?

To put it in total plain text, what you're wanting is a way of saying:

  • rel NNN -MAY- appear in this response, so we'll always include an _link or _embedded entry even if its empty?

Currently, there's no way of handling what other than swapping in your own JSON writer subclass. Personally, I'd be against such a construct, just like with HTTP headers, you don't include every possible header without a value do you? You only include it if its used in THIS representation.

Mark

Steven Bakhtiari

unread,
Aug 21, 2014, 6:54:44 AM8/21/14
to halbuil...@googlegroups.com
Hi Mark,

I don't think HTTP headers are a fair analogy. I think a more apt analogy is how you would represent those entities in code. 

We all know that nulls are frowned upon, and we know that contracts are useful in APIs. If I have an entity that has a collection of other entities (let's say a User entity that has a field called "friends"), that field doesn't cease to exist just because the user has no friends; instead, it should always be a type of collection. It may be an empty collection, but it's still there, it can still be referenced and you can clearly see, in this case, that a given user entity may or may not have friends. Now clients of this code don't need to (and shouldn't have to) perform a check to see if the field exists before attempting to use it, i.e. client code interacts with the friends field in exactly the same way, regardless of the number of friends associated with the user.

Bringing it back to the context of REST APIs, which should be self documenting, a client will have no idea which fields are available if they appear and disappear depending on whether or not there are any values. If the user entity from my previous example is returned as a resource, but the user has no friends, there will be no friends field. 

In short (as I don't think I've explained myself very well) I think the semantics are different between a missing field and an empty one, and it's unfortunate that the builder doesn't support this. That the HAL spec isn't explicit about this is somewhat disappointing.
Reply all
Reply to author
Forward
0 new messages