API REST có thể trả về nhiều tài nguyên dưới dạng một tài nguyên hỗn hợp không?


10

Tôi đang trong quá trình tạo API REST và hiện tại, tôi đang gặp phải sự cố sau:

  • Foolà tài nguyên đầu tiên. Hoạt động CRUD có thể được áp dụng thông qua /foo/URI.
  • Barlà tài nguyên thứ hai. Hoạt động CRUD có thể được áp dụng thông qua /bar/URI.
  • Mỗi Foođược liên kết với không hoặc một Bar. Lý do tại sao tôi không coi Barlà nguồn cung cấp phụ Foolà bởi vì cùng một Bartrường hợp có thể được chia sẻ giữa Foocác môn sinh. Vì vậy, tôi nghĩ rằng tốt hơn là truy cập nó thông qua một URI độc lập thay vì /foo/[id]/bar.

Vấn đề của tôi là trong một số lượng đáng kể các trường hợp, khách hàng yêu cầu một Fooví dụ cũng quan tâm đến Bartrường hợp liên quan . Hiện tại, điều này có nghĩa là họ phải thực hiện hai truy vấn thay vì một truy vấn. Tôi muốn giới thiệu một cách cho phép nhận cả hai đối tượng với một truy vấn duy nhất, nhưng tôi không biết cách mô hình hóa API để thực hiện điều đó. Những gì tôi đã đưa ra cho đến nay:

  • Tôi có thể giới thiệu một tham số truy vấn tương tự như sau : /foo/[id]?include_bar=true. Vấn đề với cách tiếp cận này là biểu diễn tài nguyên (ví dụ cấu trúc JSON) của phản hồi sẽ cần trông khác nhau (ví dụ: một thùng chứa { foo: ..., bar: ... }thay vì chỉ là một chuỗi Foo), làm cho Foođiểm cuối tài nguyên trở nên "không đồng nhất". Tôi không nghĩ đó là một điều tốt. Khi truy vấn /foo, khách hàng phải luôn có cùng biểu diễn tài nguyên (cấu trúc), bất kể tham số truy vấn.
  • Một ý tưởng khác là giới thiệu một điểm cuối chỉ đọc mới, ví dụ /fooandbar/[foo-id]. Trong trường hợp này, không có vấn đề gì khi trả về một đại diện như thế { foo: ..., bar: ... }, bởi vì đó chỉ là đại diện "chính thức" của fooandbartài nguyên. Tuy nhiên, tôi không biết liệu điểm cuối của người trợ giúp như vậy có thực sự RESTful không (đây là lý do tại sao tôi viết "có thể" trong tiêu đề của câu hỏi. Tất nhiên là về mặt kỹ thuật có thể, nhưng tôi không biết liệu đó có phải là ý hay không).

Bạn nghĩ sao? Có khả năng nào khác không?


Thuật ngữ cho mối quan hệ giữa Foo và Bar là gì? Bạn có thể nói rằng Bar là cha mẹ của Foo không?
Nathan Merrill

A Barkhông thể tồn tại mà không được liên kết với a Foo. Tuy nhiên, như tôi đã viết ở trên, có thể nhiều người Foochia sẻ giống nhau Bar. Có thể tạo ra Foomà không có Barliên kết, vì vậy tôi không nghĩ Barnên được coi là cha mẹ.
ceran

1
Tôi nghĩ rằng bạn đang gặp một số vấn đề tôi gặp phải bằng cách dịch trực tiếp các mối quan hệ mô hình miền thành URI và đánh đồng tài nguyên cho các thực thể miền . Nó có thể quan tâm API REST phải được điều khiển siêu văn bản . Đặc biệt chú ý đến điểm thứ 4
Laiv 10/11/2016

Câu trả lời:


6

Một mức 3 REST API sẽ trả lại cho bạn một Foovà cũng là một liên kết cho thấy sự liên quan Bar.

GET /foo/123
<foo id="123">
  ..foo stuff..
  <link rel="bar" uri="/bar/456"/>
</foo>

Sau đó, bạn có thể thêm tính năng "truy sâu xuống" vào API của mình, cho phép điều hướng các liên kết;

GET /foo/123?drilldown=bar
<foo id="123">
  ..foo stuff..
  <link rel="bar" uri="/bar/456">
    <bar id="456">
      ..bar stuff...
    </bar>
  </link>
</foo>

Tính năng truy sâu xuống sẽ nằm trước các API và chặn các phản hồi. Nó sẽ thực hiện các cuộc gọi đi sâu và điền thông tin chi tiết trước khi trả lời lại cho người gọi.

Đây là một điều khá phổ biến trong REST cấp 3 vì nó làm giảm sự chậm chạp của máy khách / máy chủ so với http chậm. Công ty tôi làm việc để sản xuất API REST cấp 3 với chính xác tính năng này.

Cập nhật: Để biết giá trị của nó, đây là giao diện của JSON. Đây là cách API của chúng tôi sẽ cấu trúc nó. Lưu ý rằng bạn có thể lồng các mũi khoan của mình để kéo các liên kết của các liên kết, v.v.

GET /foo/123?drilldown=bar

{
  "self": {
    "type": "thing.foo",
    "uri": "/foo/123=?drilldown=bar",
    "href": "http://localhost/api/foo/123?drilldown=bar"
  },
  "links": [
    {
      "rel": "bar",
      "rev": "foo",
      "type": "thing.bar",
      "uri": "/bar/456",
      "href": "http://localhost/api/bar/456"
    }
  ],
  "_bar": [
    {
      "self": {
        "type": "thing.bar",
        "uri": "/bar/456",
        "href": "http://localhost/api/bar/456"
      },
      "links": [
        {
          ..other link..
        },
        {
          ..other link..
        }
      ]
    }
  ]
}

Thật thú vị, tôi đã sử dụng các liên kết / điều khiển hypermedia để loại bỏ khớp nối chặt chẽ với các URI, nhưng tôi chưa nghĩ đến ý tưởng "đi sâu vào" có vẻ rất hứa hẹn. Hiện tại, mỗi biểu diễn JSON có thể trông như thế nào? Hiện tại, mỗi biểu diễn JSON của tài nguyên của tôi chứa một linksmảng, mỗi mục nhập là một đối tượng liên kết với một relvà một uritrường (tương tự như ví dụ xml của bạn). Tôi có nên thêm trường thứ ba cho mỗi đối tượng liên kết (ví dụ data) không? Có tiêu chuẩn nào không?
ceran

Việc đi sâu không thực sự là một tính năng nghỉ ngơi, vì vậy không có tiêu chuẩn nào (ít nhất là tôi biết).
Qwerky

Có một số tiêu chuẩn được đề xuất, chẳng hạn như statless.co/hal_specification.html mà tôi đang sử dụng trong các ứng dụng của mình. Nó rất gần với ví dụ của bạn.
Pete Kirkham

4

Nếu 95% của tất cả các thắc mắc muốn Foocũng như Bar, sau đó chỉ cần gửi lại bên trong của Foođối tượng khi bạn yêu cầu một Foo. Chỉ cần thêm một thuộc tính bar(hoặc một số thuật ngữ khác cho mối quan hệ) và đặt Barđối tượng ở đó. Nếu mối quan hệ không tồn tại, sau đó sử dụng null.

Tôi nghĩ rằng bạn đang xem xét lại điều này :)


Tôi không nên nghĩ ra con số đó (95%), đó là một sai lầm, xin lỗi. Điều tôi muốn nói là một phần lớn các yêu cầu quan tâm đến cả hai tài nguyên cùng một lúc. Nhưng vẫn còn một số lượng yêu cầu có liên quan chỉ quan tâm Foovà vì mỗi yêu cầu Barkhá lớn trong bộ nhớ (khoảng 3x-4x kích thước Foo), tôi không muốn trả lại Barnếu khách hàng không yêu cầu rõ ràng.
ceran

Chúng ta đang nói chuyện lớn như thế nào? Tôi nghi ngờ rằng nó sẽ làm cho rằng nhiều sự khác biệt trong thời gian chuyển giao, và tôi muốn có một API sạch hơn tốc độ
Nathan Merrill
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.