0 追蹤者

資源

RESTful API 的核心在於存取和操作資源。您可以將資源視為 MVC 範例中的模型

雖然如何表示資源沒有限制,但在 Yii 中,您通常會使用 yii\base\Model 或其子類別(例如 yii\db\ActiveRecord)的物件來表示資源,原因如下:

  • yii\base\Model 實作了 yii\base\Arrayable 介面,讓您可以自訂想要如何透過 RESTful API 公開資源資料。
  • yii\base\Model 支援輸入驗證,如果您的 RESTful API 需要支援資料輸入,這會很有用。
  • yii\db\ActiveRecord 提供了強大的資料庫資料存取和操作支援,如果您的資源資料儲存在資料庫中,這使其成為完美的選擇。

在本節中,我們將主要描述如何從 yii\base\Model(或其子類別)擴充的資源類別,可以指定哪些資料可以透過 RESTful API 回傳。如果資源類別不是從 yii\base\Model 擴充,則將會回傳其所有公開成員變數。

欄位

當在 RESTful API 回應中包含資源時,需要將資源序列化為字串。Yii 將此過程分為兩個步驟。首先,資源由 yii\rest\Serializer 轉換為陣列。其次,陣列由回應格式器序列化為請求格式(例如 JSON、XML)的字串。第一步是您在開發資源類別時應主要關注的。

透過覆寫 fields() 和/或 extraFields(),您可以指定資源中哪些資料(稱為欄位)可以放入其陣列表示形式中。這兩種方法之間的區別在於,前者指定應包含在陣列表示形式中的預設欄位集,而後者指定如果終端使用者透過 expand 查詢參數請求它們,則可以包含在陣列中的其他欄位。例如:

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

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

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

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

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

覆寫 fields()

預設情況下,yii\base\Model::fields() 會傳回所有模型屬性作為欄位,而 yii\db\ActiveRecord::fields() 僅傳回從資料庫填入的屬性。

您可以覆寫 fields() 來新增、移除、重新命名或重新定義欄位。fields() 的傳回值應該是一個陣列。陣列鍵是欄位名稱,而陣列值是對應的欄位定義,可以是屬性/屬性名稱或傳回對應欄位值的匿名函式。在欄位名稱與其定義屬性名稱相同之特殊情況下,您可以省略陣列鍵。例如:

// 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 exclude 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;
}

警告:由於預設情況下,模型的所有屬性都將包含在 API 結果中,因此您應該檢查您的資料以確保它們不包含敏感資訊。如果存在此類資訊,您應該覆寫 fields() 以將它們過濾掉。在上面的範例中,我們選擇過濾掉 auth_keypassword_hashpassword_reset_token

覆寫 extraFields()

預設情況下,yii\base\Model::extraFields() 會傳回空陣列,而 yii\db\ActiveRecord::extraFields() 則會傳回從資料庫填入的關聯名稱。

extraFields() 的傳回資料格式與 fields() 相同。通常,extraFields() 主要用於指定值為物件的欄位。例如,給定以下欄位宣告:

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

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

帶有 https://127.0.0.1/users?fields=id,email&expand=profile 的請求可能會傳回以下 JSON 資料

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

HATEOAS,是 Hypermedia as the Engine of Application State(超媒體作為應用程式狀態引擎)的縮寫,提倡 RESTful API 應該傳回資訊,讓用戶端可以發現對傳回資源支援的操作。HATEOAS 的關鍵是在 API 提供資源資料時,傳回一組帶有關係資訊的超連結。

您的資源類別可以透過實作 yii\web\Linkable 介面來支援 HATEOAS。此介面包含一個單一方法 getLinks(),它應該傳回 連結列表。通常,您應該至少傳回代表資源物件本身 URL 的 self 連結。例如:

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),
        ];
    }
}

當在回應中傳回 UserResource 物件時,它將包含一個 _links 元素,表示與使用者相關的連結,例如:

{
    "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"
        }
    }
}

集合

資源物件可以分組為集合。每個集合都包含相同類型資源物件的列表。

雖然集合可以表示為陣列,但通常更希望將它們表示為資料提供器。這是因為資料提供器支援資源的排序和分頁,這是 RESTful API 傳回集合時常用的功能。例如,以下動作傳回有關文章資源的資料提供器:

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(),
        ]);
    }
}

當資料提供器在 RESTful API 回應中傳送時,yii\rest\Serializer 將取出當前頁面的資源並將它們序列化為資源物件陣列。此外,yii\rest\Serializer 也會透過以下 HTTP 標頭包含分頁資訊:

  • X-Pagination-Total-Count:資源總數;
  • X-Pagination-Page-Count:頁數;
  • X-Pagination-Current-Page:當前頁面(從 1 開始);
  • X-Pagination-Per-Page:每頁的資源數;
  • Link:一組導航連結,允許用戶端逐頁瀏覽資源。

由於 REST API 中的集合是資料提供器,因此它共享所有資料提供器功能,即分頁和排序。

範例可以在快速開始章節中找到。

發現錯字或您認為此頁面需要改進嗎?
在 github 上編輯 !