Gradual reveal in REST APIs [closed]

In the article Building Web Services the REST Way, the author states:

Design to reveal data gradually. Don't reveal everything in a single response document. Provide hyperlinks to obtain more details.

Why is this considered a good practice?

UPDATE: I realize that this practice is also known as HATEOAS.

2

I think the main advantage you gain when following this principle is the API’s browsability. If different resources are interconnected in this way, you only need to provide a couple of entry points (well known URLs that provide clients a way to start exploring your API) and the clients are virtually free from the responsibility of building URLs. You can just provide them with links.

Another important point is that with each link, you can provide some semantically significant description that describes the nature of the link. This is a good way to describe relationships between resources.

Consider the following examples:

A non-granular approach

GET /users/1
Response:
{
    "id": 1,
    "name" : "Tom"
    "addresses" : [
        { 
            "id" : "1",
            "email" : "[email protected]",
            "street" : "Sesame Street",
            "city" : "London",
            "country" : "United Kingdom"
        }
    ],
    "posts" : [
         {
            "id" : "1",
            "title" : "HATEOAS Examples",
            "content" : "Yada yada yada",
            "created" : "2014-01-01"
         },
         {
            "id" : "2",
            "title" : "Foo bar baz",
            "content" : "Lorem ipsum dolor",
            "created" : "2014-01-05"
         },
         // many many more
    ]
}
  • How do I limit the number of posts I retrieve?
  • How do I limit the number of addresses bound to my profile that I retrieve?
  • How do I delete an address related to my profile?
  • How do I update a post?
  • How do I get the posts from a specific day?
  • Can you cache this entire response? When to invalidate the cache?

You cannot immediately tell how to do any of these things. Trying to implement them using a non-granular API like this, you’ll and up with numerous parameters that are not really specific to the resource you’re fetching and the user of your API will have to spend a lot of time browsing the documentation just to render an appropriate interface for the end user to interact with an API like this.

A hierarchy of granular, interconnected resources

Now consider the sub-resources as separate, discoverable entities. The data is revealed gradually, as the consumer performs further requests.

GET /users/1
Response:
{
    "id": 1,
    "name" : "Tom",
    "self" : "/users/1",
    "links" : [
        { "rel" : "addresses", "url" : "/users/1/addresses" },
        { "rel" : "posts", "url" : "/posts?user=1" },
        { "rel" : "all.users", "url" : "/users" }
    ]
}

And the separate resources:

All addresses

 GET /users/1/addresses
 Response:
 {
     "title" : "Tom's addresses",
     "self" : "/users/1/addresses",
     "links" : [
         { "rel" : "user", "/users/1" }
         { "rel" : "address", "/users/1/addresses/1"}
     ]
 }

A single address

 GET /users/1/addresses/1
 Response:
 {
     "id" : "1",
     "email" : "[email protected]",
     "street" : "Sesame Street",
     "city" : "London",
     "country" : "United Kingdom",
     "self" : "/users/1/addresses/1"
     "links" : {
         { "rel" : "all.addresses", "/users/1/addresses" },
         { "rel" : "update.form", "/users/1/addresses/1/update-form" },
     }
 }

All posts

GET /posts?user=1
Response:
{
    "title" : "Tom's posts",
    "self" : "/posts?user=1",
    "links" : [
        { "rel" : "user", "/users/1" },
        { "rel" : "post", "url" : "/posts/1" },
        { "rel" : "post", "url" : "/posts/2" },
        // many more            
    ]
}

Example single post

GET /posts/1
Response
{
    "title" : "HATEOAS Examples",
    "content" : "Yada yada yada",
    "created" : "2014-01-01",
    "self" : "/posts/1",
    "links" : [
        { "rel" : "user", "url" : "/users/1" },
        { "rel" : "user.all.posts", "url" : "/posts?user=1" }
        { "rel" : "edit.form", "url" : "posts/1/edit-form" }
    ]
}

Again, the same questions:

  • How do I limit the number of posts I retrieve? – Now you can have an application-wide parameters to handle pagination, say, limit and offset. You can provide these already embedded into various links. Even if you don’t, such a convention is very easy to adopt by API consumers.
  • How do I limit the number of addresses bound to my profile that I retrieve? – Same as above, no need for additional parameters to remember.
  • How do I delete an address related to my profile? – Obtain the rel link to the address and issue a DELETE request, again, this can be an application-wide convention. You can just follow links and delete whatever you can. Another way would be to provide additional metadata, you could easily provide a link with additional information saying that a DELETE request is allowed for the resource linked… or maybe make this a property of a resource and not a link itself. Ideally, you could serve such information in response to OPTIONS requests. Either way, it’s easy to understand by API consumers.
  • How do I update a post? – You can provide a link to a form, this can be a piece of HTML you prepared or even a JSON/XML response with information on how to render a form like this (this can be used by non-browser clients)
  • Can you cache this entire response? When to invalidate the cache? You can cache every single one of these responses. An update of a small, lightweight resource, like changing a post title does not require you to recreate a huge response. You also need to invalidate caches when a resource linked to something is created or deleted (to update the links).

What I like the most about this approach is that it’s easy to understand and using the API feels like browsing a website. This allows you to drive the application state using just the responses. The consumer just needs to follow the links you provide to move around.

It’s much harder for a client of such an API to break when you change something. Even if you decide to move some resources around and change their links, the clients can use their relationships, which are generally much more inert. Particularly if you use well-thought-out relations. I didn’t go this far in the examples above but in a real API, you should ideally take a look around and see what known link relations you could use. IANA keeps a registry of those. Reusing standardized links will make it easier for others to understand your API (especially if they know other APIs using them) and it will save you the work of documenting the relations (you can just point to the right RFC or other applicable document)

Potential Pitfalls

Of course none of this comes for free. Creating an API like this is not easy and it may cost you a lot of effort.

APIs designed this way tend to be more difficult to build and understand. Scalability and flexibility are very important in public APIs, for which many clients can be written by unrelated parties. This is where you can gain the most by properly using hypermedia. However, if your API is only to be consumed within your company or even in a single intranet solution, you might prefer to save yourself the effort and opt for an easy to implement (or even generate out of a service description document) design that relies on human-readable documentation and conventions rather than rich hypermedia. There’s nothing wrong with betraying the principles of REST if your use case really calls for it. Just don’t say your API is RESTful when you do so.

Another downside of this approach is the sheer amount of calls using an API like this requires. The impact of this is reduced by the API’s cache-ability and scalability. If this isn’t enough, you can consider providing the user with a way to reach deeper into the hierarchy (like, provide a parameter instructing the server to embed some of the linked resources into the single response server-side)

Some resources you might find interesting:

  • Richardson’s Maturity Model
  • The Netflix REST API using rel links in a similar manner
  • An article describing the usage of a REST API
  • An Apigee article on HATEOAS
  • A stackoverflow answer to a similar question about HATEOAS
  • Roy Fielding’s very own blog post on the importance of hypertext in REST

I can also wholeheartedly recommend RESTful Web APIs by Amundsen, Richardson and Ruby. Hypermedia and its proper use in RESTful APIs is the key subject of the book.

1

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa

Gradual reveal in REST APIs [closed]

In the article Building Web Services the REST Way, the author states:

Design to reveal data gradually. Don't reveal everything in a single response document. Provide hyperlinks to obtain more details.

Why is this considered a good practice?

UPDATE: I realize that this practice is also known as HATEOAS.

2

I think the main advantage you gain when following this principle is the API’s browsability. If different resources are interconnected in this way, you only need to provide a couple of entry points (well known URLs that provide clients a way to start exploring your API) and the clients are virtually free from the responsibility of building URLs. You can just provide them with links.

Another important point is that with each link, you can provide some semantically significant description that describes the nature of the link. This is a good way to describe relationships between resources.

Consider the following examples:

A non-granular approach

GET /users/1
Response:
{
    "id": 1,
    "name" : "Tom"
    "addresses" : [
        { 
            "id" : "1",
            "email" : "[email protected]",
            "street" : "Sesame Street",
            "city" : "London",
            "country" : "United Kingdom"
        }
    ],
    "posts" : [
         {
            "id" : "1",
            "title" : "HATEOAS Examples",
            "content" : "Yada yada yada",
            "created" : "2014-01-01"
         },
         {
            "id" : "2",
            "title" : "Foo bar baz",
            "content" : "Lorem ipsum dolor",
            "created" : "2014-01-05"
         },
         // many many more
    ]
}
  • How do I limit the number of posts I retrieve?
  • How do I limit the number of addresses bound to my profile that I retrieve?
  • How do I delete an address related to my profile?
  • How do I update a post?
  • How do I get the posts from a specific day?
  • Can you cache this entire response? When to invalidate the cache?

You cannot immediately tell how to do any of these things. Trying to implement them using a non-granular API like this, you’ll and up with numerous parameters that are not really specific to the resource you’re fetching and the user of your API will have to spend a lot of time browsing the documentation just to render an appropriate interface for the end user to interact with an API like this.

A hierarchy of granular, interconnected resources

Now consider the sub-resources as separate, discoverable entities. The data is revealed gradually, as the consumer performs further requests.

GET /users/1
Response:
{
    "id": 1,
    "name" : "Tom",
    "self" : "/users/1",
    "links" : [
        { "rel" : "addresses", "url" : "/users/1/addresses" },
        { "rel" : "posts", "url" : "/posts?user=1" },
        { "rel" : "all.users", "url" : "/users" }
    ]
}

And the separate resources:

All addresses

 GET /users/1/addresses
 Response:
 {
     "title" : "Tom's addresses",
     "self" : "/users/1/addresses",
     "links" : [
         { "rel" : "user", "/users/1" }
         { "rel" : "address", "/users/1/addresses/1"}
     ]
 }

A single address

 GET /users/1/addresses/1
 Response:
 {
     "id" : "1",
     "email" : "[email protected]",
     "street" : "Sesame Street",
     "city" : "London",
     "country" : "United Kingdom",
     "self" : "/users/1/addresses/1"
     "links" : {
         { "rel" : "all.addresses", "/users/1/addresses" },
         { "rel" : "update.form", "/users/1/addresses/1/update-form" },
     }
 }

All posts

GET /posts?user=1
Response:
{
    "title" : "Tom's posts",
    "self" : "/posts?user=1",
    "links" : [
        { "rel" : "user", "/users/1" },
        { "rel" : "post", "url" : "/posts/1" },
        { "rel" : "post", "url" : "/posts/2" },
        // many more            
    ]
}

Example single post

GET /posts/1
Response
{
    "title" : "HATEOAS Examples",
    "content" : "Yada yada yada",
    "created" : "2014-01-01",
    "self" : "/posts/1",
    "links" : [
        { "rel" : "user", "url" : "/users/1" },
        { "rel" : "user.all.posts", "url" : "/posts?user=1" }
        { "rel" : "edit.form", "url" : "posts/1/edit-form" }
    ]
}

Again, the same questions:

  • How do I limit the number of posts I retrieve? – Now you can have an application-wide parameters to handle pagination, say, limit and offset. You can provide these already embedded into various links. Even if you don’t, such a convention is very easy to adopt by API consumers.
  • How do I limit the number of addresses bound to my profile that I retrieve? – Same as above, no need for additional parameters to remember.
  • How do I delete an address related to my profile? – Obtain the rel link to the address and issue a DELETE request, again, this can be an application-wide convention. You can just follow links and delete whatever you can. Another way would be to provide additional metadata, you could easily provide a link with additional information saying that a DELETE request is allowed for the resource linked… or maybe make this a property of a resource and not a link itself. Ideally, you could serve such information in response to OPTIONS requests. Either way, it’s easy to understand by API consumers.
  • How do I update a post? – You can provide a link to a form, this can be a piece of HTML you prepared or even a JSON/XML response with information on how to render a form like this (this can be used by non-browser clients)
  • Can you cache this entire response? When to invalidate the cache? You can cache every single one of these responses. An update of a small, lightweight resource, like changing a post title does not require you to recreate a huge response. You also need to invalidate caches when a resource linked to something is created or deleted (to update the links).

What I like the most about this approach is that it’s easy to understand and using the API feels like browsing a website. This allows you to drive the application state using just the responses. The consumer just needs to follow the links you provide to move around.

It’s much harder for a client of such an API to break when you change something. Even if you decide to move some resources around and change their links, the clients can use their relationships, which are generally much more inert. Particularly if you use well-thought-out relations. I didn’t go this far in the examples above but in a real API, you should ideally take a look around and see what known link relations you could use. IANA keeps a registry of those. Reusing standardized links will make it easier for others to understand your API (especially if they know other APIs using them) and it will save you the work of documenting the relations (you can just point to the right RFC or other applicable document)

Potential Pitfalls

Of course none of this comes for free. Creating an API like this is not easy and it may cost you a lot of effort.

APIs designed this way tend to be more difficult to build and understand. Scalability and flexibility are very important in public APIs, for which many clients can be written by unrelated parties. This is where you can gain the most by properly using hypermedia. However, if your API is only to be consumed within your company or even in a single intranet solution, you might prefer to save yourself the effort and opt for an easy to implement (or even generate out of a service description document) design that relies on human-readable documentation and conventions rather than rich hypermedia. There’s nothing wrong with betraying the principles of REST if your use case really calls for it. Just don’t say your API is RESTful when you do so.

Another downside of this approach is the sheer amount of calls using an API like this requires. The impact of this is reduced by the API’s cache-ability and scalability. If this isn’t enough, you can consider providing the user with a way to reach deeper into the hierarchy (like, provide a parameter instructing the server to embed some of the linked resources into the single response server-side)

Some resources you might find interesting:

  • Richardson’s Maturity Model
  • The Netflix REST API using rel links in a similar manner
  • An article describing the usage of a REST API
  • An Apigee article on HATEOAS
  • A stackoverflow answer to a similar question about HATEOAS
  • Roy Fielding’s very own blog post on the importance of hypertext in REST

I can also wholeheartedly recommend RESTful Web APIs by Amundsen, Richardson and Ruby. Hypermedia and its proper use in RESTful APIs is the key subject of the book.

1

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật