API RESTful - Форматирование ответа

При обработке запроса RESTful API приложение обычно выполняет следующие шаги, связанные с форматированием ответа:

  • Определите различные факторы, которые могут повлиять на формат ответа, например, тип носителя, язык, версия и т.д. Этот процесс также известен как согласование содержимого.
  • Преобразуйте объекты ресурсов в массивы с помощью yii\rest\Serializer.
  • Преобразование массивов в строку в формате, определенном на этапе согласования содержимого. Это выполняется с помощью форм ответов, зарегистрированных в свойстве formatters компонента приложения ответа.

Согласование содержимого

Yii поддерживает согласование содержимого через фильтр yii\filters\ContentNegotiator. Класс базового контроллера API RESTful yii\rest\Controller снабжен этим фильтром под именем contentNegotiator. Фильтр обеспечивает согласование формата ответа, а также согласование языка. Например, если запрос API RESTful содержит следующий заголовок:

Accept: application/json; q=1.0, */*; q=0.1

Он получит ответ в формате JSON, например:

$ curl -i -H "Accept: application/json; q=1.0, */*; q=0.1" "http://localhost/users"

HTTP/1.1 200 OK
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y
X-Powered-By: PHP/5.4.20
X-Pagination-Total-Count: 1000
X-Pagination-Page-Count: 50
X-Pagination-Current-Page: 1
X-Pagination-Per-Page: 20
Link: <http://localhost/users?page=1>; rel=self,
      <http://localhost/users?page=2>; rel=next,
      <http://localhost/users?page=50>; rel=last
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8

[
    {
        "id": 1,
        ...
    },
    {
        "id": 2,
        ...
    },
    ...
]

За сценой до выполнения действия контроллера RESTful API фильтр yii\filters\ContentNegotiator проверяет заголовок Accept HTTP в запросе и устанавливает формат ответа в виде 'json'. После выполнения действия и возврата результирующего ресурсного объекта или коллекции yii\rest\Serializer преобразует результат в массив. И, наконец, yii\web\JsonResponseFormatter будет сериализовывать массив в строку JSON и включать его в тело ответа.

По умолчанию RESTful API поддерживают форматы JSON и XML. Чтобы поддерживать новый формат, вы должны настроить свойство formats фильтра contentNegotiator, например, следующее в ваших классах контроллера API:

use yii\web\Response;

public function behaviors()
{
    $behaviors = parent::behaviors();
    $behaviors['contentNegotiator']['formats']['text/html'] = Response::FORMAT_HTML;
    return $behaviors;
}

Ключами свойства formats являются поддерживаемые типы MIME, а значения - соответствующие имена формата ответа, которые должны поддерживаться в формате yii\web\Response::$formatters.

Сериализация данных

Как мы описали выше, yii\rest\Serializer является центральной частью, ответственной за преобразование объектов ресурсов или коллекций в массивы. Он распознает объекты, реализующие yii\base\Arrayable, а также yii\data\DataProviderInterface. Первый из них реализуется в основном ресурсными объектами, а второй - коллекциями ресурсов.

Сериализатор можно настроить, установив свойство yii\rest\Controller::$serializer с массивом конфигурации. Например, иногда вы можете помочь упростить работу по разработке клиента, включив информацию о разбиении на страницы непосредственно в теле ответа. Для этого настройте свойство yii\rest\Serializer::$collectionEnvelope следующим образом:

use yii\rest\ActiveController;

class UserController extends ActiveController
{
    public $modelClass = 'app\models\User';
    public $serializer = [
        'class' => 'yii\rest\Serializer',
        'collectionEnvelope' => 'items',
    ];
}

Вы можете получить следующий ответ для запроса http://localhost/users:

HTTP/1.1 200 OK
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y
X-Powered-By: PHP/5.4.20
X-Pagination-Total-Count: 1000
X-Pagination-Page-Count: 50
X-Pagination-Current-Page: 1
X-Pagination-Per-Page: 20
Link: <http://localhost/users?page=1>; rel=self,
      <http://localhost/users?page=2>; rel=next,
      <http://localhost/users?page=50>; rel=last
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8

{
    "items": [
        {
            "id": 1,
            ...
        },
        {
            "id": 2,
            ...
        },
        ...
    ],
    "_links": {
        "self": {
            "href": "http://localhost/users?page=1"
        },
        "next": {
            "href": "http://localhost/users?page=2"
        },
        "last": {
            "href": "http://localhost/users?page=50"
        }
    },
    "_meta": {
        "totalCount": 1000,
        "pageCount": 50,
        "currentPage": 1,
        "perPage": 20
    }
}

Управление выходом JSON

Ответ JSON генерируется классом JsonResponseFormatter, который будет использовать помощник JSON внутри. Этот форматтер может быть сконфигурирован с различными опциями, такими как, например, параметр $prettyPrint, который полезен при разработке для более читабельных ответов, или $encodeOptions для управления выходом JSON-кодировки.

Форматирование можно настроить в свойстве formatters компонента приложения ответа в конфигурации приложения, например:

'response' => [
    // ...
    'formatters' => [
        \yii\web\Response::FORMAT_JSON => [
            'class' => 'yii\web\JsonResponseFormatter',
            'prettyPrint' => YII_DEBUG, // use "pretty" output in debug mode
            'encodeOptions' => JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE,
            // ...
        ],
    ],
],

При возврате данных из базы данных с использованием уровня базы данных DAO все данные будут представлены в виде строк, что не всегда является ожидаемым результатом, особенно числовые значения должны быть представлены в виде чисел в JSON. При использовании уровня ActiveRecord для извлечения данных из базы данных значения числовых столбцов будут преобразованы в целые числа, когда данные будут извлечены из базы данных в файле yii\db\ActiveRecord::populateRecord().