2013-02-12 36 views
37

Tôi đã tìm kiếm trước tiên trong stackoverflow & Tôi không thể tìm ra bất kỳ câu trả lời nào liên quan đến câu hỏi của mình. Tất cả những gì tôi có thể tìm thấy là những câu hỏi liên quan đến thiết kế REST uri.Cách tốt nhất để xử lý phiên bản URI REST API JAX-RS

Câu hỏi của tôi ở phía bên phụ trợ. Giả sử chúng ta có hai phiên bản khác nhau của REST uri của

http://api.abc.com/rest/v1/products

http://api.abc.com/rest/v2/products

là gì phương pháp tốt nhất để làm theo ở phía backend (mã phía máy chủ) cho việc định tuyến thích hợp, quản lý & tái sử dụng hiện tại lớp học trên hai bộ dựa trên phiên bản của api?

Tôi đã nghĩ về cách tiếp cận để xác định các lớp tài nguyên với các chú thích @Path khác nhau cho ví dụ: có một gói cho v1 v2 & riêng & trong ProductsResource lớp của gói phần mềm đó, xác định

package com.abc.api.rest.v1.products; 
    @Path("/rest/v1/products") 
    public class ProductsResource {...} 

    package com.abc.api.rest.v2.products; 
    @Path("/rest/v2/products") 
    public class ProductsResource {...} 

& sau đó có logic thực hiện dựa trên các phiên bản. Các vấn đề với cách tiếp cận này là khi chúng ta chỉ thay đổi một api tài nguyên cụ thể từ tập hợp các api, chúng ta cũng phải sao chép các lớp khác vào gói v2. Chúng ta có thể tránh nó?

Cách viết chú thích tùy chỉnh cho biết @Version & có giá trị của các phiên bản mà nó hỗ trợ không? Bây giờ cho dù đó là v1 hay v2, cả hai yêu cầu sẽ đi đến cùng một lớp tài nguyên.

Nói ví dụ:

package com.abc.api.rest.products; 
    @Path("/rest/{version: [0-9]+}/products") 
    @Version(1,2) 
    public class ProductsResource {...} 

UPDATE:

Có một API versioning gợi ý bởi Jarrod để xử lý phiên bản trong tiêu đề. Đó cũng là một cách để thực hiện điều đó, tuy nhiên, tôi mong đợi các phương pháp hay nhất để sử dụng khi chúng tôi theo dõi phiên bản dựa trên URI

+4

thực tiễn tốt nhất là ** không ** đặt thông tin phiên bản api trong URL –

+5

Đây là một câu hỏi hay, tôi rất ngạc nhiên vì thiếu phản hồi. Có hàng trăm người tranh luận và chống lại phiên bản URI nhưng tất cả các trang web lớn đều làm điều đó vì nó rõ ràng và dễ dàng cho khách hàng sử dụng. @ Deepesh M - bạn đã sử dụng giải pháp nào cuối cùng? – arcseldon

+4

chỉ vì nhiều người làm những việc không chính xác không làm cho nó thành một ý tưởng tốt! nó chỉ có nghĩa là nhiều người đang làm điều đó không chính xác. –

Trả lời

13

Vấn đề đặt URL trong URL là phải đại diện cho tài nguyên theo vị trí. Phiên bản API không phải là một vị trí và nó không phải là một phần của định danh của tài nguyên.

Gắn bó /v2/ trong URL sẽ ngắt tất cả các liên kết hiện có trước đây.

Có hai cách thích hợp để xác định phiên bản API:

  1. Đặt nó trong mime-type cho Accept: tiêu đề mà bạn muốn. Một cái gì đó như Accept: application/myapp.2.0.1+json

  2. Đặt nó trong một Header không có trong URL. Sau đó, phương pháp của bạn đang xử lý tài nguyên có thể xem Header và xác định phương thức xử lý hoặc đối tượng nào cần gửi đến. Một cái gì đó như Version: 2.0.1

Chain of Responsiblity mẫu suôn sẻ ở đây đặc biệt là nếu sẽ có số lượng đáng kể các phiên bản API mà là khác nhau, đủ để cần phải có xử lý riêng của họ, rằng phương pháp cách không thoát khỏi tay.

+4

Tacking vào này - trong một ứng dụng RESTful, URL của bạn nên đại diện cho một nguồn tài nguyên. Tài nguyên có lẽ không phải là 'phiên bản'; nó giống nhau bất kể kiểu truy cập. Nếu tài nguyên _is_ được phiên bản, nó phải được đại diện trong tài nguyên, không phải trong mã định danh của nó. – cmonkey

+0

@cmonkey, bạn có thể đưa ra ví dụ không? –

+5

Ví dụ: tài khoản người dùng của tôi là tài nguyên trên SO. Url là: http://stackoverflow.com/users/322722/cmonkey. Khi/Nếu SO thay đổi tính năng, apis hoặc thêm dữ liệu vào tài khoản người dùng của tôi, tài khoản vẫn là tài nguyên giống nhau. Nó sẽ không đột nhiên trở thành http: //.../cmonkey_v2. Nếu không, nội dung được liên kết (như nhận xét này) sẽ không hoạt động nữa. – cmonkey

6

bài viết trên blog này có một ví dụ về những gì được coi là bởi một số người là cách tiếp cận đúng, tức là không có phiên bản trong URI: http://codebias.blogspot.ca/2014/03/versioning-rest-apis-with-custom-accept.html

Nói tóm lại, nó thúc đẩy JAX-RS @Consume chú thích để kết hợp yêu cầu cho một phiên bản đặc biệt đến việc thực hiện cụ thể, như:

@Consumes({"application/vnd.blog.v1+xml", "application/vnd.blog.v1+json"}) 
+2

Ai đã xác định những gì được coi là đường dẫn chính xác? REST là một phong cách kiến ​​trúc và không có giao thức! Trừ khi bạn vi phạm HTTP hoặc không tuân theo [ràng buộc kiến ​​trúc] (https://en.wikipedia.org/wiki/Representational_state_transfer#Architectural_constraints) không có quyền hoặc sai, có thể một số thực tiễn tốt nhất mặc dù một số dịch vụ REST tự xác nhận là aren 't RESTful trong bất kỳ cách nào do đó báo cáo nhất định nên được điều trị với sự chăm sóc đặc biệt. –

+0

Bạn nói đúng, tôi đã giảm bớt và thêm vào "bởi một số người" để nhấn mạnh rằng không phải ai cũng đồng ý. –

2

tôi chỉ thắc mắc tại sao không có một lớp con của ProductService gọi

@Path(/v2/ProductService) 
ProductServiceV2 extends ProductService { 


} 


@Path(/v1/ProductService) 
class ProductService{ 


} 

và chỉ ghi đè bất kỳ nội dung nào được thay đổi trong phiên bản 2. Mọi thứ không thay đổi sẽ hoạt động giống như trong v1/ProductService.

Điều này chắc chắn dẫn đến nhiều lớp hơn nhưng là một cách dễ dàng hơn để mã hóa cho bất kỳ thứ gì đang thay đổi trong phiên bản api mới và hoàn nguyên về phiên bản cũ mà không cần sao chép mã.

+0

Đó cũng là suy nghĩ ban đầu của tôi :) Tôi nhớ lại cách EclipseLink thực hiện hỗ trợ các phương ngữ JPA theo cách tương tự (Oracle11Platform mở rộng Oracle10Platform, v.v.). Nhưng sau đó, tôi nghĩ rằng nó sẽ rất lộn xộn với REST. Chỉ cần tưởng tượng có để mở rộng tất cả các lớp học của bạn phiên bản sau khi phiên bản. Tôi thích cách tiếp cận với các tham số Header. – jFrenetic

+4

Điều này quá ngắn ngủi, nó thậm chí còn không vui. Bạn sẽ phải duy trì '30' các phương thức hoặc lớp khác nhau cho mỗi' URL' trong ứng dụng của bạn khi bạn nhận được 'v30'? Không quy mô. –

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