hypermedia linking

145 views
Skip to first unread message

James McGinty

unread,
May 11, 2012, 10:33:34 PM5/11/12
to api-...@googlegroups.com
Consider this json which represents an Order:

{
    "Id": "2814",
    "ShipmentType": {
        "Id": "2",
        "Code": "Road",
        "Url": "http://api.company.com/logistics/shipmenttypes/{Id}"
    },
    "Warehouse": {
        "Id": "7449",
        "Code": "External",
        "Url": "Url": "http://api.company.com/logistics/warehouses/{Id}?Country=Australia"
    },
    "Products": [
        {
            "Id": "87",
            "Name": "Shirt",
            "Url": "http://api.company.com/master/products/{Id}
        },
        {
            "Id": "122",
            "Name": "Pants",
            "Url": "http://api.company.com/master/products/{Id}
        }
    ]
}

I am experimenting with links to the things referenced on the order.
The shipment type is "Road" which is found at http://api.company.com/logistics/shipmenttypes/{Id}.
What do people think of this style of defining the link to the resource - i.e. using {Id} instead of hard coding the Id in the url?

If the client wants to change the shipment type, they can see list of all Shipment types at
http://api.company.com/logistics/shipmenttypes/

This is taken one step further with the warehouse url.
The business logic demands that this particular order can only be delivered from a warehouse from Australia.
So instead of baking this logic into the client, this is expessed in the url
"http://api.company.com/logistics/warehouses/{Id}?Country=Australia"

So if the client wants to choose a different warehouse, the valid choices are found at
"http://api.company.com/logistics/warehouses/?Country=Australia"

What do you think of this?
Is anyone using a similar technique? How do other people deal with this problem ?

James

mca

unread,
May 12, 2012, 10:47:03 AM5/12/12
to api-...@googlegroups.com
James:

good to see you using hypermedia in your message designs; it's
something i do in almost all my implementations.

what follows are some of my observations and opinions on your design.

1) check out RFC6570 - URI Template [1]. This is a newly-release
standard on creating the kind of templates you are showing here. the
RFC includes processing rules and will (likely) lead to folks writing
standard parser libraries. then we can all use a common set of
templates w/ assurances they will be understood and processed by a
wide range of clients.

2) i see your designs use things like "code" and "name" to help
identify the link.. I'd encourage you use the "rel" attribute for this
and follow the RFC5988 - Web Linking [2] spec. it's essentially doing
what i think i see you already doing, but again it will be
standardized in a way that third-party devs will pick up easily.

3) operationally, i'm not sure (from looking at the example) which
"id" should be plugged into which template. this proly is covered in
the docs, but you might want to use naming to help make that easier to
pick up quickly wen devs are looking at your messages (i.e.
shipmentId, warehouseId, etc.).

4) it's not clear to me (from this example) why you are using the
template for shipment and warehouse links. are there other possible
values for {id} that i could use? if yes, where are those values? if
not, it's better to juse pass me (the client dev) a complete URI that
i know will work w/o me needing to "construct" the URI before it's
valid.

5) you write in your narrative that devs can "drop" the {id} from the
template in order to get a list of valid ids. personally, i prefer
_NOT_ coding that rule in my clients (or asking other devs to do
that). instead, i provide a "list" URI that can be used directly.
again, this makes sure devs don't need to hard code URI construction
into their apps and let's me (the server coder now<g>) change this URI
sometime in the future w/o breaking existing code. one possible way to
do this is:

"ShipmentType": {
"Id": "2"
    "Code": "Road",
    "ItemUri": "http://api.company.com/logistics/shipmenttypes/{Id}",
"ListUrl" : "http://api.company.com/logistics/shipmenttypes/"
},

Finally, i've been working on a similar design for JSON-Hypermedia.
I've registered the Collection+JSON media type[3] and continue to
tweak it based on feedback. feel free to use this as a guide for ideas
on your own design and/or provide me feedback on changes you think
could make CJ useful for your needs.

Hope this helps.

Mike


[1] http://tools.ietf.org/html/rfc6570
[2] http://tools.ietf.org/html/rfc5988
[3] http://amundsen.com/media-types/collection/

mca
http://amundsen.com/blog/
http://twitter.com@mamund
http://mamund.com/foaf.rdf#me

Mike Kelly

unread,
May 12, 2012, 1:58:37 PM5/12/12
to api-...@googlegroups.com
Hi James,

As mamund pointed out you can defer to the URI Template spec for templates URIs.

I've worked out some simple conventions for linking on top of json which look like they would fit your needs well, check it out here:

http://blog.stateless.co/post/13296666138/json-linking-with-hal

Would it be useful if j translated your example into hal+json?

Cheers,
Mike

Matthew Bishop

unread,
May 16, 2012, 2:16:34 PM5/16/12
to api-...@googlegroups.com
I can't figure out a good use case for the {id} expands in the URL given that the representation has the ID in the object too. A developer would find it frustrating and nonobvious to have to do the string math themselves.

In general, Level 3 REST APIs should not require any string math on the client. Consider it a code smell.

Matt Bishop

mca

unread,
May 16, 2012, 2:23:27 PM5/16/12
to api-...@googlegroups.com
Matt:

<snip>
In general, Level 3 REST APIs should not require any string math on the client. Consider it a code smell.
</snip>
Interesting POV. 

So you think RFC6570 (URI Templates) is an anti-pattern for REST implementations?

HTML.FORM@method="get" is an anti-pattern for REST, too?

Werner Strydom

unread,
May 16, 2012, 6:43:58 PM5/16/12
to api-...@googlegroups.com
URI Templates is a headache I can do without.  

Werner  

James McGinty

unread,
May 17, 2012, 7:38:35 AM5/17/12
to api-...@googlegroups.com
HI Mike & Mike (!) Thanks for your quick replies, sorry I am so tardy in mine.
I have gone and read RFC6570 - URI Template [1] and I think by accident (not design) that my templates match the RFC.
Good to know there is a standard for this, and I will refer to it from now on.

RFC5988 - Web Linking [2] is a bit longer, and I haven't read it all yet, but I agree that it seems to be describing what I am attempting to do.

There seems to be some confusion as to why the link is a template, not a simple link. It is to reduce redundancy.

The resource representing an Order is *NOT* a static, read only resource. The client can and does change it!

In the element

"Warehouse": {
        "Id": "7449",
        "Code": "External",
        "Url": "Url": "http://api.company.com/logistics/warehouses/{Id}?Country=Australia"
    }

Id is telling the client what the current Id of the warehouse.
If the client wishes to find more details of that (warehouse) resource they can GET the URL substituting in the 7449 for the {Id}.
e.g. GET http://api.company.com/logistics/warehouses/7449?Country=Australia
If the client wishes to choose a different warehouse, they can get a list of valid options by leaving out the {Id} part.
e.g. GET http://api.company.com/logistics/warehouses/?Country=Australia

My aim here is to remove the business logic of "What warehouses are valid for *this* Order" from the Client, and give the client a link to find the valid options.

I will be definitely checking out the Collection+JSON media type, no opinion on this as yet.. I hope I can contribute some feedback from my situation.

WHY ARE YOU USING A TEMPLATE? Glad you asked!

My motivation for using a template, not two seperate references is that they are identical, except for the {Id}.
Using the Shipment types as an example:


"ShipmentType": {

        "Id": "2",
        "Code": "Road",
        "Url": "http://api.company.com/logistics/shipmenttypes/{Id}"
    }

I could represent this as

"ShipmentType": {
        "Id": "2",
        "Code": "Road",
        "ItemUri": "http://api.company.com/logistics/shipmenttypes/2",
        "ListUrl": "http://api.company.com/logistics/shipmenttypes/"
    }

but I just didn't see the point in padding out the document with redundant (IMO) items.

I can understand if the Item & List urls are in seperate name spaces, this would be necessary, but does that really happen?
I thought in a well designed API the resource link is basically the same as the "search" link, but with the ID as a qualifier.

I must add, this example is over-simplified. In my real resources, there are 20-30+ elements which have this 'item/list' relationship which only differs by the insertion of an Id, so including two almost identical links goes against the grain.

@Mike Kelly - re "Would it be useful if I translated your example into hal+json?"  -- Yes, I think it would!

Thanks all for your feedback, I really appreciate all of it!

James

Mike Kelly

unread,
May 17, 2012, 8:34:40 AM5/17/12
to api-...@googlegroups.com
Fwiw I think you will greatly simplify your application if you stick
to template-less URIs where possible. I'm not sure I buy your
rationale in this case.

fwiw, I put together an example of how you might express your example
with hal (without template URIs)

https://gist.github.com/2718592

Cheers,
Mike

James McGinty

unread,
May 17, 2012, 6:33:09 PM5/17/12
to api-...@googlegroups.com
Hi Mike,
In your example (below) - how does the client know how to get a list of warehouses that are valid options for this order?
{
  "_links": {
    "self": { "href": "/orders/123" },
    "shipment-type": { "href": "http://api.company.com/logistics/shipmenttypes/2" },
    "products": [{
      "title": "Shirt"
    },{
      "title": "Pants"
    }]
  }
}
 
I don't think the anwer is deduceable from the data, so the client must be smart enough to know this, 
which means some business logic is embedded in the client.
I was just trying to aim for the "Smarter data, dumber clients" goal.

James

mca

unread,
May 17, 2012, 6:43:15 PM5/17/12
to api-...@googlegroups.com
James:

If you want to provide a way for clients to " get a list of warehouses", you provide a link w/ that identifer (rel) associated w/ it. that takes almost _zero_ business logic.

Matthew Bishop

unread,
May 18, 2012, 1:26:20 AM5/18/12
to api-...@googlegroups.com
URI Templates is an antipattern for Level 3 REST (it makes sense for the lower levels however). The reason is Level 3 REST clients should be looking for links that have certain rel names and following them, not constructing URLs.

mca

unread,
May 18, 2012, 2:11:05 AM5/18/12
to api-...@googlegroups.com
and does "Level 3 REST" also say HTML.FORM@method="get" is an anti-pattern?

Duncan Cragg

unread,
May 18, 2012, 4:49:37 AM5/18/12
to api-...@googlegroups.com
On 18/05/12 07:11, mca wrote:
> and does "Level 3 REST" also say HTML.FORM@method="get" is an
> anti-pattern?

There is a subtle difference between browser / Web usage of GET forms
and use of URL templates in M2M REST interpretations.

For browsers, it goes [domain-aware UI -> server-set labels -> URL]; for
M2M URL templates it goes [domain-aware labels -> URL].

That extra level of indirection is critical: it gives the bendy-point,
the decoupling point that keeps to the spirit of REST in a way that URL
templates doesn't.

Basically, in the browser, the server still keeps control of its URL
structure - the end-user or domain-level client doesn't have a clue
what's going on behind the UI - but the interaction is now at the domain
level in that UI.

For an M2M interpretation of REST, you should probably be using POST -
moving the domain interactions into the body and content. This can then
redirect you to a server-generated URL to GET, if that helps. That GET
URL can have all the data you POSTed in cleartext, just like URL
templates - but only the server can create them.

URL templates mix concerns and responsibilities by putting some domain
'protocol' elements into the HTTP header level and out of the body or
content or Media Type, and I believe should not be part of any clean M2M
REST interpretation.

(A similar thing applies to POSTed forms, and a similar conclusion: it
doesn't make sense to use a 'server-supplied form metaphor' in an M2M
interpretation of REST. Forms on the Web for POSTing translate the 'I
know what to put into the form fields at a domain level of
understanding' - which should be stable in the same way a Media Type
should be stable - into a machine-level data object, whose structure is
stable at the simple www-form Media Type level at least. For M2M, you
replace all that with a higher-level, domain-level encoding of data, and
skip the indirection - just POSTing that agreed data type because you
know you can.)


Duncan

PS I think we can all agree that there is /only/ Level 3 REST, anything
else is an oxymoron.

Mike Kelly

unread,
May 18, 2012, 4:59:16 AM5/18/12
to api-...@googlegroups.com
On Fri, May 18, 2012 at 6:26 AM, Matthew Bishop <ma...@thebishops.org> wrote:
> URI Templates is an antipattern for Level 3 REST (it makes sense for the
> lower levels however). The reason is Level 3 REST clients should be looking
> for links that have certain rel names and following them, not constructing
> URLs.

No, this is wrong. URI templates are completely different from
out-of-band 'templates' contained in documentation.

There is nothing inherently wrong with the construction of URIs
provided they are _driven in-band_ by a hypermedia control like HTML
get forms, or URI template links.

You are incorrectly conflating the antipattern of "out-of-band" URI
construction rules that are contained 'offline' in documentation for
the API. The reason this is an antipattern is because clients will
couple themselves to those construction rules, and the server loses
some control over its URI space. URI templates are in-band, so clients
will apply variables to the template as it traverses through the API,
which allows the server to completely change the target URI of a
template however it wants and/or add further optional variables to the
template.

Cheers,
Mike

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

Greg Brail

unread,
May 18, 2012, 2:28:08 PM5/18/12
to api-...@googlegroups.com

PS I think we can all agree that there is /only/ Level 3 REST, anything else is an oxymoron.


This is "API Craft," not "REST Discuss." There are many valid, efficient, and usable ways to build APIs. "Level 3 REST" is but one -- and one that has not been widely adopted despite years of debate.

I'm glad to hear that there are a few people on this list who are successfully building and using hypermedia-style APIs -- that's cool and interesting, and thanks.

--
Gregory Brail  |  Technology  |  Apigee

Mike Kelly

unread,
May 18, 2012, 2:36:37 PM5/18/12
to api-...@googlegroups.com
Hi Greg,

To be fair I think the point being made was that level 3 is the only form of legit REST rather than API design as a whole.

Cheers,
Mike
Reply all
Reply to author
Forward
0 new messages