API RESTful - Контроллеры

После создания классов ресурсов и указания того, как следует форматировать данные ресурсов, следующая задача состоит в создании действий контроллера для предоставления ресурсов конечным пользователям через API RESTful.

Yii предоставляет два базовых класса контроллера для упрощения вашей работы по созданию действий RESTful: yii\rest\Controller и yii\rest\ActiveController. Разница между этими двумя контроллерами заключается в том, что последняя предоставляет набор действий по умолчанию, специально разработанный для работы с ресурсами, представленными как Active Record. Поэтому, если вы используете Active Record и удобны с предоставленными встроенными действиями, вы можете рассмотреть возможность расширения классов контроллера из yii\rest\ActiveController, что позволит вам создавать мощные RESTful API с минимальным кодом.

Оба yii\rest\Controller и yii\rest\ActiveController предоставляют следующие возможности, некоторые из которых будут подробно описаны в следующих нескольких разделах:

  • Проверка метода HTTP;
  • Согласование содержимого и форматирование данных;
  • Аутентификация;
  • Ограничение скорости.

yii\rest\ActiveController дополнительно предоставляет следующие возможности:

  • Набор обычно необходимых действий: index, view, create, update, delete, options;
  • Авторизация пользователя в отношении запрошенного действия и ресурса.

Создание классов контроллеров

При создании нового класса контроллера соглашение об именовании класса контроллера должно использовать имя типа ресурса и использовать единственную форму. Например, чтобы обслуживать информацию пользователя, контроллер может быть назван как UserController.

Создание нового действия аналогично созданию действия для веб-приложения. Единственное отличие состоит в том, что вместо рендеринга результата с помощью вида, вызванного методом render(), для действий RESTful вы напрямую возвращаете данные. Сериализатор и объект ответа будут обрабатывать преобразование из исходных данных в запрошенный формат. Например:

public function actionView($id)
{
    return User::findOne($id);
}

Фильтры

Большинство функций API RESTful, предоставляемых yii\rest\Controller, реализованы в терминах фильтров. В частности, следующие фильтры будут выполняться в том порядке, в котором они перечислены:

  • contentNegotiator: поддерживает согласование содержимого;
  • verbFilter: поддерживает проверку HTTP-метода;
  • authenticator: поддерживает аутентификацию пользователя;
  • rateLimiter: поддерживает ограничение скорости.

Эти именованные фильтры объявляются в методе behaviors(). Вы можете переопределить этот метод, чтобы настроить отдельные фильтры, отключить некоторые из них или добавить собственные фильтры. Например, если вы хотите использовать только базовую аутентификацию HTTP, вы можете написать следующий код:

use yii\filters\auth\HttpBasicAuth;

public function behaviors()
{
    $behaviors = parent::behaviors();
    $behaviors['authenticator'] = [
        'class' => HttpBasicAuth::className(),
    ];
    return $behaviors;
}

CORS

Добавление фильтра перекрестной фильтрации ресурсов в контроллер немного сложнее, чем добавление других фильтров, описанных выше, поскольку фильтр CORS должен применяться до методов аутентификации и, следовательно, должен иметь несколько иной подход по сравнению с другими фильтрами. Кроме того, аутентификация должна быть отключена для запросов CORS Preflight, чтобы браузер мог безопасно определить, может ли запрос быть выполнен заранее, без необходимости отправки учетных данных для проверки подлинности. Ниже показан код, необходимый для добавления фильтра yii\filters\Cors к существующему контроллеру, который расширяется от yii\rest\ActiveController:

use yii\filters\auth\HttpBasicAuth;

public function behaviors()
{
    $behaviors = parent::behaviors();

    // remove authentication filter
    $auth = $behaviors['authenticator'];
    unset($behaviors['authenticator']);
    
    // add CORS filter
    $behaviors['corsFilter'] = [
        'class' => \yii\filters\Cors::className(),
    ];
    
    // re-add authentication filter
    $behaviors['authenticator'] = $auth;
    // avoid authentication on CORS-pre-flight requests (HTTP OPTIONS method)
    $behaviors['authenticator']['except'] = ['options'];

    return $behaviors;
}

Расширение ActiveController

Если ваш класс контроллера простирается от yii\rest\ActiveController, вы должны установить его свойство modelClass в качестве имени класса ресурса, который вы планируете обслуживать через этот контроллер. Класс должен распространяться от yii\db\ActiveRecord.

Пользовательские действия

По умолчанию yii\rest\ActiveController выполняет следующие действия:

  • index: список ресурсов по страницам;
  • view: возвращает информацию о указанном ресурсе;
  • create: создать новый ресурс;
  • update: обновить существующий ресурс;
  • delete: удалить указанный ресурс;
  • options: возвращает поддерживаемые методы HTTP.

Все эти действия объявляются с помощью метода actions(). Вы можете настроить эти действия или отключить некоторые из них, переопределив метод actions(), как показано ниже:

public function actions()
{
    $actions = parent::actions();

    // disable the "delete" and "create" actions
    unset($actions['delete'], $actions['create']);

    // customize the data provider preparation with the "prepareDataProvider()" method
    $actions['index']['prepareDataProvider'] = [$this, 'prepareDataProvider'];

    return $actions;
}

public function prepareDataProvider()
{
    // prepare and return a data provider for the "index" action
}

Обратитесь к ссылкам на классы для отдельных классов действий, чтобы узнать, какие параметры конфигурации доступны.

Выполнение проверки доступа

При экспонировании ресурсов через API-интерфейсы RESTful часто необходимо проверить, имеет ли текущий пользователь разрешение на доступ и управление запрошенными ресурсами. С помощью yii\rest\ActiveController это можно сделать, переопределив метод checkAccess() следующим образом:

/**
 * Checks the privilege of the current user.
 *
 * This method should be overridden to check whether the current user has the privilege
 * to run the specified action against the specified data model.
 * If the user does not have access, a [[ForbiddenHttpException]] should be thrown.
 *
 * @param string $action the ID of the action to be executed
 * @param \yii\base\Model $model the model to be accessed. If `null`, it means no specific model is being accessed.
 * @param array $params additional parameters
 * @throws ForbiddenHttpException if the user does not have access
 */
public function checkAccess($action, $model = null, $params = [])
{
    // check if the user can access $action and $model
    // throw ForbiddenHttpException if access should be denied
    if ($action === 'update' || $action === 'delete') {
        if ($model->author_id !== \Yii::$app->user->id)
            throw new \yii\web\ForbiddenHttpException(sprintf('You can only %s articles that you\'ve created.', $action));
    }
}

Метод checkAccess() будет вызван действиями по умолчанию yii\rest\ActiveController. Если вы создаете новые действия, а также хотите выполнить проверку доступа, вы должны явно вызвать этот метод в новых действиях.