链接到REST API中的另一个资源:通过其ID或URL?

时间:2015-06-22 13:51:53

标签: json api rest api-design hateoas

我正在使用创建一些API,因此使用的语言是JSON。

我们假设我需要代表这个资源:

{
    "id" : 9,
    "name" : "test",
    "customer_id" : 12,
    "user_id" : 1,
    "store_id" : 3,
    "notes" : "Lorem ipsum example long text"
}

通过ID(1213)引用其他资源是否正确,或者我应指定这些资源的网址(即/customers/12/users/1/stores/3)?

我没有使用HATEOAS而且我有点困惑。

2 个答案:

答案 0 :(得分:15)

DO 在您的回复中包含absolute个实体URI(例如/customers/12甚至http://www.example.com/customers/12)。

不要在响应中只包含实体的ID(例如12),因为这样会迫使客户自己将资源URI放在一起。为了做到这一点,他们需要事先知道有什么URI,并且你失去了对服务器端URI空间的控制。

(如果服务器指示客户端如何,例如通过发送URI template以及ID,那么将客户端放在一起就可以了;但如果它这样做,它也可以发送结果URI 。)

另见:

  • Article "REST APIs must be hypertext-driven" by Roy T. Fielding(REST的发起人)。特别注意这两个要点:

      
        
    • “应输入REST API,除了初始URI(书签)之外没有任何先验知识。”
    •   
    • “REST API不能定义固定资源名称或层次结构(客户端和服务器的明显耦合)。服务器必须能够自由控制自己的命名空间。相反,允许服务器指示客户端如何构造适当的URI [。]“
    •   
  • HAL,指定将相关资源的链接放入回复的标准方法。

  • JSON API - “使用JSON构建API的规范”

  • 以上建议不仅适用于其他资源的ID(即“外键”,例如您的customer_id);你也将资源自己的id变成了所谓的“自我链接”;请参阅SO question "What is the importance of the self link in hypermedia APIs?"

示例:

您的原始资源可以按照以下方式重新设计:

{
  "type": "foobar",
  "id": "9",
  "links": {
    "self": "//example.com/foobars/9"
  },
  "cashier": {
    "type": "user",
    "id": "1",
    "links": {
      "self": "//example.com/users/1"
    }
  },
  "customer": {
    "type": "customer",
    "id": "12",
    "links": {
      "self": "//example.com/customers/12"
    }
  },
  "name" : "test",
  "notes" : "Lorem ipsum example long text",
  "store": {
    "type": "store",
    "id": "3",
    "links": {
      "self": "//example.com/stores/3"
    }
  }
}

有几点需要注意:

  • 每个资源(正在传输的主要对象,以及子资源)都附加了一些自描述性元数据,例如typeidlinks
  • 子资源可包括部分或完整数据。只要存在自我链接,客户端就知道从哪里获得完整的资源。
  • type似乎有点减少;通常,你隐含地知道期望什么样的对象。此属性可以帮助验证,还使您有机会区分对象类型和角色(例如,上例中的cashier是一个user。)

答案 1 :(得分:5)

我看过其他流行的API(Facebook,Spotify),我相信以下是最好的方法:

{
   "id" : 9,
   "name" : "test",
   "customer" : {
      "id": 12,
      "href": "/customers/12"
   },
   "user" : {
      "id": 1,
      "href": "/users/1"
   },
   "store" : {
      "id": 3,
      "href": "/stores/3"
   },
   "notes" : "Lorem ipsum example long text"
}