Circular References

58 views
Skip to first unread message

Michael Tiller

unread,
Aug 21, 2016, 10:15:31 AM8/21/16
to Siren Hypermedia
I made a post on this earlier, but prematurely hit send (thanks to the Google Groups web UI shortcut keys).  Let me try this again.

I'm working with Siren as a message format, but also tracking it closely internally in a library I'm using.  That by itself isn't an issue.  But one thing I can end up with is circular depedencies.  The problem is that if I elaborate those relationships into the Siren message format, I can get stuff like this:

{
  "class": [ "thing-list" ],
  "entities": [
    { 
      "class": [ "thing" ],
      "rel": [ "item" ],
      "href": "http://examples.com/thing1",
      "properties": { "i": 1 },
      "entities": [
        {
          "class": [ "thing" ],
          "rel": [ "sibling" ],
          "href": "http://examples.com/thing2",
          "properties": { "i": 2 },
          "entities": [
            {
              "class": [ "thing" ],
              "rel": [ "sibling" ],
              "href": "http://examples.com/thing1"
              /* Turtles all the way down */
            }           
          ]
        }
      ]
    }, { 
      "class": [ "thing" ],
      "rel": [ "item" ],
      "properties": { "i": 2 },
      "entities": [
        {
          "class": [ "thing" ],
          "rel": [ "sibling "],
          "href": "http://examples.com/thing1",
          "properties": { "i": 1 },
          "entities": [
            {
              "class": [ "thing" ],
              "rel": [ "sibling" ],
              "properties": { "i": 1 },
              "href": "http://examples.com/things1"
                 /* Turtles all the way down */
              }
            ]
          }
      ]
    }
  ]
}

I'm wondering if other people have run into this and how they deal with it.  I see a couple of alternatives:
  1. I could impose a depth limit (i.e., just stop following relations once the response reaches a certain depth.
  2. Record what entities have already been embedded somewhere and simply avoid repeated embedding.
  3. Create a "cache" (more below)
A depth limit seems kind of arbitrary to me.  You have to make a tradeoff between knowing how far is far enough and the volume of the response.  But in the end, as I said, this seems rather arbitrary.  If you set the depth low, you get small responses, but you might "miss" something by not including it.  If you set it too high, you'll probably get large responses without much value.  And there is no real way to decide on that value.  So I don't think this is a particular good approach.

Avoiding repetition seems reasonable.  But I see two issues.  First, it will require bookkeeping to realized what entities have already been embedded.  Things could be simplified a little bit to simply avoid repetition along a given branch in the tree rather than across the whole tree.  But it is still some work to implement.  The other issue is (and this is a little specific to the application which I'm not really describing) is that you may end up wanting to embed different representations at different points (i.e., different information).  So one embed in one place (which may choose to only include some properties) isn't necessary a stand-in for an embed in another place (which might include different properties).  So making sure all information is present is tricky.

Approach #3 above could involve introducing some kind of "cache" at the top level of the response of all embeds and then using only links in all other places.  This requires the client to be aware of what is going on, however.  But the response could be something like this:

{
  "class": [ "thing-list" ],
  "links": [
      {
          "rel": [ "item" ],
          "href": "http://examples.com/thing1"
      },
      {
          "rel": [ "item" ],
          "href": "http://examples.com/thing2"
      }
  ],
  "entities": [
    { 
      "class": [ "thing" ],
      "rel": [ "cache", "item" ],
      "href": "http://examples.com/thing1",
      "properties": { "i": 1 },
      "links": [
          {
            "rel": [ "sibling" ],
            "href": "http://examples.com/thing2"
          }
      ]
    },
    { 
      "class": [ "thing" ],
      "rel": [ "cache", "item" ],
      "href": "http://examples.com/thing2",
      "properties": { "i": 2 },
      "links": [
          {
            "rel": [ "sibling" ],
            "href": "http://examples.com/thing1"
          }
      ]
    }
  ]
}

The idea is that all "entities" are recorded at the top (even ones that don't have a *direct* relationship to the root resource).  Everything else is just links.  If a client wants the embedded entity, it can look it up via the "href" and the "cache" relationship at the root level.

This seems like the most space efficient and nothing is arbitrary.  You get exactly what is required.  Nothing is every lost, it is simply all flattened at the top and circular references are handled via "links" rather than further embedding.

The drawback for the cache case is that the client has to be aware of this pattern.  Perhaps there are other drawbacks that other people have run across that I simply haven't foreseen as well (so please comment).

Any comments on this?

--
Mike

Alex Soto

unread,
Aug 22, 2016, 2:47:55 AM8/22/16
to siren-hy...@googlegroups.com
One way I resolve this is to just render link sub entities beyond the first level of embedded entities.  If clients need all full representation all the way down, then it would be a 'code smell' to me.

--
You received this message because you are subscribed to the Google Groups "Siren Hypermedia" group.
To unsubscribe from this group and stop receiving emails from it, send an email to siren-hypermedia+unsubscribe@googlegroups.com.
To post to this group, send email to siren-hypermedia@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/siren-hypermedia/047c716b-c774-47c0-a26b-598a06cc8957%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages