2009-08-18 46 views
45

Tôi đang cố gắng áp dụng các nguyên tắc RESTful cho một ứng dụng web mới mà tôi đang làm việc. Đặc biệt, đó là ý tưởng để được RESTful, mỗi yêu cầu HTTP phải tự cung cấp đủ thông tin để người nhận xử lý nó hoàn toàn hài hòa với bản chất không trạng thái của HTTP.REST - các ứng dụng phức tạp

Ứng dụng này cho phép người dùng tìm kiếm thuốc. Việc tìm kiếm chấp nhận các bộ lọc như đầu vào, ví dụ, trả lại thuốc ngưng, bao gồm điều trị miễn phí vv..vv. Tổng cộng có khoảng 30 bộ lọc có thể được áp dụng.

Bên cạnh đó, chi tiết bệnh nhân có thể được nhập bao gồm tuổi bệnh nhân, giới tính, loại thuốc hiện tại vv

để được yên tĩnh, nên tất cả các thông tin này được đính kèm với mọi yêu cầu? Điều này dường như đặt một chi phí rất lớn trên mạng. Ngoài ra, sẽ không phải là hạn chế về độ dài URL, ít nhất là cho GET, làm cho điều này không khả thi?

Trả lời

73

"Bộ lọc dưới dạng tài nguyên" là nguyên tắc hoàn hảo cho việc này.

Bạn có thể PUT định nghĩa bộ lọc cho tài nguyên bộ lọc và có thể trả về ID bộ lọc.

PUT là idempotent, vì vậy ngay cả khi bộ lọc đã có, bạn chỉ cần phát hiện rằng bạn đã xem bộ lọc trước đó, vì vậy bạn có thể trả lại ID thích hợp cho bộ lọc.

Sau đó, bạn có thể thêm thông số bộ lọc vào các yêu cầu khác của mình và họ có thể lấy bộ lọc để sử dụng cho các truy vấn.

GET/thuốc? Lọc = 1234 & page = 4 & pagesize = 20

tôi sẽ chạy các bộ lọc thô thông qua một số loại quá trình hợp quy, chỉ để có một bộ bình thường, do đó, ví dụ bộ lọc "firstname = Bob lastname = Eubanks" giống với "lastname = Eubanks firstname = Bob". Đó chỉ là tôi.

Mối quan tâm thực sự duy nhất là, khi thời gian trôi qua, bạn có thể cần phải lỗi thời một số bộ lọc. Bạn có thể chỉ đơn giản là lỗi ra yêu cầu nếu ai đó thực hiện một yêu cầu với một bộ lọc bị thiếu hoặc lỗi thời.

Chỉnh sửa câu hỏi trả lời ...

Hãy bắt đầu với các nguyên tắc cơ bản.

Đơn giản, bạn muốn chỉ định bộ lọc để sử dụng trong truy vấn, nhưng những bộ lọc này (có khả năng) có liên quan và phức tạp. Nếu nó là đơn giản/thuốc/1234, điều này sẽ không là một vấn đề.

Có hiệu quả, bạn luôn cần phải gửi bộ lọc cho truy vấn. Câu hỏi đặt ra là cách trình bày bộ lọc đó.

Vấn đề cơ bản với những thứ như phiên trong hệ thống REST là chúng thường được quản lý "ngoài băng". Khi bạn, nói, đi và tạo ra một loại thuốc, bạn PUT hoặc POST để các nguồn tài nguyên thuốc, và bạn nhận được một tài liệu tham khảo trở lại thuốc đó.

Với phiên, bạn sẽ (thường) lấy lại cookie hoặc có thể một số mã thông báo khác đại diện cho phiên đó. Nếu PUT của bạn để các nguồn tài nguyên thuốc tạo ra một phiên cũng có, sau đó, trong sự thật, yêu cầu của bạn tạo ra hai nguồn lực: một loại thuốc, và một phiên.

Thật không may, khi bạn sử dụng một cái gì đó như cookie và bạn yêu cầu cookie đó cho yêu cầu của bạn, tên tài nguyên không còn là biểu diễn thực sự của tài nguyên nữa. Bây giờ là tên tài nguyên (URL) và cookie. Vì vậy, nếu tôi thực hiện GET trên tài nguyên có tên/thuốc/tìm kiếm và cookie biểu thị một phiên và phiên đó xảy ra để có bộ lọc trong đó, bạn có thể thấy hiệu quả, tên tài nguyên đó,/thuốc/tìm kiếm, không thực sự hữu ích chút nào. Tôi không có tất cả thông tin tôi cần để sử dụng hiệu quả, vì tác dụng phụ của cookie và phiên và bộ lọc trong đó.

Bây giờ, bạn có thể viết lại tên:/drugs/search? Session = ABC123, nhúng cookie hiệu quả vào tên tài nguyên.

Nhưng bây giờ bạn đã tham gia vào hợp đồng điển hình của phiên, đáng chú ý là chúng ngắn ngủi. Vì vậy, tài nguyên được đặt tên đó ít hữu ích, lâu dài, không vô ích, chỉ kém hữu ích hơn. Ngay bây giờ, truy vấn này cung cấp cho tôi dữ liệu thú vị. Ngày mai? Chắc là không. Tôi sẽ nhận được một số lỗi khó chịu về phiên làm việc đã biến mất.

Vấn đề khác là các phiên thường không được quản lý dưới dạng tài nguyên.Ví dụ, chúng thường là một tác dụng phụ, được quản lý một cách rõ ràng qua GET/PUT/DELETE. Phiên cũng là "đống rác" của trạng thái ứng dụng web. Trong trường hợp này, chúng tôi chỉ hy vọng rằng phiên họp được điền đúng với những gì cần thiết cho yêu cầu này. Chúng tôi thực sự không thực sự biết. Một lần nữa, đó là một tác dụng phụ.

Bây giờ, hãy biến nó trên đầu một chút. Hãy sử dụng/thuốc/tìm kiếm? Filter = ABC123.

Rõ ràng, tình cờ, điều này trông giống hệt nhau. Chúng tôi chỉ thay đổi tên từ 'phiên' thành 'bộ lọc'. Nhưng, như đã thảo luận, Bộ lọc, trong trường hợp này, là một "tài nguyên lớp học đầu tiên". Chúng cần phải được tạo, quản lý, vv giống như một loại thuốc, một JPEG, hoặc bất kỳ tài nguyên nào khác trong hệ thống của bạn. Đây là điểm khác biệt chính. Chắc chắn, bạn có thể coi "phiên" là tài nguyên lớp học đầu tiên, tạo chúng, đưa nội dung trực tiếp vào chúng, v.v. Nhưng bạn có thể thấy cách, ít nhất từ ​​quan điểm rõ ràng, một phiên "lớp học đầu tiên" không thực sự là một trừu tượng tốt cho trường hợp này. Sử dụng một phiên, nó giống như đi đến các chất tẩy rửa và bàn giao toàn bộ ví hoặc vali của bạn. "Yea, vé ở đó đâu đó, đào ra những gì bạn muốn, cho tôi quần áo của tôi", đặc biệt là so với một cái gì đó rõ ràng như một bộ lọc.

Vì vậy, bạn có thể thấy như thế nào, ở độ cao 30.000 feet, không có nhiều khác biệt trong trường hợp giữa bộ lọc và phiên. Nhưng khi bạn phóng to, chúng khá khác nhau.

Với tài nguyên bộ lọc, bạn có thể chọn làm cho chúng trở thành một điều liên tục mãi mãi và lâu dài. Bạn có thể hết hạn, bạn có thể làm bất cứ điều gì bạn muốn. Phiên có xu hướng có ngữ nghĩa được hình thành trước: thời lượng ngắn, thời lượng kết nối, v.v. Bộ lọc có thể có bất kỳ ngữ nghĩa nào bạn muốn. Chúng hoàn toàn tách biệt với những gì đi kèm với một phiên.

Nếu tôi làm điều này, tôi sẽ làm việc với bộ lọc như thế nào?

Tôi cho rằng tôi thực sự không quan tâm đến nội dung của bộ lọc. Cụ thể, tôi nghi ngờ tôi sẽ truy vấn "tất cả các bộ lọc tìm kiếm theo tên". Tại thời điểm này, nó có vẻ như thông tin không thú vị, vì vậy tôi sẽ không thiết kế xung quanh nó.

Tiếp theo, tôi sẽ bình thường hóa các bộ lọc, như tôi đã đề cập ở trên. Đảm bảo rằng các bộ lọc tương đương thực sự là tương đương. Bạn có thể làm điều này bằng cách sắp xếp các biểu thức, đảm bảo tên trường là tất cả chữ hoa hoặc bất kỳ thứ gì.

Sau đó, tôi sẽ lưu bộ lọc dưới dạng tài liệu XML hoặc JSON, tùy theo điều kiện nào phù hợp hơn cho ứng dụng. Tôi sẽ cung cấp cho mỗi bộ lọc một khóa duy nhất (tự nhiên), nhưng tôi cũng sẽ lưu trữ một băm cho tài liệu thực tế với bộ lọc.

Tôi sẽ thực hiện việc này để có thể nhanh chóng tìm thấy nếu bộ lọc đã được lưu trữ. Vì tôi đang chuẩn hóa nó, tôi "biết" rằng XML (nói) cho các bộ lọc tương đương hợp lý sẽ giống hệt nhau. Vì vậy, khi ai đó đi đến PUT, hoặc chèn một bộ lọc mới, tôi sẽ làm một kiểm tra trên băm để xem nếu nó đã được lưu trữ trước đó. Tôi cũng có thể lấy lại nhiều hơn một (băm có thể va chạm, tất nhiên), vì vậy tôi sẽ cần phải kiểm tra các tải trọng XML thực tế để xem liệu chúng có phù hợp hay không.

Nếu bộ lọc phù hợp, tôi trả lại tham chiếu đến bộ lọc hiện tại. Nếu không, tôi sẽ tạo một cái mới và trả lại cái đó.

Tôi cũng sẽ không cho phép UPDATE/POST lọc. Vì tôi đang đưa ra các tham chiếu đến các bộ lọc này, tôi sẽ làm cho chúng không thay đổi nên các tham chiếu có thể vẫn hợp lệ. Nếu tôi muốn một bộ lọc bằng "vai trò", nói "bộ lọc thuốc hết hạn", thì tôi sẽ tạo một tài nguyên "được đặt tên bộ lọc" liên kết tên với cá thể bộ lọc để dữ liệu bộ lọc thực tế có thể thay đổi nhưng tên vẫn giữ nguyên.

Tâm trí, ngoài ra, trong quá trình tạo, bạn đang ở trong tình trạng đua (hai yêu cầu cố gắng tạo cùng một bộ lọc), vì vậy bạn phải tính đến điều đó. Nếu hệ thống của bạn có khối lượng bộ lọc cao, điều này có thể là một nút cổ chai tiềm ẩn.

Hy vọng điều này sẽ làm rõ vấn đề cho bạn.

+4

Đây là một trong những giải thích tốt nhất mà tôi đã thấy tại sao các phiên không phù hợp với kiến ​​trúc kiểu REST. –

+0

+1: Câu trả lời tuyệt vời, Will! –

+0

giải thích tốt @Will – jayraynet

10

REST là dành cho API, không phải ứng dụng (điển hình). Đừng cố gắng nêm một sự tương tác cơ bản về trạng thái vào một mô hình phi trạng thái chỉ vì bạn đọc về nó trên wikipedia.

Để yên tâm, tất cả thông tin này có được bao gồm trong mọi yêu cầu không? Điều này dường như đặt một chi phí rất lớn trên mạng. Ngoài ra, sẽ không phải là hạn chế về độ dài URL, ít nhất là cho GET, làm cho điều này không khả thi?

Kích thước thông số thường không đáng kể so với kích thước tài nguyên mà máy chủ gửi. Nếu bạn đang sử dụng các thông số lớn như vậy mà chúng là gánh nặng mạng, hãy đặt chúng trên máy chủ sau khi và sau đó sử dụng chúng làm tài nguyên.

Không có giới hạn đáng kể nào về độ dài URL - nếu máy chủ của bạn có giới hạn như vậy, hãy nâng cấp nó. Đó có thể là năm tuổi và thiếu các lỗ hổng bảo mật.

+2

Bạn có thể cung cấp tham chiếu cho xác nhận của mình rằng REST dành cho API không? Sự hiểu biết của tôi là REST đã được tổng hợp từ kiến ​​trúc của các ứng dụng web, mà tôi cho là người dùng phải đối mặt. Ngoài ra, bạn có thể giải thích tại sao ứng dụng tìm kiếm là "tương tác cơ bản về trạng thái" không? –

+1

REST là một thay thế cho RPC cho API; nó là một mô tả về kiến ​​trúc của web. Các ứng dụng web chỉ hiếm khi giống với Web trong kiến ​​trúc của chúng, và không thích hợp cho tương tác RESTful. Về "cơ bản nhà nước": từ câu hỏi, có vẻ như các bộ lọc được tích lũy trong một tiểu bang và sau đó áp dụng cho một bộ. Đối với tôi, cách tốt nhất có thể được biểu diễn trong một hệ thống không quốc tịch là tạo ra một tài nguyên "thiết lập" và áp dụng các bộ lọc cho nó - rất khác với việc triển khai của OP. –

+3

@John Nếu bạn thực sự quan tâm đến REST thì tôi khuyên bạn nên đọc và đọc lại luận văn của Roy. Tôi nghĩ rằng bạn hiểu lầm. –

0

Bạn đang làm việc trên API RESTful mà các ứng dụng khác sẽ sử dụng để tìm kiếm dữ liệu của bạn? Hay bạn đang xây dựng một ứng dụng web tập trung vào người dùng cuối, nơi người dùng sẽ đăng nhập và thực hiện các tìm kiếm này?

Nếu người dùng của bạn đang đăng nhập, thì bạn đã có trạng thái như bạn sẽ có một số loại cookie phiên để duy trì trạng thái đăng nhập. Tôi sẽ tiếp tục và tạo một đối tượng phiên có chứa tất cả các bộ lọc tìm kiếm. Nếu người dùng chưa đặt bất kỳ bộ lọc nào thì đối tượng này sẽ trống.

Đây là bài đăng trên blog tuyệt vời về việc sử dụng GET và POST. Nó đề cập đến giới hạn độ dài URL được đặt bởi Internet Explorer 2.048 ký tự, vì vậy bạn muốn sử dụng POST cho các yêu cầu dài.

http://carsonified.com/blog/dev/the-definitive-guide-to-get-vs-post/

5

Không có tất cả những điều đó không cần phải có trong mọi yêu cầu.

Mỗi tài nguyên (thuốc, lịch sử bệnh nhân, v.v ...) phải có URI chuẩn để nhận dạng duy nhất nó. Trong một số ứng dụng (ví dụ: các ứng dụng dựa trên Rails), điều này sẽ giống như "/ patient/1234" hoặc "/ drugs/5678" nhưng định dạng URL không quan trọng.

Một khách hàng đã nhận được URI trước đó cho một tài nguyên (chẳng hạn như từ tìm kiếm hoặc từ liên kết được nhúng trong tài nguyên khác) có thể truy xuất nó bằng URI này.

+0

Điều đó có ý nghĩa. Vì vậy, khi các đối tượng có thể được tạo động (người dùng có thể tạo bất kỳ số lượng bộ lọc nào), có vẻ như mỗi đối tượng sẽ cần được chỉ định một URI duy nhất. URI này sẽ được chuyển trở lại ứng dụng khách. Đúng không? – Alistair77

+0

@ alistair77: Đúng. Khi người dùng tạo ra một bộ lọc, một biểu diễn của nó phải được trả về, cùng với một tiêu đề 'Location' để chỉ ra nơi bộ lọc đó có thể được tìm thấy cho các hoạt động sau này. –

12

Để yên tâm, tất cả thông tin này có được bao gồm trong mọi yêu cầu không?

No. Nếu có vẻ như máy chủ của bạn đang gửi (hoặc nhận) quá nhiều thông tin, rất có thể là có một hoặc nhiều tài nguyên bạn chưa xác định.

Bước đầu tiên và quan trọng nhất trong việc thiết kế hệ thống RESTful là xác định và đặt tên tài nguyên của bạn. Làm thế nào bạn sẽ làm điều đó cho hệ thống của bạn?

Từ mô tả của bạn, đây là một bộ đa các nguồn lực:

  • tài - một người sử dụng của hệ thống (có thể là một bác sĩ hay bệnh nhân() - Vai trò có thể cần phải được tiếp xúc như một tài nguyên ở đây)
  • Thuốc - những thứ trong chai, nhưng nó cũng có thể đại diện cho loại chai (số lượng và nội dung), hoặc nó có thể đại diện cho một chai cụ thể - tùy thuộc vào việc bạn là hiệu thuốc hay chỉ bàn trợ giúp.
  • Bệnh - điều kiện mà Bệnh nhân có thể muốn dùng thuốc .
  • Bệnh nhân - một người có thể mất một thuốc
  • Khuyến nghị - một thuốc mà có thể có lợi cho một Bệnh nhân dựa trên một bệnh họ bị.

Sau đó, bạn có thể tìm kiếm mối quan hệ giữa các tài nguyên;

  • tài có và thuộc về nhiều Vai trò
  • Thuốc có và thuộc về nhiều Bệnh
  • Bệnh có nhiều Khuyến nghị.
  • Bệnh nhân có và thuộc về nhiều ThuốcBệnh (nghèo chap)
  • Bệnh nhân có nhiều Khuyến nghị
  • Khuyến nghị có một Bệnh nhân và có một Bệnh

Các chi tiết cụ thể có thể không phù hợp với vấn đề cụ thể của bạn, nhưng ý tưởng rất đơn giản: tạo một mạng lưới các mối quan hệ giữa các tài nguyên của bạn.

Tại thời điểm này, nó có thể hữu ích để suy nghĩ về cấu trúc URI, mặc dù ghi nhớ rằng REST APIs must be hypertext-driven:

# view all Recommendations for the patient 
GET http://server.com/patients/{patient}/recommendations 

# view all Recommendations for a Medication 
GET http://servier.com/medications/{medication}/recommendations 

# add a new Recommendation for a Patient 
PUT http://server.com/patients/{patient}/recommendations 

Bởi vì đây là REST, bạn sẽ dành phần lớn thời gian của bạn defining the media types sử dụng để chuyển cơ quan đại diện của tài nguyên của bạn giữa máy khách và máy chủ.

Bằng cách hiển thị nhiều tài nguyên hơn, bạn có thể giảm lượng dữ liệu cần chuyển trong mỗi yêu cầu. Cũng lưu ý không có tham số truy vấn trong URI. Các máy chủ có thể được như stateful như nó cần phải được theo dõi của tất cả, và mỗi yêu cầu có thể được hoàn toàn khép kín.

Các vấn đề liên quan