search
尋找貓咪~QQ 地點 桃園市桃園區 Taoyuan , Taoyuan

Laravel Eloquent API Resources

Laravel Eloquent API Resources

PHP:7.2

Laravel:5.8

當我們利用 Laravel 在設計 API 時,通常都會透過 Eloquent Model 取得資料,並將資料轉換成 JSON 格式輸出。

比如在 Controller 中就會像這樣回傳:

return response()->json([
    'status' => 200,
    'data' => [
        'meta' => SongModel::find($songID)
    ]
]);

然而,這裡隱藏著幾個缺點:

  • 重複的格式定義: 類似的 endpoint 可能都有類似的格式定義,可是卻散落在 Controller 各處。
  • format 不固定: 因為是直接將 model 輸出,如果資料表有更動的話,API 會直接受到衝擊。

為了因應以上問題,Laravel 在 5.5 之後提供了 API Resources 讓大家更方便的自訂輸出格式,建立 ModelOutput 之間的橋樑。

Basic Usage

Artisan 提供了命令列可以直接建立 Resource

php artisan make:resource SongResource

產生後便可以在 app\Http\Resources 看到 SongResource 檔案。

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class SongResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function toArray($request)
    {
        return parent::toArray($request);
    }
}

由於 Resource 是繼承自 JsonResource,因此輸出就會是 JSON 的格式內容,而我們要做的就是修改 toArray() method 當中的格式:

public function toArray($request)
{
    return [
        'song_id' => $this->song_id,
        'song_name' => $this->song_name,
        'artist_id' => $this->artist_id,
        'album_id' => $this->album_id,
    ];
}

接著只要在 RouteController 中直接輸出就可以了。

Controller

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Song;
use App\Http\Resources\SongResource;

class TestController extends Controller
{
    public function test()
    {
        $model = SongModel::find($songID);
        // 直接 return Resource
        return new SongResource($model);

        // 也可以自行設定 HTTP code
        return (new SongResource($model))
            ->response()
            ->setStatusCode(200);
    }
}

Route

use App\Song;
use App\Http\Resources\SongResource;

Route::get('/songs/{song}', function(Song $song) {
    return new SongResource($song);
});

Output

{
    "data":{
        "song_id":301231008,
        "song_name":"TEST",
        "artist_id":3182,
        "album_id":30497178,
    }
}

Collection

接下來問題來了,很多時候我們會取得資源的清單,比如說 SongModel::all(),直接使用 Resource 會出現錯誤訊息,因為丟進去的是一個 Collection ,並不是物件本身。

此時需要搭配 Resource::collection() 使用,它會將 Collection 中的所有 Model 物件自動套用 Resource 的格式。

Controller Exmaple

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Song;
use App\Http\Resources\SongResource;

class TestController extends Controller
{
    public function test()
    {
        $collection = SongModel::all();
        return SongResource::collection($collection);     
    }
}

當然,也可以定義一些 Collection 的資料在 Resource 之中:
app/Http/Resources/SongResource

public function toArray($request)
{
    return [
        // 傳入 collection
        'data' => $this->collection,
        'count' => $this->collection->count()
    ];
}

Relationships

既然用到了 Eloquent Model,必定會用到一些 relation 去取得不同張表的資料;對於 Resource 來說,我們必須將這些資源都一一拆開,一來具備開發彈性、二來這些資源也可重複使用。

舉例來說,如果透過 SongModel 關聯出 AlbumArtist,可以設計成以下這樣:

app/Http/Resources/ArtistResource

public function toArray($request)
{
    return [
        'artist_id' => $this->artist_id,
        'artist_name' => $this->artist_name
    ];
}

app/Http/Resources/AlbumResource

public function toArray($request)
{
    return [
        'album_id' => $this->album_id,
        'album_name' => $this->album_name
    ];
}

app/Http/Resources/SongResource

public function toArray($request)
{
    return [
        'song_id' => $this->song_id,
        'song_name' => $this->song_name,
        'artist_id' => $this->artist_id,
        'album_id' => $this->album_id,
        'artist' => new Artist($this->artist),
        'album' => new Album($this->album)
    ];
}

Controller Exmaple

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Song;
use App\Http\Resources\SongResource;

class TestController extends Controller
{
    public function test()
    {
        $collection = SongModel::with(['album', 'artist'])->all();
        return SongResource::collection($collection);     
    }
}
Categories: Laravel
Tags: LaravelPHP



熱門推薦

本文由 blogjohnsonluorg 提供 原文連結

寵物協尋 相信 終究能找到回家的路
寫了7763篇文章,獲得2次喜歡
留言回覆
回覆
精彩推薦