RESTful API如何進(jìn)行版本控制

本文將幫助您理解為什么需要版本控制,以及如何對(duì)REST API進(jìn)行版本控制。我們將討論4種版本控制的方法,并比較不同的方法。
您將學(xué)到
為什么我們需要對(duì)RESTful API 進(jìn)行版本控制? 可用的版本控制有哪些? 如何實(shí)現(xiàn)基于 Restful 的版本控制?
為什么我們需要對(duì)RESTful API進(jìn)行版本化
最好的版本控制方法是不進(jìn)行版本控制。只要不需要版本控制,就不要版本控制。
構(gòu)建向后兼容的服務(wù),以便盡可能避免版本控制!
然而,在許多情況下我們都需要進(jìn)行版本控制,然我們看看下面具體的例子:
最初,你有個(gè)這個(gè)版本的Student服務(wù),返回?cái)?shù)據(jù)如下:
{
??"name":?"Bob?Charlie"
}
后來(lái),您希望將學(xué)生的名字拆分,因此創(chuàng)建了這個(gè)版本的服務(wù)。
{
??"name":?{
????"firstName":?"Bob",
????"lastName":?"Charlie"
??}
}
您可以從同一個(gè)服務(wù)支持這兩個(gè)請(qǐng)求,但是隨著每個(gè)版本的需求多樣化,它會(huì)變得越來(lái)越復(fù)雜。
在這種情況下,版本控制就成必不可少,強(qiáng)制性的了。
接下來(lái)讓我們創(chuàng)建一個(gè)簡(jiǎn)單的SpringBoot的maven項(xiàng)目,并理解對(duì) RESTful 服務(wù)進(jìn)行版本控制的4種不同方法。
<dependencies>
?<dependency>
??<groupId>org.springframework.bootgroupId>
??<artifactId>spring-boot-starterartifactId>
?dependency>
?<dependency>
??<groupId>org.springframework.bootgroupId>
??<artifactId>spring-boot-starter-webartifactId>
?dependency>
?<dependency>
??<groupId>org.projectlombokgroupId>
??<artifactId>lombokartifactId>
?dependency>
?<dependency>
??<groupId>org.springframework.bootgroupId>
??<artifactId>spring-boot-starter-testartifactId>
??<scope>testscope>
?dependency>
dependencies>
幾個(gè)用于實(shí)現(xiàn)版本控制的Bean
第一個(gè)版本的 Bean
@Data
@AllArgsConstructor
public?class?StudentV1?{
????private?String?name;
}
第二個(gè)版本的 Bean
@Data
public?class?StudentV2?{
????private?Name?name;
}
StudentV2使用的Name實(shí)體
@Data
@AllArgsConstructor
public?class?Name?{
????private?String?firstName;
????private?String?lastName;
}
Restful 版本控制的方法
我們希望創(chuàng)建兩個(gè)版本的服務(wù),一個(gè)返回 StudentV1,另一個(gè)返回 StudentV2。
讓我們來(lái)看看創(chuàng)建相同服務(wù)版本的4種不同方法。
通過(guò) URI 進(jìn)行版本控制
@RestController
public?class?StudentUriController?{
????@GetMapping("v1/student")
????public?StudentV1?studentV1()?{
????????return?new?StudentV1("javadaily");
????}
????@GetMapping("v2/student")
????public?StudentV2?studentV2()?{
????????return?new?StudentV2(new?Name("javadaily",?"JAVA日知錄"));
????}
}
請(qǐng)求:http://localhost:8080/v1/student
響應(yīng):{"name":"javadaily"}
請(qǐng)求:http://localhost:8080/v2/student
響應(yīng):{"name":{"firstName":"javadaily","lastName":"JAVA日知錄"}}
通過(guò)請(qǐng)求參數(shù)進(jìn)行版本控制
版本控制的第二種方法是使用請(qǐng)求參數(shù)來(lái)區(qū)分版本。請(qǐng)求示例如下所示:
http://localhost:8080/student/param?version=1http://localhost:8080/student/param?version=2
實(shí)現(xiàn)方式如下:
@RestController
public?class?StudentParmController?{
????@GetMapping(value="/student/param",params?=?"version=1")
????public?StudentV1?studentV1()?{
????????return?new?StudentV1("javadaily");
????}
????@GetMapping(value="/student/param",params?=?"version=2")
????public?StudentV2?studentV2()?{
????????return?new?StudentV2(new?Name("javadaily",?"JAVA日知錄"));
????}
}
請(qǐng)求:http://localhost:8080/student/param?version=1
響應(yīng):{"name":"javadaily"}
請(qǐng)求:http://localhost:8080/student/param?version=2
響應(yīng):{"name":{"firstName":"javadaily","lastName":"JAVA日知錄"}}
通過(guò)自定義Header進(jìn)行版本控制
版本控制的第三種方法是使用請(qǐng)求頭來(lái)區(qū)分版本,請(qǐng)求示例如下:
http://localhost:8080/student/headerheaders=[X-API-VERSION=1] http://localhost:8080/student/headerheaders=[X-API-VERSION=2]
實(shí)現(xiàn)方式如下所示:
@RestController
public?class?StudentHeaderController?{
????@GetMapping(value="/student/header",headers?=?"X-API-VERSION=1")
????public?StudentV1?studentV1()?{
????????return?new?StudentV1("javadaily");
????}
????@GetMapping(value="/student/header",headers?=?"X-API-VERSION=2")
????public?StudentV2?studentV2()?{
????????return?new?StudentV2(new?Name("javadaily",?"JAVA日知錄"));
????}
}
下圖展示了我們?nèi)绾问褂肞ostman執(zhí)行帶有請(qǐng)求頭的Get請(qǐng)求方法。
請(qǐng)求:http://localhost:8080/student/header
header:X-API-VERSION = 1

請(qǐng)求:http://localhost:8080/student/header
header:X-API-VERSION = 2

通過(guò)媒體類(lèi)型進(jìn)行版本控制
最后一種版本控制方法是在請(qǐng)求中使用Accept Header,請(qǐng)求示例如下:
http://localhost:8080/student/produceheaders=[Accept=application/api-v1+json]http://localhost:8080/student/produceheaders=[Accept=application/api-v2+json]
實(shí)現(xiàn)方式如下:
@RestController
public?class?StudentProduceController?{
????@GetMapping(value="/student/produce",produces?=?"application/api-v1+json")
????public?StudentV1?studentV1()?{
????????return?new?StudentV1("javadaily");
????}
????@GetMapping(value="/student/produce",produces?=?"application/api-v2+json")
????public?StudentV2?studentV2()?{
????????return?new?StudentV2(new?Name("javadaily",?"JAVA日知錄"));
????}
}
下圖展示了我們?nèi)绾问褂肞ostman執(zhí)行帶有請(qǐng)求Accept的Get方法。
請(qǐng)求:http://localhost:8080/student/produce
header:Accept = application/api-v1+json

請(qǐng)求:http://localhost:8080/student/produce
header:Accept = application/api-v2+json

影響版本選擇的因素
以下因素影響版本控制的選擇
URI 污染 - URL版本和請(qǐng)求參數(shù)版本控制會(huì)污染URI空間。 濫用請(qǐng)求頭 - Accept 請(qǐng)求頭并不是為版本控制而設(shè)計(jì)的。 緩存 - 如果你使用基于頭的版本控制,我們不能僅僅基于URL緩存,你需要考慮特定的請(qǐng)求頭。 是否能在瀏覽器直接執(zhí)行 ? - 如果您有非技術(shù)消費(fèi)者,那么基于URL的版本將更容易使用,因?yàn)樗鼈兛梢灾苯釉跒g覽器上執(zhí)行。 API文檔 - 如何讓文檔生成理解兩個(gè)不同的url是同一服務(wù)的版本?
事實(shí)上,并沒(méi)有完美的版本控制解決方案,你需要根據(jù)項(xiàng)目實(shí)際情況進(jìn)行選擇。
下面列表展示了主要API提供商使用的不同版本控制方法:
媒體類(lèi)型的版本控制
Github 自定義Header
Microsoft URI路徑
Twitter,百度,知乎 請(qǐng)求參數(shù)控制
Amazon
以上,希望對(duì)你有所幫助!
歡迎關(guān)注微信公眾號(hào):互聯(lián)網(wǎng)全棧架構(gòu),收取更多有價(jià)值的信息。
