简体   繁体   中英

Should a RESTful API avoid requiring the client to know the resource hierarchy?

Our API's entry point has a rel named "x:reports" (where x is a prefix defined in the HAL representation, by way of a curie - but that's not important right now).

There are several types of reports. Following "x:report" provides a set of these affordances, each with a rel of its own - one rel is named "x:proofofplay". There is a set of lookup values associated with this type of report (and only this type of report). The representation returned by following "x:proofofplay" has a rel to this set of values "x:artwork".

This results in the following hierarchy

reports
  proofofplay
    artwork

While the "x:artwork" resource is fairly small, it does take some time to fetch it (10 sec). So the client has opted to async load it at app launch.

In order to get the "x:artwork"'s href the client has to follow the links. I'm not sure whether this is a problem. It seems potentially unRESTful, as the client is depending on out-of-band knowledge of the path to this resource. If ever path to artwork changes (highly unlikely) the client will break (though the hrefs themselves can change with impunity).

To see why I'm concerned, the launch function looks like this:

launch: function () {
    var me = this;
    Rest.getLinksFromEntryPoint(function(links) {
        Rest.getLinksFromHref(links["x:reports"].href, function(reportLinks){
            Rest.getLinksFromHref(reportLinks["x:proofofplay"].href, function(popLinks){
                me.loadArtworks(popLinks["x:artwork"].href);
            });
        });
    });
}

This hard-coding of the path simultaneously makes me think "that's fine - it's based on a published resource model" and "I bet Roy Fielding will be mad at me".

Is this fine, or is there a better way for a client to safely navigate such a hierarchy?

The HAL answer to this is to embed the resources.

Depending a bit on your server-side technology, this should be good enough in your case because you need all the data to be there before the start of the application, and since you worry about doing this sequentially, you might parallelize this on the server.

Your HAL client should ideally treat things in _links and things in _embedded as the same type of thing, with the exception that in the second case, you are also per-populating the HTTP cache for the resources.

Our js-based client does something like this:

var client = new Client(bookMarkUrl);
var resource = await client
  .follow('x:reports')
  .follow('x:proofofplay')
  .follow('x:artwork')
  .get();

If any of these intermediate links are specified in _links , we'll follow the links and do GET requests on demand, but if any appeared in _embedded , the request is skipped and the local cache is used. This has the benefit that in the future we can add new things from _links to _embedded , and speeding up clients who don't have to be aware of this change. It's all seamless.

In the future we intend to switch from HAL's _embedded to use HTTP2 Push instead.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM