RESTful APIs Resources in Yii 2
RESTful APIs Resources in Yii 2

Resources

RESTful APIs are all about accessing and manipulating resources. You may view resources as models in the MVC paradigm.

While there is no restriction in how to represent a resource, in Yii you usually would represent resources in terms of objects of [[yii\base\Model]] or its child classes (e.g. [[yii\db\ActiveRecord]]), for the following reasons:

Старт! Честный VDS/VPS, на котором «Лунная База» живет уже 20+ лет

Задумываетесь о том, чтобы поднять свой pet-проект, сайт клиента или настроить окружение для разработки? Уже пора подумать, где арендовать железо.

Лунная База хостится на FirstVDS более 20 лет. Мыслей о том, чтобы перебраться на другой хостинг, не было ни разу (хотя опыт работы с другими вариантами, конечно, есть).

Бывали разные ситуации, но они бывают на любом железе. Главное, что нужно понять: здесь нет маркетинговой шелухи и сказок про «мы всё сделаем за вас». Если вы берете VDS — вам дают полный root, возможность накатить любую ОС и не лезут в ваши конфиги.

Если в саппорт написать с вопросом по вашему коду и получить ответ: «Читайте документацию и разбирайтесь сами» или «Обратитесь к профильному специалисту» — это не повод обижаться. Это повод углубить свои знания в DevOps и сайтостроении! Бегите от тех, кто пообещает: «Мы всё чиним и настраиваем абсолютно бесплатно!». Никто никогда не работает «по доброте душевной» в ущерб себе, а бесплатный сыр в администрировании обычно заканчивается сломанной базой данных.

Что по факту: Гибкое масштабирование ядер и RAM, экономия по сравнению с физическими серверами и адекватная панель ispmanager, если она вам нужна.



  • [[yii\base\Model]] implements the [[yii\base\Arrayable]] interface, which allows you to customize how you want to expose resource data through RESTful APIs.
  • [[yii\base\Model]] supports input validation, which is useful if your RESTful APIs need to support data input.
  • [[yii\db\ActiveRecord]] provides powerful DB data access and manipulation support, which makes it a perfect fit if your resource data is stored in databases.

In this section, we will mainly describe how a resource class extending from [[yii\base\Model]] (or its child classes) can specify what data may be returned via RESTful APIs. If the resource class does not extend from [[yii\base\Model]], then all its public member variables will be returned.

Fields

When including a resource in a RESTful API response, the resource needs to be serialized into a string. Yii breaks this process into two steps. First, the resource is converted into an array by [[yii\rest\Serializer]]. Second, the array is serialized into a string in a requested format (e.g. JSON, XML) by [[yii\web\ResponseFormatterInterface|response formatters]]. The first step is what you should mainly focus when developing a resource class.

By overriding [[yii\base\Model::fields()|fields()]] and/or [[yii\base\Model::extraFields()|extraFields()]], you may specify what data, called fields, in the resource can be put into its array representation. The difference between these two methods is that the former specifies the default set of fields which should be included in the array representation, while the latter specifies additional fields which may be included in the array if an end user requests for them via the expand query parameter. For example,

// returns all fields as declared in fields()
http://localhost/users

// only returns "id" and "email" fields, provided they are declared in fields()
http://localhost/users?fields=id,email

// returns all fields in fields() and field "profile" if it is in extraFields()
http://localhost/users?expand=profile

// returns all fields in fields() and "author" from post if
// it is in extraFields() of post model
http://localhost/comments?expand=post.author

// only returns "id" and "email" provided they are in fields() and "profile" if it is in extraFields()
http://localhost/users?fields=id,email&expand=profile

Overriding fields()

By default, [[yii\base\Model::fields()]] returns all model attributes as fields, while [[yii\db\ActiveRecord::fields()]] only returns the attributes which have been populated from DB.

You can override fields() to add, remove, rename or redefine fields. The return value of fields() should be an array. The array keys are the field names, and the array values are the corresponding field definitions which can be either property/attribute names or anonymous functions returning the corresponding field values. In the special case when a field name is the same as its defining attribute name, you can omit the array key. For example,

// explicitly list every field, best used when you want to make sure the changes
// in your DB table or model attributes do not cause your field changes (to keep API backward compatibility).
public function fields()
{
    return [
        // field name is the same as the attribute name
        'id',
        // field name is "email", the corresponding attribute name is "email_address"
        'email' => 'email_address',
        // field name is "name", its value is defined by a PHP callback
        'name' => function ($model) {
            return $model->first_name . ' ' . $model->last_name;
        },
    ];
}

// filter out some fields, best used when you want to inherit the parent implementation
// and blacklist some sensitive fields.
public function fields()
{
    $fields = parent::fields();

    // remove fields that contain sensitive information
    unset($fields['auth_key'], $fields['password_hash'], $fields['password_reset_token']);

    return $fields;
}

Warning: Because by default all attributes of a model will be included in the API result, you should examine your data to make sure they do not contain sensitive information. If there is such information, you should override fields() to filter them out. In the above example, we choose to filter out auth_key, password_hash and password_reset_token.

Overriding extraFields()

By default, [[yii\base\Model::extraFields()]] returns an empty array, while [[yii\db\ActiveRecord::extraFields()]] returns the names of the relations that have been populated from DB.

The return data format of extraFields() is the same as that of fields(). Usually, extraFields() is mainly used to specify fields whose values are objects. For example, given the following field declaration,

public function fields()
{
    return ['id', 'email'];
}

public function extraFields()
{
    return ['profile'];
}

the request with http://localhost/users?fields=id,email&expand=profile may return the following JSON data:

[
    {
        "id": 100,
        "email": "100@example.com",
        "profile": {
            "id": 100,
            "age": 30,
        }
    },
    ...
]

Links

HATEOAS, an abbreviation for Hypermedia as the Engine of Application State, promotes that RESTful APIs should return information that allows clients to discover actions supported for the returned resources. The key of HATEOAS is to return a set of hyperlinks with relation information when resource data are served by the APIs.

Your resource classes may support HATEOAS by implementing the [[yii\web\Linkable]] interface. The interface contains a single method [[yii\web\Linkable::getLinks()|getLinks()]] which should return a list of [[yii\web\Link|links]]. Typically, you should return at least the self link representing the URL to the resource object itself. For example,

use yii\base\Model;
use yii\web\Link; // represents a link object as defined in JSON Hypermedia API Language.
use yii\web\Linkable;
use yii\helpers\Url;

class UserResource extends Model implements Linkable
{
    public $id;
    public $email;

    //...

    public function fields()
    {
        return ['id', 'email'];
    }

    public function extraFields()
    {
        return ['profile'];
    }

    public function getLinks()
    {
        return [
            Link::REL_SELF => Url::to(['user/view', 'id' => $this->id], true),
            'edit' => Url::to(['user/view', 'id' => $this->id], true),
            'profile' => Url::to(['user/profile/view', 'id' => $this->id], true),
            'index' => Url::to(['users'], true),
        ];
    }
}

When a UserResource object is returned in a response, it will contain a _links element representing the links related to the user, for example,

{
    "id": 100,
    "email": "user@example.com",
    // ...
    "_links" => {
        "self": {
            "href": "https://example.com/users/100"
        },
        "edit": {
            "href": "https://example.com/users/100"
        },
        "profile": {
            "href": "https://example.com/users/profile/100"
        },
        "index": {
            "href": "https://example.com/users"
        }
    }
}

Collections

Resource objects can be grouped into collections. Each collection contains a list of resource objects of the same type.

While collections can be represented as arrays, it is usually more desirable to represent them as data providers. This is because data providers support sorting and pagination of resources, which is a commonly needed feature for RESTful APIs returning collections. For example, the following action returns a data provider about the post resources:

namespace app\controllers;

use yii\rest\Controller;
use yii\data\ActiveDataProvider;
use app\models\Post;

class PostController extends Controller
{
    public function actionIndex()
    {
        return new ActiveDataProvider([
            'query' => Post::find(),
        ]);
    }
}

When a data provider is being sent in a RESTful API response, [[yii\rest\Serializer]] will take out the current page of resources and serialize them as an array of resource objects. Additionally, [[yii\rest\Serializer]] will also include the pagination information by the following HTTP headers:

  • X-Pagination-Total-Count: The total number of resources;
  • X-Pagination-Page-Count: The number of pages;
  • X-Pagination-Current-Page: The current page (1-based);
  • X-Pagination-Per-Page: The number of resources in each page;
  • Link: A set of navigational links allowing client to traverse the resources page by page.

Since collection in REST APIs is a data provider, it shares all data provider features i.e. pagination and sorting.

An example may be found in the Quick Start section.

Filtering collections

Since version 2.0.13 Yii provides a facility to filter collections. An example can be found in the Quick Start guide. In case you're implementing an endpoint yourself, filtering could be done as described in Filtering Data Providers using Data Filters section of Data Providers guide.

Самый честный хостинг за 20+ лет существования Лунной Базы

Задумываешься о том, чтобы поднять свой сайт в Интернете? Уже пора подумать о том, какой хостинг выбрать?

Лунная База хостится 20+ лет на firstDVS. При этом, мыслей о том, чтобы перебраться на другой хостинг не было. (Но, при этом есть опыт работы с другими вариантами.)

Бывали с firstDVS разные ситуации, но, они бывают на всех хостингах. Единственное, что тут важно понять, - это то, что никто ничего тебе не будет впаривать... Но, и работать за тебя тоже никто не станет. Если в саппорт ответили: «Читайте по ссылке и разбирайтесь сами...» или вообще «Обратитесь за помощью к специалисту», - это повод углубить свои знания в области сайтостроения, а не бежать к тем, что пообещают: «Мы всё чиним и всё делаем за своих клиентов абсолютно бесплатно!» Никто никогда ничего ни за кого "по доброте душевной" не делал, не делает и не будет делать!

Старт! MoonВase — A Hot Start on the Internet
Старт! MoonВase — A Hot Start on the Internet
Старт! Menu