Chiến Lược Quản Lý Phiên Bản API Tốt Nhất: URL, Header hay Content Negotiation?

Ashley Innocent

Ashley Innocent

13 tháng 3 2026

Chiến Lược Quản Lý Phiên Bản API Tốt Nhất: URL, Header hay Content Negotiation?

Apidog cho doanh nghiệp

Triển khai tại chỗ

SSO & RBAC

Tuân thủ SOC 2

Khám phá Apidog Enterprise

Tóm tắt

Phiên bản hóa URL (/v1/pets) là chiến lược phiên bản hóa API thực tế nhất cho hầu hết các nhóm. Nó dễ nhìn thấy, có thể lưu vào bộ nhớ cache và dễ kiểm thử. Phiên bản hóa qua tiêu đề và đàm phán nội dung "thuần" REST hơn nhưng làm tăng độ phức tạp. Modern PetstoreAPI sử dụng phiên bản hóa URL với phiên bản hóa ngữ nghĩa và các chính sách ngừng hỗ trợ rõ ràng.

Giới thiệu

API của bạn cần một thay đổi gây hỏng. Bạn đang thay đổi định dạng phản hồi cho /pets từ một mảng trần sang một đối tượng bao bọc với siêu dữ liệu phân trang. Các client hiện có sẽ bị hỏng. Bạn sẽ làm gì?

Bạn cần phiên bản hóa API. Nhưng chiến lược nào? Phiên bản hóa URL (/v1/pets so với /v2/pets)? Phiên bản hóa qua tiêu đề (Accept: application/vnd.petstore.v1+json)? Đàm phán nội dung? Mỗi cách tiếp cận đều có những người ủng hộ nhiệt tình và những quan điểm mạnh mẽ.

Câu trả lời: Phiên bản hóa URL thắng thế đối với hầu hết các nhóm. Nó thực dụng, dễ nhìn thấy và hoạt động với tất cả các công cụ HTTP. Phiên bản hóa qua tiêu đề và đàm phán nội dung về mặt lý thuyết là sạch hơn nhưng làm tăng độ phức tạp mà hầu hết các nhóm không cần.

Modern PetstoreAPI sử dụng phiên bản hóa URL với phiên bản hóa ngữ nghĩa và các chính sách ngừng hỗ trợ rõ ràng. Phiên bản hiện tại là v1, với v2 được lên kế hoạch cho các thay đổi gây hỏng trong tương lai.

💡
Nếu bạn đang xây dựng hoặc kiểm thử REST API, Apidog giúp bạn kiểm thử nhiều phiên bản API, xác thực hành vi cụ thể theo phiên bản và đảm bảo khả năng tương thích ngược. Bạn có thể duy trì các thông số kỹ thuật riêng cho từng phiên bản và chạy thử nghiệm trên tất cả các phiên bản cùng lúc.
button

Trong hướng dẫn này, bạn sẽ tìm hiểu ba chiến lược phiên bản hóa chính, những đánh đổi của chúng và cách triển khai phiên bản hóa một cách chính xác bằng cách sử dụng Modern PetstoreAPI làm tài liệu tham khảo.

Tại sao API cần phiên bản hóa

API phát triển. Bạn thêm tính năng, sửa lỗi và cải thiện thiết kế. Đôi khi những thay đổi này làm hỏng các client hiện có.

Những thay đổi gây hỏng (Breaking Changes)

Những thay đổi làm hỏng các client hiện có:

1. Xóa trường:

// v1
{"id": "123", "name": "Fluffy", "age": 3}

// v2 (gây hỏng: đã xóa age)
{"id": "123", "name": "Fluffy"}

2. Thay đổi kiểu trường:

// v1
{"price": "19.99"}

// v2 (gây hỏng: chuỗi sang số)
{"price": 19.99}

3. Thay đổi cấu trúc phản hồi:

// v1 (mảng trần)
[{"id": "123"}]

// v2 (gây hỏng: đối tượng bao bọc)
{"data": [{"id": "123"}], "pagination": {...}}

4. Thay đổi cấu trúc URL:

// v1
GET /pet/123

// v2 (gây hỏng: số nhiều)
GET /pets/123

5. Thay đổi xác thực:

// v1: API key trong truy vấn
GET /pets?api_key=xxx

// v2 (gây hỏng: mã thông báo Bearer)
GET /pets
Authorization: Bearer xxx

Những thay đổi không gây hỏng (Non-Breaking Changes)

Những thay đổi không làm hỏng client:

Quyết định phiên bản hóa

Khi bạn cần một thay đổi gây hỏng, bạn có hai lựa chọn:

1. Buộc tất cả các client phải nâng cấp - Đơn giản nhưng làm hỏng các tích hợp hiện có

2. Hỗ trợ nhiều phiên bản - Tốn nhiều công sức hơn nhưng duy trì khả năng tương thích ngược

Hầu hết các API công khai chọn tùy chọn 2. Phiên bản hóa cho phép bạn phát triển API trong khi vẫn cho client thời gian để di chuyển.

Phiên bản hóa URL

Phiên bản hóa URL đặt số phiên bản vào đường dẫn URL.

Cách hoạt động

GET /v1/pets
GET /v2/pets

Phiên bản là một phần của định danh tài nguyên. Các phiên bản khác nhau là các tài nguyên khác nhau.

Ưu điểm

1. Rõ ràng và tường minh

Phiên bản nằm trong URL. Bạn có thể thấy nó trong nhật ký, lịch sử trình duyệt và tài liệu. Không cần phải nhớ các tiêu đề ẩn.

2. Dễ kiểm thử

curl https://petstoreapi.com/v1/pets
curl https://petstoreapi.com/v2/pets

Bạn có thể kiểm thử cả hai phiên bản bằng các yêu cầu HTTP đơn giản.

3. Hoạt động với tất cả các công cụ HTTP

Trình duyệt, bộ nhớ cache, proxy và bộ cân bằng tải xem các URL khác nhau. Chúng có thể định tuyến, lưu vào bộ nhớ cache và ghi nhật ký từng phiên bản một cách độc lập.

4. Đơn giản cho client

Các client chỉ cần thay đổi URL. Không có tiêu đề tùy chỉnh hoặc logic đàm phán nội dung.

5. Dễ dàng ngừng hỗ trợ

Bạn có thể loại bỏ các endpoint /v1 mà không ảnh hưởng đến /v2.

Nhược điểm

1. Không "thuần" REST

Những người theo chủ nghĩa thuần túy REST lập luận rằng /v1/pets/123/v2/pets/123 là cùng một tài nguyên, vì vậy chúng nên có cùng URL. Phiên bản nên nằm trong tiêu đề hoặc đàm phán nội dung.

2. Ô nhiễm URL

API của bạn có nhiều không gian URL: /v1/*, /v2/*, v.v.

3. Khó phiên bản hóa các tài nguyên riêng lẻ hơn

Nếu bạn muốn phiên bản hóa chỉ một endpoint, bạn cần phiên bản hóa toàn bộ API hoặc tạo ra sự không nhất quán.

Triển khai

Phiên bản chính trong URL:

/v1/pets
/v2/pets

Không bao gồm các phiên bản nhỏ:

❌ /v1.2/pets  (quá chi tiết)
✅ /v1/pets    (chỉ phiên bản chính)

Sử dụng phiên bản hóa ngữ nghĩa nội bộ:

Modern PetstoreAPI sử dụng phiên bản hóa URL với /v1 là phiên bản hiện tại.

Phiên bản hóa qua tiêu đề

Phiên bản hóa qua tiêu đề đặt số phiên bản vào một tiêu đề HTTP tùy chỉnh.

Cách hoạt động

GET /pets
API-Version: 1

GET /pets
API-Version: 2

URL giữ nguyên. Tiêu đề chỉ định phiên bản.

Ưu điểm

1. URL sạch

/pets giống nhau cho tất cả các phiên bản. Không có tiền tố /v1 hoặc /v2.

2. "RESTful" hơn

Định danh tài nguyên (/pets/123) không thay đổi. Biểu diễn thay đổi dựa trên tiêu đề.

3. Phiên bản hóa chi tiết

Bạn có thể phiên bản hóa các tài nguyên riêng lẻ:

GET /pets
API-Version: 2

GET /orders
API-Version: 1

Nhược điểm

1. Không hiển thị

Phiên bản không nằm trong URL. Bạn không thể thấy nó trong nhật ký hoặc lịch sử trình duyệt nếu không kiểm tra tiêu đề.

2. Khó kiểm thử hơn

curl -H "API-Version: 1" https://petstoreapi.com/pets
curl -H "API-Version: 2" https://petstoreapi.com/pets

Bạn phải nhớ bao gồm tiêu đề.

3. Độ phức tạp bộ nhớ cache

Bộ nhớ cache phải xem xét tiêu đề API-Version. Bạn cần Vary: API-Version trong các phản hồi.

4. Độ phức tạp của client

Các client cần logic tiêu đề tùy chỉnh. Không phải tất cả các client HTTP đều làm điều này dễ dàng.

5. Sự mơ hồ của phiên bản mặc định

Điều gì xảy ra nếu client không gửi tiêu đề? Bạn cần một giá trị mặc định, điều này tạo ra hành vi ngầm định.

Triển khai

Tiêu đề tùy chỉnh:

API-Version: 1

Hoặc sử dụng tiêu đề Accept:

Accept: application/vnd.petstore.v1+json

Bao gồm tiêu đề Vary:

Vary: API-Version

Điều này cho bộ nhớ cache biết phải xem xét tiêu đề khi lưu vào bộ nhớ cache.

Đàm phán nội dung

Đàm phán nội dung sử dụng tiêu đề Accept với các kiểu phương tiện tùy chỉnh.

Cách hoạt động

GET /pets
Accept: application/vnd.petstore.v1+json

GET /pets
Accept: application/vnd.petstore.v2+json

Phiên bản là một phần của kiểu phương tiện.

Ưu điểm

1. "RESTful" nhất

Đây là cách REST được thiết kế. Các biểu diễn khác nhau của cùng một tài nguyên.

2. Tuân thủ các tiêu chuẩn HTTP

Sử dụng đàm phán nội dung HTTP tiêu chuẩn.

3. Hỗ trợ nhiều định dạng

Bạn có thể phiên bản hóa và định dạng đồng thời:

Accept: application/vnd.petstore.v1+json
Accept: application/vnd.petstore.v1+xml

Nhược điểm

1. Phức tạp

Các client phải hiểu các kiểu phương tiện và đàm phán nội dung.

2. Khó kiểm thử hơn

curl -H "Accept: application/vnd.petstore.v1+json" https://petstoreapi.com/pets

3. Hỗ trợ công cụ kém

Nhiều client và công cụ HTTP không xử lý tốt các kiểu phương tiện tùy chỉnh.

4. Độ phức tạp bộ nhớ cache

Bộ nhớ cache phải xem xét tiêu đề Accept. Bạn cần Vary: Accept.

5. Không cần thiết đối với hầu hết các API

Hầu hết các API không cần mức độ tinh vi này.

Triển khai

Kiểu phương tiện dành riêng cho nhà cung cấp:

Accept: application/vnd.petstore.v1+json

Phản hồi:

Content-Type: application/vnd.petstore.v1+json
Vary: Accept

Cách Modern PetstoreAPI triển khai phiên bản hóa

Modern PetstoreAPI sử dụng phiên bản hóa URL với các chính sách rõ ràng.

Phiên bản hiện tại: v1

https://petstoreapi.com/v1/pets
https://petstoreapi.com/v1/orders
https://petstoreapi.com/v1/users

Tất cả các endpoint đều nằm dưới /v1.

Tiêu đề phản hồi phiên bản

Mỗi phản hồi đều bao gồm phiên bản API:

X-API-Version: 1.2.0

Điều này hiển thị phiên bản chính xác (major.minor.patch) mặc dù URL chỉ hiển thị phiên bản chính.

Cảnh báo ngừng hỗ trợ

Khi một phiên bản bị ngừng hỗ trợ, các phản hồi bao gồm:

Deprecation: true
Sunset: Sat, 31 Dec 2026 23:59:59 GMT
Link: <https://docs.petstoreapi.com/migration/v1-to-v2>; rel="deprecation"

Khám phá phiên bản

Endpoint gốc liệt kê các phiên bản có sẵn:

GET https://petstoreapi.com/

{
  "versions": [
    {
      "version": "v1",
      "status": "current",
      "docsUrl": "https://docs.petstoreapi.com/v1"
    }
  ]
}

Phiên bản hóa ngữ nghĩa

Modern PetstoreAPI tuân theo phiên bản hóa ngữ nghĩa nội bộ:

Chỉ các phiên bản chính xuất hiện trong URL.

Kiểm thử các phiên bản API với Apidog

Apidog giúp bạn kiểm thử nhiều phiên bản API.

Nhập nhiều phiên bản

Nhập các thông số kỹ thuật OpenAPI cho mỗi phiên bản:

petstore-v1.yaml → Environment: v1
petstore-v2.yaml → Environment: v2

Chạy kiểm thử trên tất cả các phiên bản

Tạo các bộ kiểm thử chạy trên cả hai phiên bản:

// Kiểm thử v1
pm.environment.set("baseUrl", "https://petstoreapi.com/v1");
pm.sendRequest(pm.environment.get("baseUrl") + "/pets");

// Kiểm thử v2
pm.environment.set("baseUrl", "https://petstoreapi.com/v2");
pm.sendRequest(pm.environment.get("baseUrl") + "/pets");

Xác thực hành vi cụ thể theo phiên bản

Kiểm thử v1 và v2 hoạt động khác nhau:

// v1 trả về mảng trần
pm.test("v1 returns array", function() {
    pm.expect(pm.response.json()).to.be.an('array');
});

// v2 trả về đối tượng bao bọc
pm.test("v2 returns wrapped object", function() {
    pm.expect(pm.response.json()).to.have.property('data');
    pm.expect(pm.response.json()).to.have.property('pagination');
});

Kiểm tra tiêu đề ngừng hỗ trợ

Kiểm thử các phiên bản đã ngừng hỗ trợ bao gồm các tiêu đề thích hợp:

pm.test("Deprecated version includes headers", function() {
    pm.response.to.have.header("Deprecation");
    pm.response.to.have.header("Sunset");
});

Chiến lược ngừng hỗ trợ phiên bản

Cách ngừng hỗ trợ các phiên bản cũ mà không làm hỏng các client.

1. Thông báo ngừng hỗ trợ sớm

Thông báo cho client ít nhất 6-12 tháng:

Deprecation: true
Sunset: Sat, 31 Dec 2026 23:59:59 GMT

2. Cung cấp hướng dẫn di chuyển

Tài liệu hóa tất cả các thay đổi gây hỏng và cách di chuyển:

Link: <https://docs.petstoreapi.com/migration/v1-to-v2>; rel="deprecation"

3. Giám sát việc sử dụng

Theo dõi những client nào vẫn sử dụng các phiên bản đã ngừng hỗ trợ:

X-API-Version: 1.2.0
X-Client-ID: abc123

Liên hệ trực tiếp với client nếu cần.

4. Tắt dần

Không gỡ bỏ phiên bản ngay lập tức:

  1. Tháng 1-6: Thông báo ngừng hỗ trợ
  2. Tháng 7-9: Thêm tiêu đề ngừng hỗ trợ
  3. Tháng 10-11: Giảm giới hạn tốc độ cho phiên bản đã ngừng hỗ trợ
  4. Tháng 12: Gỡ bỏ phiên bản đã ngừng hỗ trợ

5. Giữ lại tài liệu

Ngay cả sau khi gỡ bỏ, hãy giữ lại tài liệu cho phiên bản cũ. Client có thể cần tham khảo nó.

Kết luận

Phiên bản hóa URL là chiến lược phiên bản hóa API thực tế nhất cho hầu hết các nhóm. Nó dễ nhìn thấy, dễ kiểm thử và hoạt động với tất cả các công cụ HTTP. Phiên bản hóa qua tiêu đề và đàm phán nội dung "thuần" REST hơn nhưng làm tăng độ phức tạp.

Modern PetstoreAPI sử dụng phiên bản hóa URL với /v1 là phiên bản hiện tại, phiên bản hóa ngữ nghĩa nội bộ và các chính sách ngừng hỗ trợ rõ ràng. Cách tiếp cận này cân bằng giữa tính thực dụng và thiết kế API tốt.

Sử dụng Apidog để kiểm thử nhiều phiên bản API, xác thực hành vi cụ thể theo phiên bản và đảm bảo quá trình di chuyển mượt mà giữa các phiên bản.

button

Câu hỏi thường gặp

Tôi nên sử dụng phiên bản hóa URL hay phiên bản hóa tiêu đề?

Hãy sử dụng phiên bản hóa URL trừ khi bạn có lý do cụ thể để không làm vậy. Nó đơn giản hơn, dễ nhìn thấy hơn và dễ kiểm thử hơn. Phiên bản hóa qua tiêu đề "RESTful" hơn nhưng làm tăng độ phức tạp mà hầu hết các nhóm không cần.

Tôi nên hỗ trợ bao nhiêu phiên bản đồng thời?

Hỗ trợ tối đa 2 phiên bản: hiện tại và trước đó. Hỗ trợ nhiều hơn sẽ tạo gánh nặng bảo trì. Cho client 6-12 tháng để di chuyển, sau đó gỡ bỏ các phiên bản cũ.

Tôi nên bắt đầu phiên bản từ v0 hay v1?

Bắt đầu với v1. v0 ngụ ý sự không ổn định. Nếu API của bạn chưa đủ ổn định cho v1, đừng phát hành công khai.

Tôi có cần phiên bản hóa mọi endpoint không?

Không. Chỉ phiên bản hóa khi bạn thực hiện các thay đổi gây hỏng. Nếu bạn thêm các endpoint mới mà không thay đổi các endpoint hiện có, bạn không cần một phiên bản mới.

Còn các phiên bản nhỏ trong URL thì sao?

Không bao gồm các phiên bản nhỏ trong URL. Sử dụng /v1, không phải /v1.2. Các phiên bản nhỏ tương thích ngược, vì vậy các client không cần thay đổi URL.

Làm thế nào để xử lý các lỗi cụ thể theo phiên bản?

Sửa lỗi trong tất cả các phiên bản được hỗ trợ. Nếu một lỗi chỉ tồn tại trong v1, hãy sửa nó trong v1. Đừng buộc các client phải nâng cấp lên v2 để sửa lỗi.

Tôi có nên sử dụng phiên bản hóa ngữ nghĩa không?

Có, nội bộ. Theo dõi các phiên bản major.minor.patch, nhưng chỉ hiển thị các phiên bản chính trong URL. Điều này mang lại cho bạn sự linh hoạt cho các thay đổi không gây hỏng.

Điều gì nếu tôi chỉ cần phiên bản hóa một endpoint?

Với phiên bản hóa URL, bạn sẽ cần phiên bản hóa toàn bộ API hoặc tạo ra sự không nhất quán. Đây là một sự đánh đổi. Hầu hết các nhóm chấp nhận phiên bản hóa toàn bộ API để đơn giản.

Thực hành thiết kế API trong Apidog

Khám phá cách dễ dàng hơn để xây dựng và sử dụng API