API RESTful đại diện cho sự vắng mặt của một thứ


18

Hãy tưởng tượng một API để xác định xem một người đã chọn động vật linh hồn của họ hay chưa. Họ chỉ có thể có không hoặc một động vật tinh thần.

Hiện tại:

/person/{id}/selectedSpiritAnimal

khi họ đã chọn một con vật trả về http 200 và {selectedAnimal:mole}

nhưng khi họ không có lựa chọn thì nó trả về http 404.

Điều này làm cho động vật tinh thần của tôi không hài lòng vì chúng tôi đại diện cho một mối quan tâm miền hợp lệ - chưa chọn một động vật tinh thần - là một lỗi HTTP.

Thêm vào đó, với tư cách là một doanh nghiệp - erm Sprit-Animal-Hampers-R-us - chúng tôi muốn biết khi ai đó không có lựa chọn để chúng tôi có thể nhắc họ.

Thật là một phản ứng tốt hơn ở đây:

HTTP 200 và {selectedAnimal:null}

hoặc thậm chí rõ ràng hơn

HTTP 200 và {selectedAnimal:null, spiritAnimalSelected: false}

Hoặc tốt hơn là trả lại 404? Vì rất giống this image has not yet been uploadedkhi xem hình ảnh trực tuyến sẽ là 404. this person has not selected a spirit animalcó thể là 404


Câu hỏi này đã được đề xuất dưới dạng trùng lặp nhưng câu hỏi đó giải quyết một URL hợp lệ khác được yêu cầu khi ứng dụng được định cấu hình để không cho phép thay đổi mà URL thể hiện.

Trong khi đó ở đây tôi đang xem làm thế nào một người đại diện cho một tài nguyên mà sự vắng mặt của tài nguyên đó có ý nghĩa. Tức là khách hàng có thể yêu cầu URL và phản hồi là bạn đã yêu cầu thành công tài nguyên thể hiện sự vắng mặt của một thứ.

Vì vậy, đây không phải là 'logic kinh doanh' mà là một tình huống mà sự vắng mặt của một thứ có ý nghĩa (có thể là do nhiều đồng nghiệp của tôi cho rằng 404 vẫn đúng) nhưng tôi không chắc làm thế nào để ánh xạ nó tới thông số kỹ thuật


Rất khó để chọn một câu trả lời. Tôi đã thay đổi suy nghĩ của mình nhiều lần trong cuộc trò chuyện ở đây và cuộc trò chuyện đang diễn ra.

Điều giải quyết nó cho tôi ở đây là thông số kỹ thuật nói rằng 4xx là khi máy khách bị lỗi . Trong trường hợp này, máy khách đã được yêu cầu mong đợi một phản hồi từ url được chọn SpriteAnimal để không bị lỗi.

Sự đồng thuận giữa các đồng nghiệp của tôi là đây là một triệu chứng của một thiết kế API xấu

Có lẽ tốt hơn là chúng tôi chỉ cần yêu cầu / người / {id} và trả về một tập hợp các mối quan hệ liên kết cho người đó ... sau đó nếu bạn không được cung cấp liên kết / chọnSpriteAnimal (khi một người không có lựa chọn) nhưng bạn hãy gọi nó bằng mọi cách sau đó 404 có ý nghĩa. Hoặc là bạn triển khai các phản hồi một phần và cho phép / person / {id} trả về một tài liệu đầy đủ hơn trừ khi khách hàng yêu cầu một tập hợp con của dữ liệu


5
Bạn chưa giải thích lý do tại sao bạn tin rằng đó là vấn đề khi trả về 404. Từ quan điểm tên miền, bạn không biết liệu bạn đã nhận được 404 hay 200, được trừu tượng hóa bởi lớp máy khách.
Vincent Savard

14
hoặc có lẽ tốt hơn là trả lại 204 không có nội dung?
Paul D'Ambra

6
Tôi cho rằng sự lo lắng của tôi với 404 đang làm thay đổi cấu hình thay đổi giới thiệu một mẫu URL xấu từ một người không có động vật tinh thần
Paul D'Ambra

2
@ PaulD'Ambra Vì những gì đáng giá, tôi sẽ không sử dụng nội dung không có nội dung. Tôi chưa thấy mã HTTP được xử lý ở mặt trước theo cách đó trong Javascript kể từ những ngày XmlHttpRequest. Nhưng nó chắc chắn là hợp lệ.
Brandon Arnold

Câu trả lời:


24

Mã HTTP 4xx có lẽ không phải là lựa chọn phù hợp cho kịch bản này. Bạn tuyên bố rằng có động vật không có tinh thần là trạng thái hợp lệ và tuyến API person/{id}/selectedSpiritAnimalsẽ tính đến việc người đó idcó hay không có.

Phản hồi HTTP 4xx được dành riêng cho tình huống khi khách hàng thực hiện điều gì đó không chính xác trong yêu cầu (xem lưu trữ của w3 về thông số ban đầu ). Nhưng khách hàng đang đưa ra một yêu cầu hợp lệ, cho dù người đó idcó động vật linh hồn hay không .

Vì vậy, tôi nghiêng về các giải pháp thứ hai bằng cách sử dụng phần thân JSON được định dạng chính xác trong phản hồi và mã HTTP 2xx.

Bây giờ nếu bạn nhận được một yêu cầu như vậy và hóa ra người idđó không tồn tại, mã 4xx có ý nghĩa hơn.


17
"Phản hồi HTTP 4xx được dành riêng cho tình huống khi khách hàng thực hiện điều gì đó không đúng trong yêu cầu". Khi đưa ra tuyên bố chính thức về thông số kỹ thuật, vui lòng tham khảo thông số HTTP thực tế và không (a) một khung được xây dựng trên đầu trang hoặc (b) một bài đăng blog ngẫu nhiên.
Eric Stein

5
@EricStein Tôi đã cảm thấy một chút lười biếng về điều đó; cảm ơn đã phê bình Cập nhật.
Brandon Arnold

1
Tôi cảm thấy như liên kết RFC ở đây là loại xung đột. Một mặt phần 4xx nói cases in which the client seems to have erred, nhưng mặt khác 404 nói trực tiếp The server has not found anything matching the Request-URI. Bạn có thể xem xét yêu cầu một cái gì đó không tồn tại một lỗi máy khách. Tôi hiểu người không tồn tại so với chống đỡ phụ không tồn tại, nhưng điều đó có thể được chỉ định là thông điệp phản hồi. 204 cũng có vẻ có liên quan, vì thực thể tồn tại, nhưng không có nội dung cho một thuộc tính phụ.
shortthingsushi

1
Khách hàng đã làm sai điều gì đó; nó yêu cầu động vật tinh thần được chọn cho người dùng khi nó không tồn tại. Đó chính xác là những gì 404 có nghĩa là ... bạn đã yêu cầu một cái gì đó không có ở đó.
Andy

5
Khi trình duyệt của tôi đưa ra yêu cầu tới phần mềmengineering.stackexchange.com/questions/unicorn, đó là một yêu cầu hợp lệ và tôi vẫn nhận được 404 (không có câu hỏi nào với ID "kỳ lân").
user253751

24

Hãy để tôi giới thiệu cho bạn Mô hình trưởng thành của Richardson .

Vấn đề của bạn là bạn đang đại diện cho hai tài nguyên là một, trong đó bạn thực sự nên có hai tài nguyên có mối quan hệ được biểu thị bởi hypermedia. Sử dụng hypermedia để mô tả các mối quan hệ là mức 3 tuyệt vời của phần còn lại.

Người của bạn nên sống theo URI /person/{id}và động vật nên sống theo /spiritanimal/{id}. Người đó nên chỉ ra rằng nó có động vật linh hồn bằng cách sử dụng một liên kết đến động vật.

Hãy tưởng tượng một người tên là Bob, người có id 123 và một động vật tinh linh kỳ lân.

GET /person/123

sẽ trở lại;

{
  "name": "Bob",
  "links": [
    {
      "rel": "spiritanimal",
      "uri": "/spiritanimals/789"
    }
  ]
}

Bây giờ bất cứ ai đọc người 123 sẽ biết rằng họ có một động vật linh hồn và có URI nơi họ có thể nhận thêm thông tin về nó.

GET /spitiranimal/789

có thể trở lại

{
  "type": "Unicorn"
}

Bây giờ hãy tưởng tượng một người tên là Fred, người có id 456 và không có động vật linh hồn.

GET /person/456

sẽ trở lại;

{
  "name": "Fred",
  "links": [
  ]
}

Bây giờ bất cứ ai đọc người 456 sẽ biết rằng họ không có động vật linh hồn, vì không có liên kết. Không cần sử dụng bất kỳ mã trạng thái HTTP nào để thể hiện sự thiếu mối quan hệ.


1
Chỉ cần thêm vào câu hỏi rằng, với khả năng thay đổi api, một số mức HATEOAS có lẽ sẽ là giải pháp phù hợp. Đó là một ví dụ tuyệt vời về điều đó
Paul D'Ambra

1

Đây là url thích hợp để có được động vật linh hồn; do đó, một lỗi 404 là không phù hợp. 404 là để đại diện cho một vấn đề kỹ thuật, không phải là một vấn đề logic.

Giải pháp thích hợp là trả lại http 200 và {"selectedAnimal": null}

Bạn nên có một webmethod riêng biệt/person/{id}/hasSelectedSpiritAnimal mà trả về {"isSpiritAnimalSelected": false}. Đằng sau hậu trường, nó có thể hoặc không thể thực hiện các cuộc gọi phương thức tương tự, chỉ trả về false nếu null, nhưng đó là do nó quyết định, không phải là mã tiêu thụ.

Tốt hơn là tránh kết hợp để tách các truy vấn thành một phương thức web mà không có lý do thuyết phục để làm như vậy, ngay cả khi các truy vấn có liên quan chặt chẽ.


1
Bạn có thể giải thích tại sao bạn tin rằng đây là giải pháp thích hợp? Tôi không thể có ý nghĩa trả lại dữ liệu khi không có dữ liệu nào được trả về. Tôi đồng ý với bạn rằng 404 không có ý nghĩa vì URL vẫn ổn, do đó, 204 dường như có ý nghĩa nhất đối với tôi.
Vincent Savard

2
@VincentSavard Mã trạng thái khó làm việc hơn các phản hồi json và phù hợp hơn cho các vấn đề kỹ thuật thay vì truyền thông tin tên miền.
TheCatWhisperer

2
204: Không có nội dung với một cơ thể trống rỗng. Đó là tất cả rõ ràng và tự giải thích. Không cần phải tranh luận thêm. Nói chung, khi không có mẫu thiết kế rõ ràng, SE nên chọn một mẫu, uốn cong theo nhu cầu của nó và cung cấp tài liệu. Trả lại một cơ thể với một phản ứng 204 không phải là kết quả.
formixian

2
@formixian ... Nếu bạn đang tạo một api bjson / tcp thay vì json / http, bạn sẽ trả lại gì cho trường hợp này? Dựa vào mã http dường như để tôi ràng buộc một cách không cần thiết kết quả của api với việc thực hiện http của nó.
TheCatWhisperer

2
@VincentSavard When you said "the spirit animal is not currently on file", it seemed quite similar to me to "there is no content"Không có nội dung có nghĩa là không có nội dung . tức là: nó trả về "". Hai cái này không giống nhau chút nào. "Động vật tinh thần hiện không có trong hồ sơ" rất khác với "".
Shane

1

Những gì điểm cuối của bạn đại diện không chỉ là một con vật; nó là một con vật hoặc thiếu nó. Đó là một giá trị được thể hiện tốt nhất bằng Optional/ Maybe/ Nullable/ v.v.

Vì vậy, các giá trị hợp pháp (như trong 200 OK) có thể là:

  • {'animal': <some animal>, 'selected': true}
  • {'animal': null, 'selected': false}

Tôi có thể tưởng tượng rằng DELETEphương pháp, khi áp dụng cho các thiết bị đầu cuối, có thể thiết lập 'selected'để falsemột lần nữa, có nghĩa là, bỏ đặt con vật được chọn.

Tất nhiên, bạn có thể thả 'selected'chìa khóa ở đây, nó chỉ được hiển thị cho rõ ràng; chuỗi vs nulllà đủ cho sự phân biệt.


0

Bạn nên sử dụng 404.

Mã trạng thái 404 (Không tìm thấy) chỉ ra rằng máy chủ gốc không tìm thấy đại diện hiện tại cho tài nguyên đích

RFC7231

HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 25 Sep 2017 00:00:00 GMT

"mole"

HTTP/1.1 404 Not Found
Content-Type: text/plain
Date: Mon, 25 Sep 2017 00:00:00 GMT

this person has not selected a spirit animal

Vì bạn đang tạo giao diện lập trình, không phải giao diện người, văn bản 404 là tùy chọn.

Tôi thích điều này bởi vì tôi thích các giao thức tiêu chuẩn càng nhiều càng tốt. HTTP có một cách để thể hiện sự không tồn tại và đó là những gì tôi sẽ sử dụng.

EDIT: Giả sử bạn đã thêm một tính năng nơi người dùng có thể chọn chia sẻ động vật linh hồn của họ và ai đó đã không chia sẻ tính năng này. Bạn sẽ trả lại 200 OK null, hay 200 OK "Unauthorized? Hoặc bạn sẽ sử dụng tiêu chuẩn 401 trái phép / 403 bị cấm? Điều này có vẻ tương tự trực tiếp với việc không chọn một ở nơi đầu tiên.


Ngoài ra, nếu bạn muốn sử dụng 200 OK + JSON, bạn nên quay lại null.

HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 25 Sep 2017 00:00:00 GMT

"mole"

HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 25 Sep 2017 00:00:00 GMT

null

Giữ mọi thứ sạch sẽ. Tạo thêm gói chỉ khi cần thiết.


2
Các dữ liệu được tìm thấy, mặc dù. Nó chỉ xảy ra rằng dữ liệu là null(không có giá trị). Điều này khác với ứng dụng khách yêu cầu một cái gì đó mà không có vị trí nào giữ giá trị tồn tại. Bạn sẽ không đề xuất ném AttributeErrorPython khi giá trị xảy ra None; điều đó sẽ làm cho giao diện không thực tế và khó sử dụng. Thực tế hơn, nhiều API máy khách HTTP có thể chuyển đổi 404 thành cơ chế xử lý lỗi tiêu chuẩn của ngôn ngữ (mã lỗi, ngoại lệ, loại lỗi), nghĩa là bạn phải loại bỏ lỗi không liên quan.
jpmc26

@Paul Draper Cuộn lên một chút trong thông số kỹ thuật, bạn sẽ thấy rằng nó đưa ra tuyên bố về HTTP 4xx: "Lớp mã trạng thái 4xx dành cho các trường hợp mà máy khách dường như đã bị lỗi." Các op đã tuyên bố rõ ràng rằng không có động vật linh hồn là trạng thái hợp lệ mà API nên tính đến. tools.ietf.org/html/rfc7231#section-6.5
Brandon Arnold

Sau đó, làm thế nào để bạn phân biệt giữa việc chỉ ra sự không tồn tại của tài nguyên được yêu cầu (nghĩa là không có động vật nào được chọn) và khách hàng yêu cầu một đường dẫn không hợp lệ (nghĩa là /person/{id}/selectedSpritAnimalquan sát lỗi đánh máy Sprit).
sampathsris

1
Bất kể ý định là gì, 404 hoàn toàn có nghĩa là tài nguyên không được tìm thấy. Nếu một SpriteAnimal được chọn là một tài nguyên và không tồn tại, thì không có gì để NHẬN và 404 là phù hợp. Tuy nhiên, nếu khách hàng muốn biết liệu một động vật linh hồn đã được chọn hay chưa thì máy chủ sẽ tiết lộ một tài nguyên khác /person/{id}/isSpiritAnimalSelectedsẽ cho khách hàng biết liệu chúng có được chọn hay không. Dường như với tôi ví dụ kinh điển tương tự về việc kiểm tra xem một tệp có tồn tại trước khi đọc nó hay không. Chỉ cần đọc tệp và xử lý lỗi ENOENT nên được ném.
aaaaaa

1
@PaulDraper Điểm không phải là tài nguyên có tồn tại hay không. Vấn đề là mã HTTP 4xx có nghĩa là khi người gọi đang sử dụng API không chính xác. Các trạng thái Op /person/{id}/selectedSpiritAnimalcó nghĩa là được sử dụng ngay cả khi động vật linh hồn không tồn tại. Điều này có nghĩa là HTTP 4xx không chính xác, khi được sử dụng trong trường hợp như vậy. Op cũng nói chính xác rằng đây có thể là một mùi của thiết kế API xấu.
Brandon Arnold
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.