我应该如何处理 RESTful API 中的对象层次结构?

我目前正在为一个现有的 PHP 应用程序设计 API,为此我正在研究 REST 作为一种合理的体系结构方法。

我相信我已经对关键概念有了一个合理的理解,但是我正在努力寻找那些解决了对象层次结构和 REST 的人。

问题是..。

在[应用程序]业务对象层次结构中,我们有:

Users
L which have one-to-many Channel objects
L which have one-to-many Member objects
 

在应用程序本身中,我们使用一种延迟加载方法,根据需要用这些对象的数组填充 User 对象。我相信在面向对象的术语中,这是对象聚合,但我看到了各种不一致的命名,并不在乎开始一场关于精确变数命名原则 的战争。

现在,考虑一下我有一些松散耦合的对象,根据应用程序的需要,我可以填充它们,也可以不填充它们。

从 REST 的角度来看,我试图确定应该采用什么样的方法。以下是我目前的想法(暂时只考虑 GET) :

选项1-充分填充对象:

GET api.example.com/user/{user_id}

读取 User 对象(资源)并返回 User 对象,其中包含预加载和编码的所有可能的 Channel 和 Member 对象(JSON 或 XML)。

优点: 减少对象的数量,不需要遍历对象层次结构
缺点: 对象必须完全填充(代价高昂)

选项2-填充主对象并包含到其他对象资源的链接:

GET api.example.com/user/{user_id}

读取 User 对象(资源)并返回 User 对象 User 数据填充和两个列表。

每个列表引用适当的(子)资源,即。

api.example.com/channel/{channel_id}
api.example.com/member/{member_id}
    

我认为这与超媒体的含义非常接近(或者确切地说)——客户可以根据需要获得其他资源(只要我合理地标记它们)。

支持: 客户端可以选择加载下属或其他方式,更好地将对象分离为 REST 资源
缺点: 需要进一步的旅行才能获得备用资源

选项3-启用递归检索

GET api.example.com/user/{user_id}

阅读 User 对象并包含子对象列表的链接,即。

api.example.com/user/{user_id}/channels
api.example.com/user/{user_id}/members

通道调用将返回表单中的通道资源列表(如上所示) :

api.example.com/channel/{channel_id}
    

支持: 主要资源暴露了从哪里获得下属,而不是他们是什么(更多的 RESTful?),不需要让下属提前,下属列表生成器(/channel 和/member)提供接口(类似方法) ,使响应更像服务。
反对: 现在需要三个调用来完全填充对象

选项4-(重新)考虑 REST 的对象设计

我正在重用[现有的]应用程序对象层次结构,并试图将其应用于 REST ——或者更直接地,为其提供一个 API 接口。

也许 REST 对象层次结构应该有所不同,或者新的 RESTful 思想暴露了现有对象设计的局限性。

欢迎对上述问题有任何想法。

30862 次浏览

There's no reason not to combine these.

  • api.example.com/user/{user_id} – return a user representation
  • api.example.com/channel/{channel_id} – return a channel representation
  • api.example.com/user/{user_id}/channels – return a list of channel representations
  • api.example.com/user/{user_id}/channel_list – return a list of channel ids (or links to their full representations, using the above links)

When in doubt, think about how you would display the data to a human user without "API" concerns: a user wants both index pages ({user_id}/channel_list) and full views ({user_id}/channels).

Once you have that, just support JSON instead of (or in addition to) HTML as the representation format, and you have REST.

The best advice I can give is to try and avoid thinking about your REST api as exposing your objects. The resources you create should support the use cases you need. If necessary you might create resources for all three options:

api.example.com/completeuser/{id}
api.example.com/linkeduser/{id}
api.example.com/lightweightuser/{id}

Obviously my names are a bit goofy, but it really doesn't matter what you call them. The idea is that you use the REST api to present data in the most logical way for the particular usage scenario. If there are multiple scenarios, create multiple resources, if necessary. I like to think of my resources more like UI models rather than business entities.

Here's my conclusions from many hours searching and with input from the responders here:

Where I have an object that is effectively a multi-part object, I need to treat that as a single resource. Thus if I GET the object, all the sub-ordinates should be present. This is required in order that the resource is cacheable. If I part load the object (and provide an ETag stamp) then other requestors may receive a partial object when they expected a full one. Conclude - objects should be fully populated if they are being made available as resources.

Associated object relationships should be made available as links to other (primary) resources. In this way the objects are discoverable by traversing the API.

Also, the object hierarchy that made sense for main application site may appear not be what you need to act in RESTful manner, but is more likely revealing problems with the existing hierarchy. Having said this the API may require more specialised use cases than had been previously envisaged, and specialised resources may be required.

Hope that helps someone

I would recommend Restful Obects which is standards for exposing domain model's restful

The idea of Restful Objects is to provide a standard, generic RESTful interface for domain object models, exposing representations of their structure using JSON and enabling interactions with domain object instances using HTTP GET, POST, PUT and DELETE.

According to the standard, the URIs will be like:

  • api.example.com/object/user/31
  • api.example.com/object/user/31/properties/username
  • api.example.com/object/user/31/collections/channels
  • api.example.com/object/user/31/collections/members
  • api.example.com/object/user/31/actions/someFunction
  • api.example.com/object/user/31/actions/someFunction/invoke

There are also other resources

  • api.example.com/services
  • api.example.com/domain-types

The specification defines a few primary representations:

  • object (which represents any domain object or service)
  • list (of links to other objects)
  • property
  • collection
  • action
  • action result (typically containing either an object or a list, or just feedback messages)
  • and also a small number of secondary representations such as home, and user

This is interesting as you’ll see that representations are fully self-describing, opening up the possibility of generic viewers to be implemented if required.

Alternatively, the representations can be consumed directly by a bespoke application.