Nếu không có kết quả thì có thể là một lỗi trong phản hồi RESTful?


52

Tôi sẽ mô tả một ví dụ:
Tôi bắt đầu tạo API cho cửa hàng bánh. API sẽ cho phép mọi người tìm kiếm danh mục sản phẩm làm bánh của họ, chẳng hạn như bánh quy sô cô la bạc hà làm tại nhà bằng cách sử dụng api.examplebakery.com/search?q=......

Ai đó sử dụng điều này để tìm kiếm một sản phẩm có tên pineapple-banana flavoured cookiesvà rõ ràng sẽ không tìm thấy bất kỳ kết quả nào.

Điều này có nên được trả lại như là một lỗi? Tìm kiếm không thất bại, API đã tìm kiếm và kết luận thành công không tìm thấy cookie nào. API không nên trả về 404, vì API thực sự đã được tìm thấy.




3
@gnat: Đây không phải là một bản sao, bởi vì câu hỏi khác là về một tài nguyên cụ thể, không phải là một truy vấn đối với nhiều tài nguyên.
Greg Burghardt

7
Tương tự, giả sử bạn có một hàm trả về một mảng các đối tượng. Nếu không có bất kỳ đối tượng nào khớp với một trường hợp sử dụng cụ thể, bạn sẽ thay hàm thông qua một ngoại lệ hoặc trả về một mảng trống?
Kevin - Tái lập Monica

2
@AakashM Việc trả lại HTTP-204 cho yêu cầu GET là khá bất thường, tôi biết tôi chưa thấy điều đó ở bất cứ đâu. Theo như tôi biết, HTTP-204 thường được sử dụng làm phản hồi khi sửa đổi tài nguyên trên máy chủ, ví dụ như các yêu cầu POST / PUT / DELETE.
Radu Murzea

Câu trả lời:


122

Khi có kết quả, đầu ra là một danh sách (JSON, dựa trên nhận xét của bạn). Đối với các truy vấn không có kết quả, đầu ra phải giống hệt nhau. Danh sách đơn giản có 0 mục trong đó.

Vì vậy, nếu phản hồi của bạn là bình thường này:

{
    "results": [
        {
            "name": "Pancakes",
            ....
        },
        {
            "name": "French Fries",
            ....
        }
    ]
}

Sau đó, đối với một truy vấn có 0 kết quả, nó sẽ là:

{
    "results": []
}

Nếu bạn cũng bao gồm dữ liệu meta về số lượng "trang" kết quả, liên kết đến các "trang" đó, v.v. thì tôi sẽ đề nghị nói có 1 "trang".

Trạng thái HTTP phải giống như khi có kết quả - 200 OK.

204 No Contentcó vẻ cũng là một lựa chọn, nhưng không phải vì bạn thực sự đang trả lại "nội dung" - danh sách trống. Nếu bạn cảm thấy một danh sách trống không được tính là "nội dung", nếu sau đó bạn sửa đổi phản hồi để đưa ra đề xuất chính tả thì sao? Cốt lõi của phản hồi vẫn sẽ là một danh sách trống, nhưng bây giờ thậm chí còn có nhiều "nội dung" hơn.

Để biết thêm thông tin hữu ích về mã trạng thái HTTP, jpmc26 câu trả lời của họ rất đáng đọc.


9
Đây là kiểu suy nghĩ giống như mẫu đối tượng null . Lỗi và null không phải là cách duy nhất để nói rằng không có gì ở đây. Đôi khi bạn muốn thể hiện không có gì lặng lẽ. Bằng cách đó, khách hàng không phải kiểm tra gì cả.
candied_orange

54
Tôi cho rằng việc trả lại 204 là không phù hợp, vì bạn đang trả lại nội dung. Chỉ là nội dung không có kết quả, khác biệt với việc không trả lại nội dung nào cả.
TMN

9
@TMN đồng ý - 204 không phù hợp với "không có kết quả." Truy vấn của bạn phải luôn trả về một mảng, với kết quả bên trong mảng. Nếu không có kết quả, khách hàng sẽ xử lý một cách tự nhiên. Nếu khách hàng muốn hiển thị văn bản đặc biệt ("Không tìm thấy kết quả"), thì tốt thôi. Chỉ nên trả lại 204 cho điểm cuối không tự nhiên trả về kết quả.
JasonB

1
Bạn có thể sử dụng 204 nếu bạn trả về null được tuần tự hóa dưới dạng một chuỗi rỗng tôi điều chỉnh lại
Ewan

15
Điều này. Điều quan trọng khi xây dựng API RESTful là phần API, không phải phần còn lại. Một API tốt làm cho cuộc sống dễ dàng cho khách hàng / người tiêu dùng. Một mảng trống dễ xử lý hơn các giá trị null / ngoại lệ / mã trạng thái.
Guran

37

Bất cứ khi nào quyết định mã HTTP, bạn nên luôn đặt câu hỏi này:

Bất kỳ khách hàng tùy ý có thể / sẽ / nên làm gì với phản hồi?

  1. Khách hàng có nên luôn coi phản ứng là một thất bại? Sau đó, bạn muốn 4xx hoặc 5xx, tùy thuộc vào vấn đề là đầu vào của máy khách hay quy trình của máy chủ.
  2. Thay vào đó, khách hàng có nên đưa ra yêu cầu ở nơi khác không? Sau đó, 3xx là dành cho bạn.
  3. Máy chủ đã làm những gì khách hàng yêu cầu (đã thành công)? Đó là 2xx.

Luôn luôn quyết định phạm vi mã phản hồi của bạn nên ở đầu tiên. Làm như vậy nhanh chóng loại bỏ rất nhiều mã phản hồi dưới dạng tùy chọn và (có thể quan trọng hơn) nó làm cho việc tuân theo ngữ nghĩa của mã đơn giản hơn nhiều. Xem các phần đầu của tài liệu mã HTTP để biết giải thích về từng loại mã thể hiện.

Trong trường hợp này, khách hàng yêu cầu danh sách kết quả được cung cấp bộ lọc từ điểm cuối hợp lệ, hiện có và có quyền truy cập vào nó. Máy chủ đã có thể xử lý yêu cầu và xác định dữ liệu phù hợp để trả về (không có mục nào), vì vậy yêu cầu đã thành công. Nó chỉ xảy ra rằng bộ lọc họ đã lọc ra tất cả các kết quả. Máy chủ không xác định liệu đây có phải là điều khách hàng muốn hay không, vì đây có thể là kết quả mong đợi đối với một số khách hàng. Nếu đó là một vấn đề nào đó đối với mã máy khách, đó là trách nhiệm của khách hàng trong việc xác định, kiểm tra và xử lý một cách thích hợp. Vì vậy, đây rõ ràng là 2xx.

Bây giờ câu hỏi là "2xx nào?" Điều này phụ thuộc vào cách bạn dự định cho máy chủ phản hồi.

  • Bạn sẽ gửi lại một đại diện của một danh sách trống, giống như một số câu trả lời khác mô tả? Nếu vậy, bạn muốn 200. 200 có nghĩa là máy chủ không gặp vấn đề gì và có đại diện cho kết quả để khách hàng tiêu thụ. Đây có thể là cách thuận tiện nhất để trả lời cho người tiêu dùng của bạn, người chỉ có thể phân tích phản hồi cho dù có kết quả hay không và sau đó tìm ra cách tự xử lý một danh sách trống.
  • 204 không sai về mặt ngữ nghĩa ở đây, nhưng bạn sẽ phải trả lời mà không có thông điệp gì . Điều này có nghĩa là tất cả các mã máy khách sẽ phải kiểm tra rõ ràng các mã HTTP khác nhau (hoặc ít nhất là thiếu phần thân thông báo) và xử lý chúng một cách riêng biệt. Nó bất tiện và có nhiều khả năng dẫn đến các khách hàng cư xử kém.

Những cái khác hoàn toàn không áp dụng:

  • 201 là ra khỏi câu hỏi. Bạn đã không tạo bất kỳ tài nguyên liên tục nào và không trả lại vị trí cho tài nguyên đã tạo.
  • 202 là ra khỏi câu hỏi. Yêu cầu được thực hiện; nó không xử lý ở chế độ nền.
  • 203 có nghĩa là phản hồi đã được sửa đổi giữa máy chủ có thẩm quyền và máy khách. Giao diện RESTful của bạn máy chủ có thẩm quyền, vì vậy điều này không áp dụng ở đây.
  • 205 không có ý nghĩa. Bạn không cần khách hàng xóa hoặc làm mới bất cứ điều gì.
  • 206 dường như được thiết kế để trả về một tài nguyên lớn qua nhiều phản hồi. Nó cũng yêu cầu khách hàng yêu cầu một phần nội dung trong các tiêu đề (vì vậy phân trang qua chuỗi truy vấn không đủ điều kiện). Không áp dụng ở đây.

Vì vậy, nó phải là 200 hoặc 204, và 200 có nhiều khả năng dẫn đến mã máy khách đơn giản hơn, mạnh mẽ hơn (đặc biệt nếu bạn sử dụng cấu trúc phản hồi nhất quán có chứa danh sách trống).


5
Sẽ quan tâm đến ý kiến ​​của downvoter. Tôi không nghĩ bất kỳ điều này thậm chí còn gây tranh cãi.
jpmc26

2
Tôi không nghĩ rằng khách hàng phải kiểm tra rõ ràng 204. Tất cả những gì họ cần là khả năng xử lý đối tượng phản hồi null. Đó là công việc của khung công tác HTTP để xử lý 204 bằng cách bỏ qua phần "phân tích cơ thể". 200 với Content-Lenght 4 và body null là như nhau.
Đặc vụ_L

1
@Agent_L Bạn đúng rằng nếu máy chủ phản hồi với cấu trúc không phù hợp với phản hồi bình thường (như đặt nulldanh sách bình thường), bạn sẽ không gặt hái được lợi ích của tính nhất quán ngay cả với 200. Tuy nhiên, những gì tôi mô tả là sử dụng phản hồi phù hợp với cấu trúc bình thường và có một danh sách trống trong đó danh sách kết quả thường sẽ đi. 204 lấy đi bất kỳ cơ hội để có một phản ứng nhất quán như vậy. Ngoài ra, ngay cả trong các thư viện máy khách HTTP có chức năng tiện lợi cho nó, bạn thường (thường là?) Phải thực hiện một cuộc gọi rõ ràng để phân tích JSON.
jpmc26

@Agent_L Đặc biệt với các danh sách, người gọi thường có thể để mã của họ chạy bình thường trên một danh sách trống (ví dụ bằng cách lặp qua nó), trong khi họ cần một loại kiểm tra rõ ràng để xử lý một loại đại diện khác.
jpmc26

16

Không. Việc sử dụng 404 để chỉ ra 'truy vấn của bạn đã được xử lý nhưng không có kết quả trùng khớp' là khủng khiếp vì:

  • luồng có điều kiện dựa trên xử lý ngoại lệ (nghĩa là buộc một kết quả không đặc biệt để tạo và xử lý một ngoại lệ trong máy khách có thể không hiệu quả và khó xử)

  • Không rõ ràng giữa trang 'thực', bạn đã nhập sai điểm cuối

Điều cần nhớ là luôn có một khách hàng để giải trừ thông điệp và những gì khách hàng trả lại là điều quan trọng; không phải là tuần tự hóa.

Nếu máy khách sẽ trả về null, sau đó sử dụng tuần tự hóa null. Nếu máy khách sẽ trả về một mảng trống, hãy sử dụng [], nếu máy khách sẽ ném lỗi, hãy sử dụng 500 và truyền thông báo lỗi


2
Tại sao máy chủ nên quan tâm những gì khách hàng đang làm với thông tin? (PS: Tôi không phải là người đánh giá thấp câu trả lời của bạn).
Radu Murzea

trong ngữ cảnh này, 'client' là mã chạy trên thiết bị khách hiển thị dịch vụ cho ứng dụng khách. Nó phải có khả năng phơi bày các phương thức dịch vụ và trả về kết quả như dự định của dịch vụ. Bạn cần một cặp máy khách-máy chủ để liên lạc hoạt động hoàn toàn
Ewan

3
Tất nhiên, đừng sử dụng 5xx cho lỗi máy khách . Thích 4xx trong trường hợp đó.
Kevin

1
Mặc dù, không nên là "máy chủ" chứ không phải "máy khách" trong hầu hết các trường hợp này? Đó có phải là máy chủ đang xử lý yêu cầu và phục vụ phản hồi, máy khách chỉ xử lý phản hồi? Trong trường hợp nào mã 5xx sẽ ổn, vì đó là lỗi máy chủ, không phải lỗi máy khách?
MrWhite

2
rắc rối với tất cả các mã lỗi là chúng có ý nghĩa trong http. 500 là mã duy nhất phù hợp khi dịch vụ của bạn đưa ra một ngoại lệ
Ewan

9

Ngoài câu trả lời rất hay của @ Ewan:

Nếu truy vấn là loại trả về một tập hợp kết quả, thì tập hợp trống sẽ hợp lý như một tập hợp của một hoặc một tập hợp nhiều hơn. Nói chung vì những lý do mà @Ewan tuyên bố, việc thay đổi tập hợp trống thành một lỗi có hại, và đơn giản là không cần thiết.

Nếu truy vấn là loại tìm kiếm và trả về một singleton cụ thể (dự kiến ​​sẽ được tìm thấy, ví dụ: khớp chính xác theo id), thì không tìm thấy là một phản ứng phù hợp về mặt logic.


vâng tôi nghĩ chính xác câu trả lời của Ewan.
Walfrat

5

Bạn đang giả sử mã phải thực hiện một hành động đặc biệt khi không có dữ liệu nào được trả về, nhưng đó có thể không phải là trường hợp. Mã có thể chỉ đơn giản là tìm kiếm số lượng sản phẩm hoặc nối thêm kết quả vào danh sách hoặc bất kỳ số lượng nào. Bạn chỉ nên cung cấp cho người dùng một "lỗi" nếu thực sự có lỗi.


3
"Bạn chỉ nên cung cấp cho người dùng một" lỗi "nếu thực sự có lỗi." - điều này. Một kết quả trống được đặt khi thực hiện "tìm kiếm" thường không phải là "lỗi". Tuy nhiên, nếu kết nối cơ sở dữ liệu không thành công có nghĩa là tìm kiếm thực sự không thể được thực hiện thì một tập kết quả trống (và không có lỗi) sẽ không rõ ràng. Một số loại trạng thái lỗi sẽ phù hợp trong trường hợp này (có lẽ cùng với một tập kết quả trống - tùy thuộc vào cách xác định API).
MrWhite

0

Khi tôi sử dụng API, với tư cách là khách hàng, tôi phải xử lý các trường hợp "thành công" khác với các trường hợp "lỗi"; Tôi không có lựa chọn nào ở đó. Do đó, bạn nên trả lại lỗi trong các tình huống mà khách hàng muốn đối xử khác nhau và thành công trong các tình huống mà khách hàng muốn đối xử như nhau.

Nếu tôi thực hiện một truy vấn về lý thuyết có thể trả về bất kỳ số lượng kết quả nào, 0, 1, 2 trăm, thì bạn sẽ trả về "thành công" bất cứ khi nào API cung cấp danh sách đầy đủ tất cả các kết quả. Và có thể trong trường hợp có nhiều kết quả, bạn đã trả về một danh sách một phần kết quả để tránh kích thước quá mức và có một cách đồng ý làm thế nào tôi có thể nhận được kết quả khác. Đó là bởi vì là một khách hàng, tôi thường muốn xử lý trường hợp không có kết quả như trường hợp có nhiều kết quả hơn. Tôi có thể đối xử với nó khác nhau, nhưng tôi không muốn bị ép buộc.

Nó là khác nhau trong trường hợp tôi tìm kiếm một giá trị. Tôi mong đợi chính xác một kết quả, giá trị mà tôi đang tìm kiếm. Và tôi cần một kết quả đó để tiếp tục những gì tôi muốn làm một cách có ý nghĩa. Ở đây, việc trả lại trạng thái 404 cho trường hợp không có giá trị là điều dễ chấp nhận hơn, vì dù sao tôi cũng cần xử lý trường hợp đó một cách khác.

Tóm tắt: Nếu khách hàng mong đợi bất kỳ số lượng kết quả nào, từ số 0 đến số lớn, sau đó trả về "thành công" nếu tất cả các kết quả được gửi, ngay cả khi số đó bằng không. Nếu khách hàng mong đợi chính xác một kết quả, thì trả về thành công nếu kết quả được tìm thấy và một lỗi nếu không tìm thấy kết quả.

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.