Mẫu được đề xuất cho kế hoạch điểm cuối REST là gì đối với các thay đổi có tầm nhìn xa


25

Cố gắng thiết kế API cho các ứng dụng bên ngoài với tầm nhìn xa để thay đổi là không dễ dàng, nhưng một chút suy nghĩ trước có thể giúp cuộc sống sau này dễ dàng hơn. Tôi đang cố gắng thiết lập một sơ đồ sẽ hỗ trợ các thay đổi trong tương lai trong khi vẫn tương thích ngược bằng cách đặt các trình xử lý phiên bản trước.

Mối quan tâm chính trong bài viết này là nên tuân theo mô hình nào cho tất cả các điểm cuối được xác định cho một sản phẩm / công ty nhất định.

Sơ đồ cơ sở

Đưa ra một mẫu URL cơ sở của https://rest.product.com/tôi đã nghĩ ra rằng tất cả các dịch vụ nằm /apicùng với /authvà các điểm cuối không dựa trên phần còn lại khác, chẳng hạn như /doc. Do đó tôi có thể thiết lập các điểm cuối cơ sở như sau:

https://rest.product.com/api/...
https://rest.product.com/auth/login
https://rest.product.com/auth/logout
https://rest.product.com/doc/...

Điểm cuối dịch vụ

Bây giờ cho các điểm cuối chính mình. Lo ngại về POST, GET, DELETEkhông phải là mục tiêu chính của bài viết này và là mối quan tâm về những hành động của bản thân.

Điểm cuối có thể được chia thành các không gian tên và hành động. Mỗi hành động cũng phải thể hiện chính nó theo cách hỗ trợ các thay đổi cơ bản trong kiểu trả về hoặc các tham số bắt buộc.

Sử dụng dịch vụ trò chuyện giả định trong đó người dùng đã đăng ký có thể gửi tin nhắn, chúng tôi có thể có các điểm cuối sau:

https://rest.product.com/api/messages/list/{user}
https://rest.product.com/api/messages/send

Bây giờ để thêm hỗ trợ phiên bản cho các thay đổi API trong tương lai có thể bị phá vỡ. Chúng tôi có thể thêm chữ ký phiên bản sau /api/hoặc sau /messages/. Cho sendđiểm cuối chúng ta có thể có đoạn sau cho v1.

https://rest.product.com/api/v1/messages/send
https://rest.product.com/api/messages/v1/send

Vì vậy, câu hỏi đầu tiên của tôi là, nơi được đề xuất cho định danh phiên bản là gì?

Quản lý mã điều khiển

Vì vậy, bây giờ chúng tôi đã thiết lập chúng tôi cần hỗ trợ các phiên bản trước mà chúng tôi cần để bằng cách nào đó xử lý mã cho từng phiên bản mới có thể không dùng nữa theo thời gian. Giả sử chúng ta đang viết các điểm cuối trong Java, chúng ta có thể quản lý điều này thông qua các gói.

package com.product.messages.v1;
public interface MessageController {
    void send();
    Message[] list();
}

Điều này có lợi thế là tất cả các mã đã được phân tách thông qua các không gian tên trong đó mọi thay đổi vi phạm sẽ có nghĩa là một bản sao mới của các điểm cuối dịch vụ. Bất lợi của điều này là tất cả các mã cần được sao chép và sửa lỗi mong muốn được áp dụng cho các phiên bản mới và trước đó cần được áp dụng / kiểm tra cho mỗi bản sao.

Một cách tiếp cận khác là tạo các trình xử lý cho mỗi điểm cuối.

package com.product.messages;
public class MessageServiceImpl {
    public void send(String version) {
        getMessageSender(version).send();
    }
    // Assume we have a List of senders in order of newest to oldest.
    private MessageSender getMessageSender(String version) {
        for (MessageSender s : senders) {
            if (s.supportsVersion(version)) {
                return s;
            }
        }
    }
}

Điều này hiện cách ly phiên bản với từng điểm cuối và sửa lỗi cổng tương thích bởi trong hầu hết các trường hợp chỉ cần được áp dụng một lần, nhưng điều đó có nghĩa là chúng ta cần thực hiện thêm một chút công việc cho từng điểm cuối riêng lẻ để hỗ trợ điều này.

Vì vậy, có câu hỏi thứ hai của tôi "Cách tốt nhất để thiết kế mã dịch vụ REST để hỗ trợ các phiên bản trước."

Câu trả lời:


13

Vì vậy, có câu hỏi thứ hai của tôi "Cách tốt nhất để thiết kế mã dịch vụ REST để hỗ trợ các phiên bản trước."

Một API trực giao được thiết kế rất cẩn thận và có thể sẽ không bao giờ cần phải thay đổi theo những cách không tương thích ngược, vì vậy thực sự cách tốt nhất là không có các phiên bản trong tương lai.

Tất nhiên, có lẽ bạn sẽ không thực sự có được điều đó ngay lần thử đầu tiên; Vì thế:

  • Phiên bản API của bạn, giống như bạn đang lập kế hoạch (và đó là API được phiên bản, không phải là các phương thức riêng lẻ bên trong) và gây ồn ào về nó. Đảm bảo rằng các đối tác của bạn biết rằng API có thể thay đổi và các ứng dụng của họ sẽ kiểm tra xem họ có đang sử dụng phiên bản mới nhất hay không; và khuyên người dùng nâng cấp khi có sẵn phiên bản mới hơn. Hỗ trợ hai phiên bản cũ là khó khăn, hỗ trợ năm là không thể.
  • Chống lại sự thôi thúc cập nhật phiên bản API với mỗi lần "phát hành". Các tính năng mới thường có thể được đưa vào phiên bản hiện tại mà không phá vỡ các máy khách hiện có; chúng là những tính năng mới. Điều cuối cùng bạn muốn là cho khách hàng bỏ qua số phiên bản, vì dù sao nó cũng tương thích ngược. Chỉ cập nhật phiên bản API khi bạn hoàn toàn không thể tiến lên mà không phá vỡ API hiện có.
  • Khi đến lúc tạo ra một phiên bản mới, ứng dụng khách đầu tiên phải là triển khai tương thích ngược của phiên bản trước. Bản thân "API bảo trì" nên được triển khai trên API hiện tại. Bằng cách này, bạn không gặp khó khăn gì trong việc thực hiện một số triển khai đầy đủ; chỉ phiên bản hiện tại và một số "vỏ" cho các phiên bản cũ. Chạy thử nghiệm hồi quy cho API hiện không dùng nữa đối với máy khách có thể xóa được là một cách tốt để kiểm tra cả API mới và lớp tương thích.

3

Tùy chọn thiết kế URI đầu tiên thể hiện rõ hơn ý tưởng rằng bạn đang phiên bản toàn bộ API. Thứ hai có thể được hiểu là phiên bản các tin nhắn. Vì vậy, đây là IMO tốt hơn:

rest.product.com/api/v1/messages/send

Đối với thư viện máy khách, tôi nghĩ rằng việc sử dụng hai triển khai đầy đủ trong các gói Java riêng biệt sẽ sạch hơn, dễ sử dụng hơn và dễ bảo trì hơn.

Điều đó đang được nói, có các phương pháp tốt hơn để phát triển API hơn là phiên bản. Tôi đồng ý với bạn rằng bạn nên chuẩn bị cho nó, nhưng tôi nghĩ rằng phiên bản là phương pháp cuối cùng, được sử dụng cẩn thận và tiết kiệm. Đó là một nỗ lực tương đối lớn cho khách hàng để nâng cấp. Cách đây không lâu, tôi đã đặt một vài trong số những suy nghĩ này vào một bài đăng trên blog:

http://theamiableapi.com/2011/10/18/api-design-best-practice-plan-for-evolution/

Đối với phiên bản API REST cụ thể, bạn sẽ thấy bài đăng này của Mark Nottingham hữu ích:

http://www.mnot.net/blog/2011/10/25/web_api_versioning_smackdown


3

Một cách tiếp cận khác để xử lý phiên bản API là sử dụng Phiên bản trong Tiêu đề HTTP. Như

POST /messages/list/{user} HTTP/1.1
Host: http://rest.service.com
Content-Type: application/json
API-Version: 1.0      <----- like here
Cache-Control: no-cache

Bạn có thể phân tích cú pháp tiêu đề và xử lý nó một cách thích hợp trong phần phụ trợ.

Với cách tiếp cận này, khách hàng không cần phải thay đổi URL, chỉ cần tiêu đề. Và điều này cũng làm cho các điểm cuối REST luôn sạch hơn.

Nếu bất kỳ khách hàng nào không gửi tiêu đề phiên bản, bạn sẽ gửi 400 - Yêu cầu xấu hoặc bạn có thể xử lý nó với phiên bản API tương thích ngược của bạn.

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.