From 2e2a7af5a83084adbde6696988fc18bf9a74a73b Mon Sep 17 00:00:00 2001 From: Vadim Belorussov Date: Mon, 18 Aug 2014 23:51:24 +0500 Subject: [PATCH] Add rest-versioning.md to translate into Russian [skip ci] --- docs/guide-ru/rest-versioning.md | 107 +++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 docs/guide-ru/rest-versioning.md diff --git a/docs/guide-ru/rest-versioning.md b/docs/guide-ru/rest-versioning.md new file mode 100644 index 0000000000..0b876ca742 --- /dev/null +++ b/docs/guide-ru/rest-versioning.md @@ -0,0 +1,107 @@ +Versioning +========== + +Your APIs should be versioned. Unlike Web applications which you have full control on both client side and server side +code, for APIs you usually do not have control of the client code that consumes the APIs. Therefore, backward +compatibility (BC) of the APIs should be maintained whenever possible, and if some BC-breaking changes must be +introduced to the APIs, you should bump up the version number. You may refer to [Semantic Versioning](http://semver.org/) +for more information about designing the version numbers of your APIs. + +Regarding how to implement API versioning, a common practice is to embed the version number in the API URLs. +For example, `http://example.com/v1/users` stands for `/users` API of version 1. Another method of API versioning +which gains momentum recently is to put version numbers in the HTTP request headers, typically through the `Accept` header, +like the following: + +``` +// via a parameter +Accept: application/json; version=v1 +// via a vendor content type +Accept: application/vnd.company.myapp-v1+json +``` + +Both methods have pros and cons, and there are a lot of debates about them. Below we describe a practical strategy +of API versioning that is kind of a mix of these two methods: + +* Put each major version of API implementation in a separate module whose ID is the major version number (e.g. `v1`, `v2`). + Naturally, the API URLs will contain major version numbers. +* Within each major version (and thus within the corresponding module), use the `Accept` HTTP request header + to determine the minor version number and write conditional code to respond to the minor versions accordingly. + +For each module serving a major version, it should include the resource classes and the controller classes +serving for that specific version. To better separate code responsibility, you may keep a common set of +base resource and controller classes, and subclass them in each individual version module. Within the subclasses, +implement the concrete code such as `Model::fields()`. + +Your code may be organized like the following: + +``` +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 +``` + +Your application configuration would look like: + +```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']], + ], + ], + ], +]; +``` + +As a result, `http://example.com/v1/users` will return the list of users in version 1, while +`http://example.com/v2/users` will return version 2 users. + +Using modules, code for different major versions can be well isolated. And it is still possible +to reuse code across modules via common base classes and other shared classes. + +To deal with minor version numbers, you may take advantage of the content negotiation +feature provided by the [[yii\filters\ContentNegotiator|contentNegotiator]] behavior. The `contentNegotiator` +behavior will set the [[yii\web\Response::acceptParams]] property when it determines which +content type to support. + +For example, if a request is sent with the HTTP header `Accept: application/json; version=v1`, +after content negotiation, [[yii\web\Response::acceptParams]] will contain the value `['version' => 'v1']`. + +Based on the version information in `acceptParams`, you may write conditional code in places +such as actions, resource classes, serializers, etc. + +Since minor versions require maintaining backward compatibility, hopefully there are not much +version checks in your code. Otherwise, chances are that you may need to create a new major version.