Action in collection for embedded item

88 views
Skip to first unread message

nickdu

unread,
Mar 5, 2015, 9:07:11 PM3/5/15
to api-...@googlegroups.com
I'm new to hypermedia.  After doing a bunch of research I'm currently investigating exposing an API as a set of processes/workflows as opposed to entities.  Of course I'll still need entities, but it seems reasonable to assume that a client is looking to invoke actions in order to achieve a goal so exposing a set of processes for each goal sounds like a good idea.

The sample API/service we've been using is an issue tracker service.  The processes I'm thinking of exposing are:

1. Create an issue.
2. Close an issue.
3. Update an issue.
4. Browse issues.

Let me try to cut to the chase so that this is not too long of a read.  If you already have an issue ID then I can expose a link for closing it.  However, most likely you'll want to search for the issue you're looking to close.  If I know you're coming from the 'Close an issue' process and you ask for the collection of issues, can I have the action to close the issue in the collection instead of repeating it in each embedded item?  I'm thinking of doing this so the payload is smaller.  For example, below is what I'm thinking would be the representation for the collection:

{
  "count" : 10,
  "_links" :
  {
    "curies" : [{"name" : "itrel", "href" : "http://localhost/issuetracker/docs/rels/{rel}", "templated" : true}],
    "itrel:closebyid" : {"href" : "http://localhost/issuetracker/issuestoclose"},
    "next" : {"href" : "http://localhost/issuetracker/issues?close&offset=5{&count}", "templated" : true}
  },
  "embedded" :
  {
    "itrel:issue" :
    [
      {
        "title" : "first bug",
        "description" : "description of first bug.",
        "id" : 1,
        "_links" : {"self" : "http://localhost/issuetracker/issues/1"}
      },
      {
        "title" : "second bug",
        "description" : "description of second bug.",
        "id" : 2,
        "_links" : {"self" : "http://localhost/issuetracker/issues/2"}
      },
      {
        "title" : "third bug",
        "description" : "description of third bug.",
        "id" : 3,
        "_links" : {"self" : "http://localhost/issuetracker/issues/3"}
      },
      {
        "title" : "fourth bug",
        "description" : "description of fourth bug.",
        "id" : 4,
        "_links" : {"self" : "http://localhost/issuetracker/issues/4"}
      }
    ]
  }
}

The goal is to be able to navigate to the "itrel:closebyid" link.  This link needs an item id.  Is it ok to have the client get the id from the embedded resource and us it in the link of the representation?

Thanks,
Nick

wiki1000

unread,
Mar 6, 2015, 1:20:24 AM3/6/15
to api-...@googlegroups.com
You MUST not use "id" extracted from uris to build or worse, denote other uris.

You can return a Link header along with the list of uris which is the result of the query:
Link: <>;rel=close_issue;allow-post=text/uri-list;allow=POST

All that you can do then, is to POST the uris of the issues you want to close to the drop site uri provided by the link.
You may even send nothing to mean that you want to close all the issues ! (I would not recommand that, but this may be fun).
 
You can also require confirmation and return the list of links in a dynamically generated uri that you would have to DELETE to
really close the issues.
 
This proposition shows (imho) that the separation of the hypermedia controls and the hypermedia content
is a good thing in lot of cases: simple to add, simple to understand and to use.

nickdu

unread,
Mar 6, 2015, 9:55:47 AM3/6/15
to api-...@googlegroups.com
I'm not exactly following.  I think I understand most of what you say.

You say not to use "id" extracted from uri's to build or denote other uris.  Am I doing that?  The "id" is a property of the issue.  I was thinking the endpoint to close an issue would take, as a payload, the issue "id".  The client is browsing the collection to find the issue they're interested in and when they do they have the issue "id" available (in the embedded resource).  They can now make the request to the closebyid link.  Are you suggesting I should always be passing URI's instead of just the ID?

Thanks,
Nick

wiki1000

unread,
Mar 6, 2015, 10:09:20 AM3/6/15
to api-...@googlegroups.com

>Are you suggesting I should always be passing URI's instead of just the ID?
Yes!
A URI shall be considered fully opaque: imagine that for some reason or another, one of them does NOT follow your schema ?

In fact an "id" (generally a meaningnless number) shall never be used as a transmissible value, while an URI can always be...

URI templating shall only be used with meaningfull values (in order to express queries) and never to abstract opaque parts of an opaque value.

Cheers.

nickdu

unread,
Mar 6, 2015, 10:31:08 AM3/6/15
to api-...@googlegroups.com
Thanks.  But it sounds like we might not be on the same page.  I was not suggesting some code would pull an "id" out of a URL.  The issue entity has an "id".  Someone wanting to close an issue would following the closebyid link passing the issue "id".

Thanks,
Nick

wiki1000

unread,
Mar 6, 2015, 11:01:13 AM3/6/15
to api-...@googlegroups.com
All right, sorry: but the issue entity has also an uri and the whole thing is so complex I lost my way.
Why not POSTing one or several issue uris to a closing uri ?

I maintain my (humble) point: you shall not refer to an entity with something different from a uri.





nickdu

unread,
Mar 6, 2015, 12:17:19 PM3/6/15
to api-...@googlegroups.com
To be honest, that's another question I had.  If we have "action" endpoints (collections in our case) and the action operates on or is related to a resource, should you always be passing the URI of the resource or some other identifier?  It sounds like you're saying it should always be a URI.  I thought that maybe you could also use a unique key of the resource.  In this case I'm bringing up it's the "id".  In some cases you could envision it being a "name".  I like the uri version, but then the server needs to know how to pull the unique key out of it and thus it would seem easier, and I wasn't aware of any rules I might be breaking, by just passing the unique key.

Thanks,
Nick

Piers

unread,
Mar 6, 2015, 2:34:27 PM3/6/15
to api-...@googlegroups.com
The URI is the Uniform Resource Identifier  :) 

"3" is not an especially useful identifier of something.  <the issue "3" in the context of a the issue tracker at issuetracker.example.org> is, perhaps. But what it identifies already has a more concise ID - the URI.

Piers

unread,
Mar 6, 2015, 2:40:50 PM3/6/15
to api-...@googlegroups.com
While I'm here ;)


Some different patterns might be:
1)
      ...
      {
        "title" : "third bug",
        "description" : "description of third bug.",
        "id" : 3,
        "_links" : {
           "self" : "http://localhost/issuetracker/issues/3",
           "it:close": "http://localhost/issuetracker/close/byid/3"
         }
      },

The docs for link relation it:close would give the semantics, perhaps POST "<close>" to the linked resource. Note that the actual URI target of it:close is opaque to the client.

OR

2)
Just have clients do actual Representational State Transfer something like:


{
     ...
      "State": "closed"
     ...
}




On Friday, 6 March 2015 17:17:19 UTC, nickdu wrote:

wiki1000

unread,
Mar 6, 2015, 3:26:33 PM3/6/15
to api-...@googlegroups.com
I dont know if you are "new to hypermedia" or if you are kidding at me, but precisely,
hypermedia and REST consist in abandoning for ever the idea to reference entities by their
"id" and to radically shift to the use of uris in any circumstance.
Seriously: you did not realize this before ? 

http://www.w3.org/DesignIssues/Axioms.html

already almost twenty years, dear sir...

nickdu

unread,
Mar 6, 2015, 4:34:56 PM3/6/15
to api-...@googlegroups.com
Was this comment meant for me?  If so, no I'm not kidding.  I have better things to do with my time such that I can't waste it on just joking around.  So no, I did not realize that "it's against the rules" to use anything but an URI to reference an entity.

Thanks,
Nick

nickdu

unread,
Mar 6, 2015, 4:36:21 PM3/6/15
to api-...@googlegroups.com
Would certainly not want to post {"state" : "closed"} to close an issue as there are most likely other side effects of closing an item.  I therefore want to draw attention to these "actions" and thus would create possibly write-only collections to handle them.

Thanks,
Nick

Sam Ramji

unread,
Mar 6, 2015, 4:37:03 PM3/6/15
to Api Craft
wiki1000, you are not coming across as clever, funny, or collegial.

This is your final warning before you are banned from API-Craft.

--
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.
For more options, visit https://groups.google.com/d/optout.

nickdu

unread,
Mar 6, 2015, 4:37:10 PM3/6/15
to api-...@googlegroups.com
Also, I was trying to limit the size of the payload and thus didn't want to include the close link on all embedded resources but instead include it once in the collection.

Thanks,
Nick

On Friday, March 6, 2015 at 12:40:50 PM UTC-7, Piers wrote:

nickdu

unread,
Mar 6, 2015, 4:37:54 PM3/6/15
to api-...@googlegroups.com
Plus, didn't I say I was "new to hypermedia".

Thanks,
Nick

Sam Ramji

unread,
Mar 6, 2015, 4:40:49 PM3/6/15
to api-...@googlegroups.com
Nick, your questions and comments are in keeping with the spirit of this community.  You're doing great.

We have been working with wiki1000 on their communications and attitude.  Please don't take their comments as representative of our community standards.

On behalf of the community, I apologize for wiki1000 and sincerely hope that you have a good Friday and that you get your questions resolved here.

Sam 

nickdu

unread,
Mar 6, 2015, 7:14:23 PM3/6/15
to api-...@googlegroups.com
I'm curious why you think separating hypermedia controls from the hypermedia content is a good thing?  Not that I disagree.  In fact I don't disagree or agree since I'm still too new at this to know.  I think I've seen other posts of yours where you mention the same thing.  Can you provide more info/examples showing the pros of doing it this way?


Thanks,
Nick

On Thursday, March 5, 2015 at 11:20:24 PM UTC-7, wiki1000 wrote:
 
You can return a Link header along with the list of uris which is the result of the query:
Link: <>;rel=close_issue;allow-post=text/uri-list;allow=POST

  ...
 

wiki1000

unread,
Mar 7, 2015, 5:27:44 AM3/7/15
to api-...@googlegroups.com
>I'm curious why you think separating hypermedia controls from the hypermedia content is a good thing?  Not that I disagree.  In fact I don't disagree or agree since I'm still too new at this to know.  I think I've seen other posts of yours where you mention the same thing.  Can you provide more info/examples showing the pros of doing it this way?

I will prefer not to. For fear of offending innocents and be censored.
Bye !

Piers

unread,
Mar 7, 2015, 6:41:28 AM3/7/15
to api-...@googlegroups.com
It's your choice :) Designing anything is probably always a series of trade-offs after all. 

I'm fond of reminding myself that the API should be designed for clients, not just a simple way to expose the innards of a system. An API is a type of UI - with a different "user". It needs as much care and design and abstraction from the underlying system as a human UI. 

To my mind, this is what separates 'RPC' from 'REST' (and I'm making an assumption that Hypermedia means REST-including-HATEOS). 

I guess it depends really how much this particular use case the API client needs to know about the side effects. If the client has to vary the side effects in some way then ok, but if the API client doesn't really care if there are side effects but just wants to tell your system that it considers the issue closed, then the PUT of that state (or a PATCH perhaps) is good. If you buy into REST at all (and you don't have to) then transferring representations of current state, rather than calling remote procedures to do actions, is part of the game. 

If you do accept PUT then likely you'll want to implement If-Match / Precondition failed parts of HTTP etc. You'll have to do some clever stuff on the server to make sure it's idempotent (not triggering side effects more than once). All that is abstracted by the API and the REST concept, but it does take work behind the scenes to make it work well. 

This might all be way off the mark for your particular use case, it's just some random thoughts.

Piers

unread,
Mar 7, 2015, 6:46:15 AM3/7/15
to api-...@googlegroups.com
Me again! Compress your payloads with e.g. http content-encoding options for sure if byte-on-the-wire is an issue (if you're likely going over mobile networks for example). 

But I'd see it as a mistake to use size of payload as anything other than the very last factor in designing an API. It's the sort of optimisation that feels important but almost never turns out to be, in my limited experience.
Reply all
Reply to author
Forward
0 new messages