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

MeV*_*MeV 8 api rest json api-design hateoas

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

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

{
    "id" : 9,
    "name" : "test",
    "customer_id" : 12,
    "user_id" : 1,
    "store_id" : 3,
    "notes" : "Lorem ipsum example long text"
}
Run Code Online (Sandbox Code Playgroud)

难道是正确的根据ID引用其他资源(12,1,3),或者我应该指定这些资源的URL(即/customers/12,/users/1,/stores/3)?

我没有使用HATEOAS,我有点困惑.

sta*_*ica 18

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

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

(如果服务器指示客户端如何,例如通过发送URI模板和ID,那么客户端将URI放在一起就可以了;但如果它这样做,它也可以发送生成的URI.)

也可以看看:

  • Roy T.Fielding(REST的创始人)的文章"REST API必须由超文本驱动".特别注意这两个要点:

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

  • JSON API - "用于在JSON中构建API的规范"

  • 上述建议不仅适用于其他资源的ID(即您的"外键" customer_id); 你也将资源自己id变成了一个所谓的"自我链接"; 看到SO问题"超媒体API中自我链接的重要性是什么?" .

例:

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

{
  "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"
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

有几点需要注意:

  • 每个资源(主对象被转移,也子资源)具有一些自描述性的元数据连接到它,例如type,id,links.
  • 子资源可以包括部分或完整数据.只要存在自我链接,客户端就知道从哪里获得完整的资源.
  • type可能似乎有点redudant; 通常,你隐含地知道期望什么样的对象.此属性可以帮助验证,还使您有机会区分对象类型和角色(例如,上例中的cashieris-a user).


MeV*_*MeV 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"
}
Run Code Online (Sandbox Code Playgroud)