Версионирование =============== <<<<<<< HEAD <<<<<<< HEAD Свои API вам следует версионировать. В отличие от Web-приложений, где у вас есть полный контроль и над серверным, и над клиентским кодом, при работе с API у вас обычно нет контроля над клиентским кодом, работающим с вашими API. Поэтому всегда, когда это только возможно, должна поддерживаться обратная совместимость API, и если в API должны быть внесены изменения, ломающие обратную совместимость, следует увеличить номер версии. Почитайте про [семантическое версионирование](http://semver.org/) для получения более подробной информации о возможных способах нумерации различных версий ваших API. ======= ======= >>>>>>> master Хороший API должен быть *версионирован*: изменения и новые возможности реализуются в новых версиях API, а не в одной и той же версии. В отличие от Web-приложений, где у вас есть полный контроль и над серверным, и над клиентским кодом, API используются клиентами, код которых вы не контролируете. Поэтому, обратная совместимость (BC) должна по возможности сохраняться. Если ломающее её изменение необходимо, делать его нужно в новой версии API. Существующие клиенты могут продолжать использовать старую, совместимую с ними версию API. Новые или обновлённые клиенты могут использовать новую версию. <<<<<<< HEAD >>>>>>> yiichina/master ======= > Tip: Чтобы узнать больше о выборе версий обратитесь к [Semantic Versioning](http://semver.org/). >>>>>>> master Общей практикой при реализации версионирования API является включение номера версии в URL-адрес вызова API-метода. Например, `http://example.com/v1/users` означает вызов API `/users` версии 1. Другой способ версионирования API, получивший недавно широкое распространение, состоит в добавлении номера версии в HTTP-заголовки запроса, обычно в заголовок `Accept`: <<<<<<< HEAD ======= > Подсказка: Чтобы узнать больше о выборе версий обратитесь к [Semantic Versioning](http://semver.org/). Один из типичных способов реализации версионирования — указание версии в URL. Например, `http://example.com/v1/users` соответствует `/users` версии 1. Ещё один способ, ставший сейчас популярным — передача версии через заголовок HTTP. Чаще всего для этого используется заголовок `Accept`: >>>>>>> yiichina/master ``` // как параметр Accept: application/json; version=v1 // как тип содержимого, определенный поставщиком API Accept: application/vnd.company.myapp-v1+json ``` Оба способа имеют достоинства и недостатки, и вокруг них много споров. Ниже мы опишем реально работающую стратегию версионирования API, которая является некоторой смесью этих двух способов: * Помещать каждую мажорную версию реализации API в отдельный модуль, чей ID является номером мажорной версии (например, `v1`, `v2`). Естественно, URL-адреса API будут содержать в себе номера мажорных версий. * В пределах каждой мажорной версии (т.е. внутри соответствующего модуля) использовать HTTP-заголовок `Accept` для определения номера минорной версии и писать условный код для соответствующих минорных версий. В каждый модуль, обслуживающий мажорную версию, следует включать классы ресурсов и контроллеров, обслуживающих эту конкретную версию. Для лучшего разделения ответственности кода вы можете составить общий набор базовых классов ресурсов и контроллеров, и субклассировать их в каждом отдельно взятом модуле версии. Внутри дочерних классов реализуйте конкретный код вроде метода `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 <<<<<<< HEAD <<<<<<< HEAD ======= Module.php >>>>>>> yiichina/master ======= Module.php >>>>>>> master v2/ controllers/ UserController.php PostController.php models/ User.php Post.php <<<<<<< HEAD <<<<<<< HEAD ======= Module.php >>>>>>> yiichina/master ======= Module.php >>>>>>> master ``` Конфигурация вашего приложения могла бы выглядеть так: ```php return [ 'modules' => [ 'v1' => [ <<<<<<< HEAD <<<<<<< HEAD 'basePath' => '@app/modules/v1', ], 'v2' => [ 'basePath' => '@app/modules/v2', ======= 'class' => 'app\modules\v1\Module', ], 'v2' => [ 'class' => 'app\modules\v2\Module', >>>>>>> yiichina/master ======= 'class' => 'app\modules\v1\Module', ], 'v2' => [ 'class' => 'app\modules\v2\Module', >>>>>>> master ], ], '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` возвратит список пользователей API версии 1, в то время как `http://example.com/v2/users` вернет список пользователей версии 2. <<<<<<< HEAD <<<<<<< HEAD При использовании модулей код API различных мажорных версий может быть хорошо изолирован. И по-прежнему возможно ======= Благодаря использованию модулей код API различных мажорных версий может быть хорошо изолирован. И по-прежнему возможно >>>>>>> yiichina/master ======= Благодаря использованию модулей код API различных мажорных версий может быть хорошо изолирован. И по-прежнему возможно >>>>>>> master повторное использование кода между модулями через общие базовые классы и другие разделяемые классы. Для работы с минорными номерами версий вы можете использовать преимущества согласования содержимого, предоставляемого поведением [[yii\filters\ContentNegotiator|contentNegotiator]]. Определив тип поддерживаемого содержимого, поведение `contentNegotiator` установит значение свойства [[yii\web\Response::acceptParams]]. Например, если запрос посылается с HTTP-заголовком `Accept: application/json; version=v1`, то после согласования содержимого свойство [[yii\web\Response::acceptParams]] будет содержать значение `['version' => 'v1']`. <<<<<<< HEAD <<<<<<< HEAD На основе информации о версии из `acceptParams` вы можете написать условный код в таких местах, как действия, классы ресурсов, сериализаторы и т.д. ======= На основе информации о версии из `acceptParams` вы можете выбирать поведение в действиях, классах ресурсов, сериализаторах и т.д. >>>>>>> yiichina/master ======= На основе информации о версии из `acceptParams` вы можете выбирать поведение в действиях, классах ресурсов, сериализаторах и т.д. >>>>>>> master Так как минорные версии требуют поддержания обратной совместимости, будем надеяться, что в вашем коде не так уж много проверок на номер версии. В противном случае велики шансы, что вам нужна новая мажорная версия.