
Java?API設計實戰指南:打造穩健、用戶友好的API
· 使用 Composer 命令 composer create-project laravel/laravel responses dev-develop
來創建一個 Laravel 5.5 項目。這個命令會從 Laravel 官方的存儲庫中下載最新版本的 Laravel 5.5 代碼并安裝到名為 “responses” 的文件夾中。
· cd responses
: 進入到新創建的 “responses” 文件夾中。
· touch database/database.sqlite
: 創建一個 SQLite 數據庫文件,用于存儲數據。
php artisan make:model Post -mf
: 創建一個名為 “Post” 的 Eloquent 模型,并生成相應的遷移文件和工廠。
· php artisan make:resource UsersWithPostsResource
: 創建一個名為 “UsersWithPostsResource” 的資源類,用于對用戶及其posts進行處理。
· php artisan make:resource PostsResource
: 創建一個名為 “PostsResource” 的資源類,用于對posts進行處理。
· php artisan make:controller UsersController –resource: 創建一個名為 “UsersController” 的控制器,添加了 CRUD(創建、讀取、更新、刪除)操作的資源路由。
· 修改 .env
文件,使用 SQLite 數據庫,并刪除其他數據庫相關的變量。
· 添加或修改 DB_CONNECTION=sqlite
來指定 Laravel 使用 SQLite 作為數據庫連接。
這些步驟旨在建立一個基本的 Laravel 5.5 項目,并做了一些初始化設置,包括創建模型、資源類和控制器,并配置使用 SQLite 作為數據庫。
·posts遷移 database/migrations/______create_posts_table.php
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->string('body');
$table->unsignedInteger('user_id');
$table->timestamps();
});
這涉及創建posts模型的數據庫表結構。在 database/migrations
目錄下的create_posts_table.php
的文件,定義了posts表的字段和結構。這個文件包含了使用 Laravel 的遷移(Migration)功能創建數據庫表的代碼。
· posts工廠database/factories/PostFactory.php
<?php
use Faker\Generator as Faker;
$factory->define(App\Post::class,
function (Faker $faker) {
return [
'title' => $faker->sentence,
'body' => $faker->paragraph,
'user_id' => function () {
return factory(\App\User::class);
}
];
});
這一步驟是為了創建一個posts的工廠,用于生成測試數據或者用于種子數據填充。在 database/factories
目錄下的 PostFactory.php
文件中,你會定義創建posts模型時所用的數據格式和規則。
· 用戶擁有posts的關系 app/User.php
public function posts(){return $this->hasMany(Post::class);}
這是在用戶模型(User)中定義與posts模型的關系。也就是在 app 目錄下的 User.php
文件中,你會定義用戶和posts之間的關聯關系,比如一對多關系(一個用戶有多個posts)或其他關系。
· 避免批量賦值 app/Post.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model{protected $guarded = [];}
在 app
目錄下的 Post.php
文件中,通常會有一個模型類,即posts模型(Post)。避免批量賦值是指使用 Laravel 的屬性來指定哪些字段可以被批量賦值,以防止不受控制的數據注入。
· 播種數據庫
<?php
artisan migrate:freshphp artisan
tinkerfactory(App\Post::class)->times(2)->create();
factory(App\Post::class)->times(2)->create(['user_id' => 1]);
數據庫種子用于向數據庫中填充測試數據或初始數據。這是在開發或測試階段常用的操作,可以使用 Laravel 的 Seeder 來填充數據庫表,確保數據庫中有一些初始數據可用于開發和測試。
Route::apiResource('/users', 'UsersController');
之前創建了一個名為 UsersWithPostsResource
的資源。讓我們將其重命名為 UsersResource
,并了解如何在以下步驟中重用它。
<?php
/**
* Display a listing of the resource.
*
* @param User $user
* @return \Illuminate\Http\Response
*/
public function index(User $user)
{
return UsersResource::collection($user->with('posts')->paginate());
// If you don't want to include the relationship in your response, don't use with()
// return UsersResource::collection($user->paginate());
}
靜態 collection
方法將采用要轉換的記錄集合,并確保為每個記錄實例化一個新的UsersResource
。
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
class UsersResource extends Resource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
{
return [
'name' => $this->name,
'email' => $this->email,
'posts' => PostsResource::collection($this->whenLoaded('posts'))
];
}
}
這里的兩個關鍵部分:屬性訪問器和可選的嵌套轉換。
在 Resource
中,可以通過 $this
直接訪問模型的屬性。這個神奇的功能是通過 DelegatesToResource trait 在基礎資源類中實現的。簡單來說,這意味著資源類中可以直接使用 $this->attributeName
的方式訪問模型中的屬性,而不必每次都通過模型實例去獲取屬性。
能夠在資源類中進行關系的轉換,但是有條件:如果數據是可用的(已經預加載),就可以進行轉換;如果數據尚未加載,可以選擇忽略這個轉換。這樣做有利于避免 N+1 查詢問題(在獲取關聯數據時出現的效率問題),同時可以使用單個資源類處理不同的情況。如果關聯數據不可用,資源類會忽略它;反之,如果可用,資源類會將其包含在返回的數據中。
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
class PostsResource extends Resource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
{
return [
'title' => $this->title,
'body' => $this->body
];
}
}
1.簡化和逐步進行
本文著重于學習如何使用 Resource::collection 而不是手動實例化類,并將關系數據的提供(或不提供)責任委托給控制器。通過在控制器中簡單地移除 with(‘posts’),API 將不再在響應中包含每個用戶的posts數據。
2.對比 Fractal 和 Laravel 的資源
本文提到 Fractal 在轉換層(Transformer)提供了默認和可用的包含(includes)功能,但是 Laravel 的原生 API 資源更傾向于讓控制器處理這個邏輯。畢竟,控制器的工作是理解請求。這暗示著對于數據包含的處理,Laravel 更多地依賴于控制器層面的邏輯,而不是在資源轉換層實現。
總體而言,本文聚焦于利用 Laravel 中的 Resource::collection,并強調控制器對于處理數據關系包含的重要性。
參考鏈接:
First?impressions?on?Laravel?API?Resources?|?HackerNoon
具有嵌套關系的可重用?API?資源?—?Laravel?5.5?|由?Marco?Aurélio?Deleu?|HackerNoon.com?|中等?(medium.com)