WHY
              HATEOAS
A simple case study on the often ignored REST constraint


                  Wayne Lee, June 200...
Background
• Representational state transfer (REST)
  – A software architecture style for distributed
    hypermedia syste...
HATEOAS
     Hypermedia as the engine of application state

• The model of application is an engine that
  moves from one ...
Why HATEOAS
• Resources will evolve over time
  – Naming, URI, location, partition …


• Thus any assumptions about server...
A Simple Case Study

  Imagine You’re Building
 an Online Order Manager
Where You Start
         Users Table                                         Orders Table
    ID             Name         ...
Your “REST” API V1
•   Step 1: POST /login (user_name, password)
     – Session created
•   Step 2: GET /orders
     – Get...
Then lots client apps emerge …
• From users, fans, solution providers,
  mashup makers…

• 10s  100s  1000s …

• Based o...
After some time …
• Some suggest implicit user id in session /
  cookie NOT a good idea …

• That user_name should be incl...
“REST” API V1.1
•   Step 1: POST /login (user_name, password)
     – Session created

•   Step 2: GET /{user_name}/orders
...
But, what about old apps?
• Just let them break? – Not Acceptable

• Make sure Orders servlet maintain backward
  compatib...
Then after some time …
• You decide to add a paid offerings:
  – Free accounts:
     • Data on the old host
  – Profession...
DB Changes
     Users Table                             Orders Table for Free Users
ID      Name       Type               ...
“REST” API V2
•   Step 1: POST /login (user_name, password)
     –   Session created, with User_Type returned

•   Step 2:...
Again, what about old apps?
• Just let them break? – Still Not Acceptable

• Modify Orders servlet logic again:
   – Retri...
As time goes by
• You think it time for a VIP offering:
  – Free accounts:
     • Data on the old host
  – Professional ac...
DB Changes
     Users Table                                Orders Table for Free Users
ID         Name     Type       Doma...
“REST” API V3
•   Step 1: POST /login (user_name, password)
     –   Session created, with User_Type, User_Domain returned...
Again, what about old apps?
•   “We’ll support old client apps, as usual…”

•   Modify Orders servlet logic again:
     – ...
Things Can Get Even More
       Complicated
More requirements, more offerings,
more functions, more features, more
rules, ...
So Will Servlet Logic …

And maintenance, logging, testing,
      trouble-shooting …
And Client App Implementation Cost
So

What’s Wrong in the First Place?
“REST” API V1
•   Step 1: POST /login (user_name, password)
     – Session created

•   Step 2: GET /orders
     – Get Ord...
A True REST API V0.1 Instead
•   Step 1: POST /login (user_name, password)
     – Session created, user related resource d...
Same API Works
                      across Various Account Types …
                    Free                       Pro    ...
… and Adaptable to Various Situations
•    Tom just upgrade from Free account to Pro, with bulk data migration
     schedu...
Put It Visually

Imagine a Parking Lot
Different Zones for Different Parkers



                                                 Free parkers
               Pro ...
A once-free-now-VIP Parker who
 cannot get rid of old habits …


                           “Sir, your lot is in the VIP z...
“REST” API without HATEOAS
Be prepared to repeat this mess each and every day




               Pro parkers


           ...
A HATEOAS API Scenario
    Instructions to each customer each time




                                                   ...
RPC vs. HATEOAS
           Not necessarily future-proof but more efficient for now
                                       ...
Take Away
• HATEOAS is essential, for
  – APIs as well as internal organization of complex
    systems that may evolve ove...
Upcoming SlideShare
Loading in...5
×

Why HATEOAS

27,884

Published on

A simple case study around HATEOAS (Hypermedia as the engine of application state), an essential constraint of the REST architecture style

Published in: Technology, Business
5 Comments
67 Likes
Statistics
Notes
  • This is the most eye opening deck I've seen on the subject of RESTful APIs, and brings back a lot of painful memories of systems I've built which fell into the same trap. My next API will almost certainly follow these guidelines. Thank you OP.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Very well explanation and great use of visuals.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • The best doc about Hateoas I've seen. thanks!
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • 3 years after this presentation and I don't see HATEOAS widely adopted. Why?
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • If your entry points change, you should redirect the user to the new default entry point. In HTTP-speak, that's one of the class 3xx status codes.

    That should give you time to depreciate and notify your clients of changes.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total Views
27,884
On Slideshare
0
From Embeds
0
Number of Embeds
51
Actions
Shares
0
Downloads
388
Comments
5
Likes
67
Embeds 0
No embeds

No notes for slide

Why HATEOAS

  1. 1. WHY HATEOAS A simple case study on the often ignored REST constraint Wayne Lee, June 2009 http://trilancer.wordpress.com/
  2. 2. Background • Representational state transfer (REST) – A software architecture style for distributed hypermedia systems, e.g., the World Wide Web – Introduced by Roy Fielding in 2000 • REST Constraints – Identification of resources – Manipulation of resources through representations – Self-descriptive messages – Hypermedia as the engine of application state
  3. 3. HATEOAS Hypermedia as the engine of application state • The model of application is an engine that moves from one state to another by picking alternative state transitions in current set of representations • Or simply put: – State: where the user is • i.e., current resources – Transitions: instructions on user’s next steps • i.e., links / forms from current resources to others
  4. 4. Why HATEOAS • Resources will evolve over time – Naming, URI, location, partition … • Thus any assumptions about server resources will break eventually – URI pattern, valid state transitions … • HATEOAS is about reducing assumptions – Loose coupling between client & server – Allowing each to evolve independently
  5. 5. A Simple Case Study Imagine You’re Building an Online Order Manager
  6. 6. Where You Start Users Table Orders Table ID Name ID User_ID 1 Tom 123 1 2 Jerry 456 2 … … … … Server 1: myorders.com • One server • Two DB tables • Free user registration
  7. 7. Your “REST” API V1 • Step 1: POST /login (user_name, password) – Session created • Step 2: GET /orders – Get Order List, with user id implicitly provided in session • Step 3: GET /orders/{order_id} – Get specific Order data through cooked URI • Sample order list data in JSON format: [ order: {id:123}, order: {id:456}, ] • URI cooking rules: – List_URI = ‘/orders’ – Order_URI = List_URI + order_list[n].order.id • Seems really simple for client app implementation, for now
  8. 8. Then lots client apps emerge … • From users, fans, solution providers, mashup makers… • 10s  100s  1000s … • Based on the simple “REST” API V1
  9. 9. After some time … • Some suggest implicit user id in session / cookie NOT a good idea … • That user_name should be included in URI
  10. 10. “REST” API V1.1 • Step 1: POST /login (user_name, password) – Session created • Step 2: GET /{user_name}/orders – Get Order List, with user name explicitly provided • Step 3: GET /{user_name}/orders/{order_id} – Get specific Order data through cooked URI • URI cooking rules: – User_name retrieved from client local input – List_URI = “/” + user_name + “/orders” – Order_URI = List_URI + order_list[n].order.id • Seems simple for client implementation still
  11. 11. But, what about old apps? • Just let them break? – Not Acceptable • Make sure Orders servlet maintain backward compatibility: – Retrieve user_name from request URI – If NOT provided, retrieve from session data instead • In the end, API V1 still works for old apps
  12. 12. Then after some time … • You decide to add a paid offerings: – Free accounts: • Data on the old host – Professional accounts: • Data moved to a new faster server • With a new domain name
  13. 13. DB Changes Users Table Orders Table for Free Users ID Name Type ID User_ID 1 Tom Free 123 1 2 Jerry Pro … … … … … Server 1: myorders.com Orders Table for Pro Users ID User_ID 456 2 … … Server 2: pro.myorders.com
  14. 14. “REST” API V2 • Step 1: POST /login (user_name, password) – Session created, with User_Type returned • Step 2: – Free accounts: GET /{user_name}/orders – Pro accounts: GET pro.myorders.com/{user_name}/orders • Step 3: – Free accounts: GET /{user_name}/orders/{order_id} – Pro accounts: GET pro.myorders.com/{user_name}/orders/{order_id} • URI cooking rules: – User_name retrieved from client-side input – User_type received from server, “free” or “pro” – List_URI = ((user_type == ‘pro’) ? ‘pro.myorders.com/’ : ‘/’) + user_name + ‘/orders’ – Order_URI = List_URI + order_list[n].order.id • Still ok for client implementation, nonetheless
  15. 15. Again, what about old apps? • Just let them break? – Still Not Acceptable • Modify Orders servlet logic again: – Retrieve domain & user_name from request URI – If NOT provided  API V1.0 • Retrieve user_name from session first, then • Lookup Users table to determine user_type, i.e., which DB to use – If only user_name provided  API V1.1 • Likewise, lookup Users table to determine which DB to use • In the end, API V1/V1.1 still works fine
  16. 16. As time goes by • You think it time for a VIP offering: – Free accounts: • Data on the old host – Professional accounts: • Data on a faster server • With a new domain name – VIP accounts: • Dedicated DB server • Custom domain name
  17. 17. DB Changes Users Table Orders Table for Free Users ID Name Type Domain ID User_ID 1 Tom Free N/A 123 1 2 Jerry Pro N/A … … 3 Susan VIP susan_test Server 1: myorders.com Orders Table for Pro Users Orders Tables for VIP User ID User_ID ID data 456 2 789 … … … … … Server 2: pro.myorders.com Server 3: susan_test.myorders.com Server 4: mikeabc.myorders.com Server 5: Alf_shop.myorders.com Server 6: anna_box.myorders.com
  18. 18. “REST” API V3 • Step 1: POST /login (user_name, password) – Session created, with User_Type, User_Domain returned • Step 2: – Free accounts: GET /{user_name}/orders – Pro accounts: GET pro.myorders.com/{user_name}/orders – VIP accounts: GET {user_domain}.myorders.com/orders • Step 3: – Free accounts: GET /{user_name}/orders/{order_id} – Pro accounts: GET pro.myorders.com/{user_name}orders/{order_id} – VIP accounts: GET {user_domain}.myorders.com/orders/{order_id} • URI cooking rules: – User_name retrieved from client-side input – User_type received from server, “free” or “pro” or “vip” – User_domain received from server, maybe null – List_URI = user_domain ? user_domain + ‘.myorders.com/orders’ : (user_type == ‘pro’ ? ‘pro.myorders.com/’ : ‘/’) + user_name + ‘/orders’ – Order_URI = List_URI + order_list[n].order.id • Seems not that simple for client anymore …
  19. 19. Again, what about old apps? • “We’ll support old client apps, as usual…” • Modify Orders servlet logic again: – Retrieve domain & user_name from request URI – If domain name is “Pro”  API V2/V3 • Use DB on pro.myorders.com – If domain name is not “Pro”  API V3 • Use DB on {domain_name}.myorders.com – If NOTHING is provided  API V1.0 • Retrieve user_name from session first, then • Then lookup Users table to get user_type, user_domain – If user_type is “Free”, use DB on myorders.com – If user_type is “Pro”, use DB on pro.myorders.com – If user_type is “VIP”, use DB on {user_domain}.myorders.com – If only user_name is provided  API V1.1 • Likewise, lookup Users table to determine which DB to use • In the end, API V1/V1.1/V2 still works fine, sadly …
  20. 20. Things Can Get Even More Complicated More requirements, more offerings, more functions, more features, more rules, clusters, load-balancers, data partitions, backups …
  21. 21. So Will Servlet Logic … And maintenance, logging, testing, trouble-shooting …
  22. 22. And Client App Implementation Cost
  23. 23. So What’s Wrong in the First Place?
  24. 24. “REST” API V1 • Step 1: POST /login (user_name, password) – Session created • Step 2: GET /orders – Get Order List, with user id implicitly provided in session – Should NOT let client assume the URI, if potential changes expected • Step 3: GET /orders/{order_id} – Get specific Order data through cooked URI – Should NOT let client assume the URI pattern , if potential changes expected • More assumptions allowed = More tightly coupling • Simple effort for one-time client implementation  possibly huge, on-going & ever-increasing liability for the server
  25. 25. A True REST API V0.1 Instead • Step 1: POST /login (user_name, password) – Session created, user related resource descriptions returned – User_Data: { name: “tom”, order_list_uri: “/tom/orders” } • Step 2: GET {User_Data.order_list_uri} – Retrieve order list data, sample data: – Order_List = [ order: {id:123, uri:“/tom/orders/123”} … ] • Step 3: GET {Order_List[n].order.uri} – Retrieve specific Order data through given URI
  26. 26. Same API Works across Various Account Types … Free Pro VIP POST /login POST /login POST /login User_Data: { User_Data: { User_Data: { name: “tom”, name: “jerry”, name: “susan”, order_list_uri: order_list_uri: order_list_uri: “/tom/orders” “pro.myorders.com/jerry/orders” “susan_test.myorders.com/orders” } } } GET /tom/orders GET pro.myorders.com/jerry/orders GET susan_test.myorders.com/orders Order_List = [ Order_List = [ Order_List = [ order: { order: { order: { id:123, id:456, id:789, uri:“/tom/orders/123” uri:“suasan_test.myorders.com/orders/78 } uri:“pro.myorders.com/jerry/orders/456”} 9”} ] ] ] GET /tom/orders/123 GET GET pro.myorders.com/jerry/orders/456 suasan_test.myorders.com/orders/7 89
  27. 27. … and Adaptable to Various Situations • Tom just upgrade from Free account to Pro, with bulk data migration scheduled later … And Tom can continue work across DBs Order_List = [ order:{ id:123, uri: ‘/tom/orders/123’ }, Data from different DBs mixed order:{ id:456, uri: ‘pro.myorders.com/tom/orders/456’ } ] • Pro.myorders.com is down for maintenance, and Pro_1 is up as backup … And users will hardly notice the change Order_List = [ order:{ id:123, uri: ‘pro_1.myorders.com/tom/orders/123’ } order:{ id:456, uri: ‘pro_1.myorders.com/tom/orders/456’ } ]
  28. 28. Put It Visually Imagine a Parking Lot
  29. 29. Different Zones for Different Parkers Free parkers Pro parkers VIP parker VIP parker VIP parker VIP parker VIP parker VIP parker VIP parker VIP parker Gate
  30. 30. A once-free-now-VIP Parker who cannot get rid of old habits … “Sir, your lot is in the VIP zone around the corner…” Pro parkers “!!!!...” “Since you’re VIP customer, we’ll redirect your car there for free …” Free parkers VIP parker VIP parker VIP parker VIP parker VIP parker VIP parker VIP parker VIP parker Gate
  31. 31. “REST” API without HATEOAS Be prepared to repeat this mess each and every day Pro parkers Free parkers VIP parker VIP parker VIP parker VIP parker VIP parker VIP parker VIP parker VIP parker Gate
  32. 32. A HATEOAS API Scenario Instructions to each customer each time Free parkers Pro parkers VIP parker VIP parker VIP parker VIP parker VIP parker VIP parker VIP parker UNDER CONSTRUCTION “Sir, your lot is being repaired, fortunately we’ve allocated a new one for you, here’s the route …” “I see, thanks a lot ” Gate
  33. 33. RPC vs. HATEOAS Not necessarily future-proof but more efficient for now Free Gate Pro Gate Free parkers Pro parkers VIP parker VIP parker VIP parker VIP parker VIP parker VIP parker VIP parker VIP parker VIP Gate Old Gate Blocked Old client: “!@#$$#%^&^%!!!!”
  34. 34. Take Away • HATEOAS is essential, for – APIs as well as internal organization of complex systems that may evolve over time – In order to minimize maintenance cost and support old client apps • However, mind that – Loose coupling  less efficiency • So, if you’re 100% sure something will never change, e.g., /login as login URL, just let everyone assume it forever
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×