Rest Api CRUD in Laravel with Api Resources
执行:
php artisan make:model Task –mf
执行:
php artisan make:controller TaskController -r
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateTasksTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('tasks', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('user_id'); $table->string('title'); $table->text('description'); $table->dateTime('due'); $table->timestamps(); }); Schema::table('tasks', function (Blueprint $table) { $table->foreign('user_id')->references('id')->on('users')->cascadeOnDelete(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('tasks'); } }
执行:
php artisan migrate
TaskController修改index方法:
public function index() { // $tasks = Task::all(); return response($tasks, 200); }
api.php添加:
Route::resource('task', ‘TaskController');
然后我们用PostMan发送请求测试:
因为目前我们数据库中没有添加任何数据,所以返回为空,尝试用factory添加一些数据:
修改一下task的migration文件:
public function up() { Schema::create('tasks', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('user_id'); $table->string('title'); $table->text('description')->nullable(); $table->dateTime('due')->nullable(); $table->timestamps(); }); Schema::table('tasks', function (Blueprint $table) { $table->foreign('user_id')->references('id')->on('users')->cascadeOnDelete(); }); }
然后执行:
php artisan migrate:fresh
强制删除所有数据表并重新生成。
打开TaskFactory.php 修改如下:
<?php /** @var \Illuminate\Database\Eloquent\Factory $factory */ use App\Task; use Faker\Generator as Faker; $factory->define(Task::class, function (Faker $faker) { return [ // 'title' => $faker->company, 'description' => $faker->paragraph(20), 'user_id' => 1, ]; });
执行:
php artisan passport:install
然后
添加用户数据后,执行
php artisan tinker
在tinker中执行:
factory(App\Task::class,5)->create();
添加5条任务数据。
然后测试如下:
改进:
一个用户只能查看属于自己的任务。
所以先定义User模型与Task模型之间的关系:
User.php中添加:
public function tasks() { return $this->hasMany(Task::class); }
Task.php中添加:
public function user() { return $this->belongsTo(User::class); }
完善Task.php:
添加
protected $fillable = ['user_id', 'title', 'description', 'due'];
terminal中键入exit退出tinker控制台。
执行:
从本质上来说,资源的作用很简单。它们只需要将一个给定的模型转换成一个数组。所以每一个资源都包含一个
toArray
方法用来将你的模型属性转换成一个可以返回给用户的 API 友好数组
php artisan make:resource TaskResource
修改api.php:
将之前的
Route::resource('task', ‘TaskController');
修改为
Route::apiResource('tasks', 'TaskController')->middleware('auth:api');
修改TaskController的index方法如下:
public function index() { // $tasks = TaskResource::collection(auth()->user()->tasks()->latest()->paginate(4)); return response($tasks, 200); }
现在我们需要先登录,获取用户token
然后用这个token放置于authorization中,
然后发送请求获取属于user的对应的全部task资源数据。
如果没有这个token会显示:
接下来完善store方法,注意我们是api方式所以不需要几个show form方法:
删除掉就行。
创建资源前需要验证,然后验证用户通过模型关联创建task即可,最后返回一个taskresource实例。
public function store(Request $request) { $validated = Validator::make($request->all(), [ 'title' => 'required|max:255', ]); if ($validated->fails()) { return response($validated->errors()->all()); } $task = auth()->user()->tasks()->create($request->all()); return new TaskResource($task->load('user')); }
最后返回的时候,我们用了load方法,这里不能用with,具体区别在于with是一次,load是分开,因为我们先获取生成的task,所以是分开的,只能用load。
PostMan测试如下:
Token我们已经登录后然后配置了:
发送请求:
show方法修改如下:
postman测试:
update方法:
public function update(Request $request, Task $task) { // $validated = Validator::make($request->all(), [ 'title' => 'required|max:255', ]); if ($validated->fails()) { return response($validated->errors()->all()); } if (!auth()->user()->tasks->contains($task)) { return response('No permission!', 422); } $task->update($request->all()); return new TaskResource($task->load('user')); }
Postman测试:
或发送:
数据库查看结果:
在destroy方法之前我们还是给模型添加一个软删除的支持,
以及对应的migrate添加:
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class AddSoftdeteleToUsersTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::table('users', function (Blueprint $table) { // $table->softDeletes(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('users', function (Blueprint $table) { // $table->dropSoftDeletes(); }); } }
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class AddSoftdeteleToTasksTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::table('tasks', function (Blueprint $table) { // $table->softDeletes(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('tasks', function (Blueprint $table) { // $table->dropSoftDeletes(); }); } }
执行:
php artisan migrate
destory方法:
public function destroy(Task $task) { // if (!auth()->user()->tasks->contains($task)) { return response('No permission!', 422); } $task->delete(); return response(['message' => 'Success deleted!']); }
最后Postman测试结果:
数据库结果:
due修正后:
store方法:
public function store(Request $request) { $validated = Validator::make($request->all(), [ 'title' => 'required|max:255', ]); if ($validated->fails()) { return response($validated->errors()->all()); } $input = $request->all(); if ($request->has('due')) { $input['due'] = Carbon::parse($request->get('due'))->toDateTimeString(); } $task = auth()->user()->tasks()->create($input); return new TaskResource($task->load('user')); }
update方法:
public function update(Request $request, Task $task) { // $validated = Validator::make($request->all(), [ 'title' => 'required|max:255', ]); if ($validated->fails()) { return response($validated->errors()->all()); } if (!auth()->user()->tasks->contains($task)) { return response('No permission!', 422); } $input = $request->all(); if ($request->has('due')) { $input['due'] = Carbon::parse($request->get('due'))->toDateTimeString(); } $task->update($input); return new TaskResource($task->load('user')); }
PostMan测试结果:
以及:
数据库查看: