你的 API 應該是版本化的。不像你完全控制在客戶端和服務器端 Web 應用程序代碼, 對于 API,您通常沒有對 API 的客戶端代碼的控制權。因此,應該盡可能的保持向后兼容性(BC),如果一些不能向后兼容的變化必須引入 APIs,你應該增加版本號。你可以參考Semantic Versioning有關設計的 API 的版本號的詳細信息。
關于如何實現(xiàn) API 版本,一個常見的做法是在 API 的 URL 中嵌入版本號。例如,http://example.com/v1/users
代表/users
版本 1 的 API. 另一種 API 版本化的方法最近用的非常多的是把版本號放入 HTTP 請求頭,通常是通過Accept
頭,如下:
// 通過參數(shù)
Accept: application/json; version=v1
// 通過 vendor 的內(nèi)容類型
Accept: application/vnd.company.myapp-v1+json
這兩種方法都有優(yōu)點和缺點, 而且關于他們也有很多爭論。下面我們描述在一種 API 版本混合了這兩種方法的一個實用的策略:
v1
, v2
)。
自然,API 的 url 將包含主要的版本號。Accept
HTTP 請求頭確定小版本號編寫條件代碼來響應相應的次要版本.為每個模塊提供一個主要版本, 它應該包括資源類和控制器類為特定服務版本。 更好的分離代碼, 你可以保存一組通用的基礎資源和控制器類, 并用在每個子類版本模塊。 在子類中,實現(xiàn)具體的代碼例如 Model::fields()
。
你的代碼可以類似于如下的方法組織起來:
api/
common/
controllers/
UserController.php
PostController.php
models/
User.php
Post.php
modules/
v1/
controllers/
UserController.php
PostController.php
models/
User.php
Post.php
v2/
controllers/
UserController.php
PostController.php
models/
User.php
Post.php
你的應用程序配置應該這樣:
return [
'modules' => [
'v1' => [
'basePath' => '@app/modules/v1',
],
'v2' => [
'basePath' => '@app/modules/v2',
],
],
'components' => [
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false,
'rules' => [
['class' => 'yii\rest\UrlRule', 'controller' => ['v1/user', 'v1/post']],
['class' => 'yii\rest\UrlRule', 'controller' => ['v2/user', 'v2/post']],
],
],
],
];
因此,http://example.com/v1/users
將返回版本 1 的用戶列表,而 http://example.com/v2/users
將返回版本 2 的用戶。
使用模塊, 將不同版本的代碼隔離。 通過共用基類和其他類跨模塊重用代碼也是有可能的。
為了處理次要版本號, 可以利用內(nèi)容協(xié)商功能通過 [[yii\filters\ContentNegotiator|contentNegotiator]] 提供的行為。contentNegotiator
行為可設置 [[yii\web\Response::acceptParams]] 屬性當它確定支持哪些內(nèi)容類型時。
例如, 如果一個請求通過 Accept: application/json; version=v1
被發(fā)送,內(nèi)容交涉后,[[yii\web\Response::acceptParams]]將包含值['version' => 'v1']
.
基于 acceptParams
的版本信息,你可以寫條件代碼如 actions,resource classes,serializers 等等。
由于次要版本需要保持向后兼容性,希望你的代碼不會有太多的版本檢查。否則,有機會你可能需要創(chuàng)建一個新的主要版本。