Đại diện cho hành động (động từ) trong REST URI


16

Tôi có một hoạt động in để thực hiện cho các tài liệu khách hàng của tôi. Tôi cần các hoạt động tiêu chuẩn khác cũng được thực hiện, như thêm, cập nhật, xóa. vì vậy, tôi có sau:

  • Để tạo khách hàng mới:
    URI = / customer / {id}, gõ = POST, Methodname = CreateCustomer ()
  • Để cập nhật:
    URI: / customer / {id}, gõ = PUT, method = UpdateCstomer ()
  • Để xóa khách hàng:
    URI = / customer / {id}, gõ = DELETE, Methodname = DeleteCustomer ()
  • Để xem:
    URI: / customer / {id}, gõ = GET, method = GetCustomer ()

Bây giờ, nếu tôi cần in một tài liệu cho khách hàng đó, tôi cần một chức năng in. URI của tôi có thể trông như thế này: / customer / {id}, type = POST, method = PrintCustomer (). Nhưng tôi đã sử dụng loại URI và POST đó cho CreatCustomer. Tôi muốn URI trông như thế này: / customer / Print / {id}, type = POST, method = PrintCustomer ().

Nhưng tôi không thể có động từ "In" trong URI của mình. Cách tốt nhất để làm điều này là gì? Tôi đã nghĩ về / khách hàng / tài liệu / {id} là URI ... nhưng tôi sẽ gặp vấn đề tương tự. Tôi sẽ có các thao tác CRUD trên "tài liệu". Vì vậy, một lần nữa tôi hết những gì tôi sẽ sử dụng cho "in". Xin tư vấn.


2
In thường là một hoạt động phía máy khách, vì vậy tôi tò mò - cách thiết lập của bạn sao cho nó yêu cầu bạn gửi lệnh đến máy chủ REST?
Shauna

2
@Shauna Không nhất thiết, URI có thể là một yêu cầu đến máy chủ cho phiên bản tài nguyên thân thiện với bản in (tức là một chế độ xem khác).
Evan Plaice

1
@EvanPlaice - Đủ công bằng, mặc dù điều đó vẫn để lại hành động in cho khách hàng (mà ngay cả sau khi tìm nạp phiên bản thân thiện với máy chủ, sau đó sẽ quyết định thiết bị nào sẽ in và gửi lệnh in, ngay cả khi đó lệnh đi đến một máy chủ in). Một yêu cầu để có được một phiên bản tài nguyên thân thiện với bản in sau đó sẽ hợp lý là ... à ... NHẬN.
Shauna

@Shauna Kích hoạt một công việc in từ một yêu cầu HTTP là không thể do bảo mật trình duyệt. Yêu cầu cho phiên bản thân thiện với bản in chỉ là yêu cầu NHẬN nhưng bạn vẫn cần một cách để xác định rằng trình duyệt sẽ hiển thị phiên bản có thể in. Bạn có thể chỉ định một URL khác nhưng điều đó sẽ vi phạm các nguyên tắc của REST vì bạn không thực sự yêu cầu một tài nguyên khác, chỉ là một biến đổi khác nhau của cùng một tài nguyên. Do đó, lý do để chỉ định biến đổi thông qua tham số truy vấn và / hoặc loại nội dung.
Evan Plaice

Tôi không có đủ đại diện để đăng bài như một câu trả lời, nhưng tôi thấy thật thú vị khi tyk.io/rest-never-crud cho rằng đó POST /customers/123/printlà một điều hợp lệ để làm.
jlh

Câu trả lời:


9

POSTkhông có nghĩa là "tạo", nó có nghĩa là "quá trình". Bạn có thể tạo một tài nguyên mới bằng cách đăng một yêu cầu phù hợp lên một tài nguyên hiện có (tức là đăng bài /customersđể tạo một khách hàng mới). Nhưng bạn cũng có thể sử dụng POSTđể điền vào tất cả các hành động khác không tương ứng với mô hình CRUD gọn gàng.

Trong trường hợp in, bạn nên xem hành động in như là một tài nguyên. Bạn đang yêu cầu hệ thống tạo một "công việc in" cho bạn. Điều này có nghĩa là bạn có thể có một prints/tài nguyên đóng vai trò là thùng chứa cho tất cả các bản in được yêu cầu. Khi bạn muốn in POSTmột tài liệu nào đó cho bạn một tài liệu tới tài nguyên này chứa tất cả thông tin về bản in bạn muốn tạo, hãy xác định các tài nguyên bạn muốn in bằng các liên kết đến chúng.

Là một tài liệu JSON, nó có thể trông như thế này:

{
   contents: ["http://site/customers/12345"],
   paper-size: "A4",
   duplex: "true"
}

Rõ ràng, bạn cần tùy chỉnh điều này để phù hợp với những gì bạn muốn làm. Điều quan trọng là bạn đang xác định các tài nguyên khác để in bằng cách chỉ định URL của họ.

Để đáp ứng yêu cầu, bạn chỉ cần trả lại một 200 OKhoặc một 204 No-Contentvà coi đó là một quá trình quên và quên. Tuy nhiên, nếu bạn muốn nâng cao nó, bạn có thể quay lại 201 Createdvà chỉ định URL của lệnh in mới được tạo, vd /prints/12345.

Sau đó, người dùng có thể thực hiện một GETtài nguyên để xem trạng thái của công việc in của họ (đang chờ xử lý, đang thực hiện, v.v.) hoặc có thể yêu cầu công việc bị hủy bằng cách phát hành DELETE.

Khi bạn viết lại vấn đề về tài nguyên, thiết kế RESTful sẽ xuất hiện một cách tự nhiên và cho bạn cơ hội mở rộng và nâng cao theo những cách mà bạn có thể chưa xem xét ngay lập tức.


2
POST thường có nghĩa là tạo / chèn, trong khi đặt thường có nghĩa là cập nhật lưu / cập nhật. Đó là cách nó được định nghĩa trong REST ngay cả khi nó không được sử dụng trong HTML.
Evan Plaice

2
@EvanPlaice tên đặc tả HTTP PUT là động từ tạo / cập nhật (nó sử dụng mô hình tạo + cập nhật thay vì mô hình tạo + lấy + cập nhật quen thuộc hơn) và POST là động từ "xử lý dữ liệu", cũng như động từ "chắp thêm" . Roy Fielding trong blog của mình đã mô tả POST là động từ sẽ sử dụng khi bạn không muốn chuẩn hóa thao tác. POST thực hiện ngữ nghĩa "tạo" khi bạn xem xét nó nối thêm một mục mới vào một bộ sưu tập các mục. Trong trường hợp này, Tragedian đánh vào đầu bằng cách sử dụng POST để xử lý hoặc thêm lệnh in.
Rob

@RobY OK, điều đó có ý nghĩa. Ví dụ, PUT có thể được sử dụng để thể hiện một XUÂN được thiết kế để nhập dữ liệu vào cơ sở dữ liệu. Trong khi đó, POST có thể tạo nên các bước trung gian và đột biến cần thiết để thu thập / chuẩn bị dữ liệu đó. Thiết kế của hoạt động POST có thể thay đổi hoặc được thay thế khi thiết kế phát triển nhưng các hoạt động PUT đại diện cho mô hình (lý tưởng) không nên thay đổi. Tôi sẽ cập nhật câu trả lời của mình nhưng câu hỏi này đã làm rất tốt khi giải thích sự khác biệt.
Evan Plaice

4

Tôi đã làm điều này trước đây. Để in tài liệu tôi chỉ cần trả về phiên bản pdf của tài nguyên. Máy khách chỉ cần gửi yêu cầu GET cho tài nguyên với ứng dụng tiêu đề Chấp nhận / pdf.

Điều này cũng tránh tạo URI mới cho tài nguyên tạm thời như công việc in. Sử dụng tiêu đề HTTP cũng là một phần của REST và nó giữ cho URI sạch sẽ.


3

Chỉ cần thêm một tham số vào GET của URI hiện tại

Việc sử dụng một URI cho nhiều hành động là khá điển hình.

Nếu bạn đang nói về cùng một tài nguyên nhưng một hành động khác, bạn sẽ xác định đó là một tham số.

/ khách hàng / {id}? print = true

Sau đó, tại đây bạn xác định phương thức GET của mình, bạn phát hiện sự hiện diện của tham số in và xử lý nó theo cách khác.

REST được định nghĩa theo cách sau:

  • POST - Tạo bản ghi, tài sản hoặc tài nguyên
  • PUT - Cập nhật, bản ghi, tài sản hoặc tài nguyên
  • XÓA - Xóa a, bản ghi, tài sản hoặc tài nguyên

Mặt khác, GET có nghĩa là được sử dụng theo nhiều cách vì thông thường có rất nhiều dạng khác nhau mà tài nguyên có thể được lấy. Đó cũng là lý do tại sao các yêu cầu GET được biểu diễn dưới dạng chuỗi truy vấn. Nếu bạn đang làm việc với tài nguyên cơ sở dữ liệu, bạn thực sự sẽ truy xuất một chế độ xem thông qua truy vấn nhưng REST được cố ý trừu tượng hóa lên mức cao hơn vì nó được thiết kế để xử lý với nhiều loại tài nguyên khác nhau.

Đặc tả REST rất dễ nghĩ, mặc dù các API mới chỉ bắt đầu sử dụng nó gần đây.

Nếu bạn quan tâm đến việc tìm hiểu thêm về các giao thức REST, tôi khuyên bạn nên đọc " Haters Gonna Hate HATEOAS ".


Cập nhật:

@Shauna đã chỉ ra một lỗ hổng thú vị trong lý luận của tôi. Không có sự thật đúng cách và nhiều hình thức được coi là chấp nhận được. Tôi đã nghĩ về nó nhiều hơn và vì mục đích sử dụng của bạn là chuyển đổi dữ liệu thành một biểu diễn khác, nên xác định biến đổi là MIME-Type mới.

Ví dụ: bạn có thể biểu diễn URI là:

/customer/{id}+print

Nơi bạn có thể đặt loại Nội dung phản hồi thành văn bản / html + in. Bằng cách đó, bạn cũng có tùy chọn để xác định nhiều biến đổi hơn trong tương lai.

Ví dụ:

// for application/json
/customer/{id}+json

// for application/atom+xml
/customer/{id}+atom

Dù bằng cách nào, tất cả các hình thức đều được chấp nhận. Việc triển khai bạn quyết định phụ thuộc nhiều hơn vào sở thích cá nhân và khả năng của máy chủ của bạn.

Ngoài ra: Hãy để tôi làm rõ vì dường như có một số nhầm lẫn. Tham số truy vấn 'in' và / hoặc loại nội dung được sử dụng để chỉ định cách tài nguyên được chuyển đổi. Không phải làm thế nào để kích hoạt một công việc in vật lý. Vì lý do bảo mật, quyền truy cập cấp phần cứng luôn được dành cho người dùng / máy khách / trình duyệt.


Để thêm - Thay thế cho việc sử dụng chuỗi truy vấn ( ?print=true), bạn cũng có thể sử dụng các tham số URI (tức là - /customer/{id}/printable). Cái nào bạn sử dụng sẽ phụ thuộc phần lớn vào tiêu chuẩn mà hệ thống của bạn (CMS, khung, mã nói chung) được thiết lập để xử lý. Cả hai đều được coi là hợp lệ và chấp nhận được .
Shauna

@Shauna Về mặt kỹ thuật, cách tiếp cận tốt nhất sẽ là sử dụng loại MIME cụ thể để in bằng URI '/ customer / {id} + print' và phản hồi MIME-Type of text / html + print. Ưu điểm của cách tiếp cận như vậy là, bạn có thể tạo các biến đổi cho nhiều loại MIME (ex text / html, text / x-markdown, application / json, v.v.) cho cùng một URI. Nhược điểm của giải pháp bạn trình bày là, bạn cần tạo một URI bổ sung (và xác định tuyến đường khác) cho mỗi Loại MIME khác nhau. Nó đánh bại mục đích sử dụng REST.
Evan Plaice

(tiếp) Tôi cho rằng hack URI là một mô hình chống được giới thiệu chủ yếu bởi cộng đồng ROR nhưng điều đó không có nghĩa là chúng không hữu ích. Với sự xuất hiện của các máy chủ HTTPd cấp thấp tốt hơn, việc triển khai REST trở nên dễ dàng hơn theo cách tận dụng tối đa tiềm năng của nó. Mọi thứ đã đi một chặng đường dài kể từ ngày Apache và định tuyến mọi thứ thông qua index.html là lựa chọn duy nhất.
Evan Plaice

2
NHẬN không nên thay đổi trạng thái hoặc có tác dụng phụ. Hãy xem xét rằng GET là idempotent, có nghĩa là phần mềm trung gian có thể thử lại yêu cầu nếu nó không thấy nó đi qua. Trong trường hợp này, mỗi lần thử lại sẽ dẫn đến một bản sao mới, được in mới của tài liệu. ;)
Rob

@RobY Tôi đã giả sử rằng hành động 'in' sẽ không xử lý quá trình in tài liệu vì nó sẽ được trình duyệt và trình điều khiển in phục vụ tốt hơn. Thay vào đó, đầu ra phương tiện / in sẽ trả về đại diện 'in thân thiện' của tài liệu. Do đó, idempotency được duy trì. Điểm tốt, gửi công việc in trên internet theo cách không trạng thái sẽ là một thời gian xấu.
Evan Plaice
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.