简体   繁体   中英

Is it Worth Achieving HATEOAS for Restful Web Services In Real World Usage?

I have been reading a lot about the potential benefits if I were to convert my existing Restful web services to be as HATEOS as possible. I understand the importance in providing links in the payload to reduce the consumer's burden in remembering the next valid available actions. However, I can't seem to wrap my head around how it will help the consumer of my Restful web services in reality.

To illustrate, I take this example from Rest In Practice book about making a coffee order:-

<order xmlns="http://schemas.restbucks.com">
  <location>takeAway</location>
  <item>
    <name>latte</name>
    <quantity>1</quantity>
    <milk>whole</milk>
    <size>small</size>
  </item>
  <cost>2.0</cost>
  <status>payment-expected</status>
  <link rel="payment" href="https://restbucks.com/payment/1234" />
</order>

Basically, this allows the consumer to make a payment defined by the <link> tag. However, in reality, the consumer still needs to know all the semantics of that web service call, for example, what method (POST or PUT) to use, what request parameters to use in the payload in order to make the payment, etc... in another word, the consumer still needs to rely on the WADL documentation to know how to make invoke this web service successfully. These tags probably make more sense if they are all using GETs on one specific item. Otherwise, I really don't see much benefits in defining the links here... apart from the fact the consumer knows what actions they can invoke next, and then refer to the WADL to determine how to invoke it correctly.

My next concern is the possibility of ending up with a very heavy payload with all the <link> tags. For example, if a GET on /projects/1/users returns all the user information that belong project 1, I assume I will end up with the following tags:-

<project>
    <users>
        <user id="12" name="mike" ... />
        <user id="23" name="kurt" ... />
        <user id="65" name="corey" ... />
    </user>
    <links>
        <link rel="self" href="http://server/projects/1/users"/>
        <link rel="create_user" href="http://server/projects/1/users"/>

        <link rel="get_user_mike" href="http://server/projects/1/users/12"/>
        <link rel="get_user_kurt" href="http://server/projects/1/users/23"/>
        <link rel="get_user_corey" href="http://server/projects/1/users/65"/>
        ...
    </links>
</project>

If a project contains say, 500 users... wouldn't I have 500 user links in the payload? Otherwise, what is the best approach in redesigning my web services to handle this situation? Or is this acceptable in real world?

Any thoughts or suggestions are greatly appreciated here. Thank you.

To think of why it's the right thing to do, imagine your API without a HATEOAS approach: you'll have to publish every single possible URI scheme in your documentation (or in your WADL, if that's your thing), and from that point on you cannot change them without breaking your clients.

In essence, your clients will be inextricably coupled to your choice of URI layout. That's a level of coupling that you can easily avoid by just documenting where the links are in your media types rather than documenting what the links look like as well.

That said, it might be OK for your application's needs to take that approach, and that's fine. Just keep in mind that you'll be stuck with your URI layout for a long, long time. You'll be in good company though.

For your particular example, I think it makes sense to go back to HTML. If you display a list of 500 resources in HTML, would you include a link to each resource, so that users can get more information? You probably would. A REST API is not much different - if you return a list of 500 resources, you need to include 500 links, so that users can get more information about each resource.

Expecting clients to build up URLs based on some IDs or names would be like asking users to manually type URLs in the browser's address bar.

Here is a very good article about this, in particular:

Just like HTML files link to each other with tags, or just like XML files link to each other with XLink, all state transfer has to be done solely as a reaction to a link found inside of a representation

Just a side-point on the 500 user thing: I'm no expert but my understanding is that you can restfully provide pagination:

/project/1/users/pages/1

<links>
    ...
    <link rel="get_user_mike" href="http://server/projects/1/users/12"/>
    <link rel="get_user_kurt" href="http://server/projects/1/users/23"/>
    <link rel="get_user_corey" href="http://server/projects/1/users/65"/>
    <link rel="get_page_2" href="http://server/projects/1/users/pages/2"/>
</links>

This isn't really an answer, just some tips for adopting HATEOAS. You do not need to include hundreds of links, you can either include 1 link to the full list of 500, 1 link to a paginated subset of the links, or include a paginated subset in the response and add a next page link.

In response to the WADL thing, you should use the built-in facilities of whatever your content format is, eg In HTML that would be LINK and A elements to indicate the client should make GET requests, and FORM elements for POST requests. Obviously other formats and APIs XLink and XMLHTTPRequest support HTTP better than HTML does. You might like to look at http://tools.ietf.org/html/draft-nottingham-link-hint

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