1. 概述
在本教程中,我們將探討如何利用 Micronaut 框架 的能力來實現不斷演進的 REST API。
在軟件開發項目不斷演進的背景下,僅僅基於 REST API 時,在引入新功能和改進的同時保持向後兼容性是一個關鍵挑戰。實現這一點的一個基本方面是實施一種稱為 API 版本控制的技術。
我們將探討 API 版本控制的概念,並將其置於 Micronaut 的背景下,Micronaut 是一款流行的微服務框架,用於構建高效且可擴展的應用程序。我們將深入研究 API 版本控制的重要性、在 Micronaut 中實施的不同策略以及最佳實踐,以確保平穩的版本過渡。
2. API 版本的重要性
API 版本控制是管理和演進應用程序編程接口 (API) 的實踐,允許客户端在準備好時繼續使用現有版本,同時採用更新的版本。 這對於以下幾個原因至關重要。
2.1. 保持兼容性
隨着我們的應用程序不斷髮展,我們可能需要更改我們的 API 以引入新功能、修復錯誤或提高性能。然而,也必須確保這些更改不會影響現有客户端。通過 API 版本控制,我們可以在不影響先前版本兼容性的情況下引入更改。
2.2. 逐步採用
我們的API客户可能具有不同的版本採用時間表。因此,提供多個API版本,允許客户在合理的採用時間內更新其代碼,從而降低對現有應用程序造成中斷的風險。
2.3. 促進協作
它還促進了開發團隊之間的協作。當不同的團隊在系統的其他部分工作,或者第三方開發者與我們的API集成時,版本控制允許每個團隊在其他地方進行更改的情況下,都擁有一個穩定的接口。
3. Micronaut 中 API 版本控制策略
Micronaut 提供多種 API 版本控制策略。 我們不會討論哪一種策略是最好的,因為它很大程度上取決於用例和項目的實際情況。 儘管如此,我們可以討論每種策略的具體細節。
3.1. URI 版本控制
在 URI 版本控制中,API 的版本定義在 URI 中。 這種方法明確了客户端正在消費的 API 版本。 儘管 URL 可能不如它那樣用户友好,但它向客户端明確了它使用的版本。
@Controller("/v1/sheep/count")
public class SheepCountControllerV1 {
@Get(
uri = "{?max}",
consumes = {"application/json"},
produces = {"application/json"}
)
Flowable<String> countV1(@Nullable Integer max) {
// implementation
雖然可能並不實用,但我們的客户對使用的版本非常確定,這意味着透明度。從開發角度來看,很容易實現特定版本的任何業務規則,這意味着良好的隔離性。然而,有人可能會認為這具有侵入性,因為URI可能會頻繁更改。這可能需要在客户端端進行硬編碼,並添加不完全特定於資源的額外上下文。
3.2. 頭部版本控制
另一個實現 API 版本控制的方法是利用頭部路由請求到正確的控制器。下面是一個示例:
@Controller("/dog")
public class DogCountController {
@Get(value = "/count", produces = {"application/json"})
@Version("1")
public Flowable<String> countV1(@QueryValue("max") @Nullable Integer max) {
// logic
}
@Get(value = "/count", produces = {"application/json"})
@Version("2")
public Flowable<String> countV2(@QueryValue("max") @NonNull Integer max) {
// logic
}
}
通過僅僅使用 @Version 註解,Microunat 可以根據請求頭的值將請求重定向到正確的處理器。但是,我們仍然需要修改一些配置,如下所述:
micronaut:
router:
versioning:
enabled: true
default-version: 2
header:
enabled: true
names:
- 'X-API-VERSION'我們現在已通過 Micronaut 啓用了版本控制,在未指定版本時,將版本 2 定義為默認版本。所採用的策略是基於頭信息的,並且使用頭信息 X-API-VERSION 來確定版本。實際上,這正是 Micronaut 默認檢查的頭信息,因此在這種情況下,無需定義它,但如果希望使用另一個頭信息,可以這樣指定。
使用頭信息,URI 保持清晰簡潔,我們可以保持向後兼容性,URI 純粹基於資源,並且允許 API 在演進過程中具有更大的靈活性。但是,它不太直觀且不易察覺。客户端必須意識到他想要使用的版本,並且略顯容易出錯。 還有一種類似的策略是使用 MIME 類型。
3.3. 參數版本控制
該策略利用 URI 中的查詢參數進行路由。在 Mircronaut 中的實現上,它與之前的策略完全相同。我們只需要在我們的控制器中添加 @Version 屬性。但是,我們需要更改一些屬性:
micronaut:
router:
versioning:
enabled: true
default-version: 2
parameter:
enabled: true
names: 'v,api-version'通過此方法,客户端只需在每個請求中將 v 或 api-version 作為查詢參數傳遞,Micronat 將負責路由。
再次使用此策略時,URI 將不包含任何與資源相關的信息,儘管不如直接更改 URI 那麼方便。此外,版本控制也更不明確且更容易出錯。這不符合 RESTful 規範,因此需要提供文檔以避免混淆。然而,我們也可以欣賞該解決方案的簡潔性。
3.4. 自定義版本控制
Micronaut 還提供了一種自定義的 API 版本控制方式,其中我們可以實現一個版本路由解析器並告知 Micronaut 使用哪個版本。 實現方式簡單,我們只需要實現一個接口,如以下示例所示:
@Singleton
@Requires(property = "my.router.versioning.enabled", value = "true")
public class CustomVersionResolver implements RequestVersionResolver {
@Inject
@Value("${micronaut.router.versioning.default-version}")
private String defaultVersion;
@Override
public Optional<String> resolve(HttpRequest<?> request) {
var apiKey = Optional.ofNullable(request.getHeaders().get("api-key"));
if (apiKey.isPresent() && !apiKey.get().isEmpty()) {
return Optional.of(Integer.parseInt(apiKey.get()) % 2 == 0 ? "2" : "1");
}
return Optional.of(defaultVersion);
}
}
在這裏,我們可以看到如何利用請求中的任何信息來實施路由策略,而 Micronaut 會完成其餘工作。 這非常強大,但我們需要謹慎,因為這可能會導致版本控制實施方式不佳且不直觀。
4. 結論
在本文中,我們瞭解到如何使用 Micronaut 實現 API 版本控制。此外,我們還探討了各種應用該技術的策略及其細微差別。
同時,明確的是,選擇合適的策略需要權衡 URI 清潔度、版本明確性、易用性、向後兼容性、RESTful 規範以及消費 API 的客户端特定需求等因素。 最佳方法取決於我們項目的獨特要求和約束條件。