Another short lesson will be about the endpoint of updating the Travel record by the editor
user role. We will mostly re-use the things we had done already in previous lessons.
A private (editor) endpoint to update a travel.
That's it. That's all we have.
We already have a method to create Travel by admin
user. We will use the same Controller and add the update()
method.
app/Http/Controllers/Api/V1/Admin/TravelController.php:
class TravelController extends Controller{ public function store(TravelRequest $request) { $travel = Travel::create($request->validated()); return new TravelResource($travel); } public function update(Travel $travel, TravelRequest $request) { $travel->update($request->validated()); return new TravelResource($travel); }}
We use the same TravelRequest
for the validation because the rules are identical.
The difference in using those methods will be in the Middleware:
store()
should be accessed by the admin
roleupdate()
should be accessed by both admin
and editor
rolesHere's the updated Route:
routes/api.php:
Route::prefix('admin')->middleware(['auth:sanctum'])->group(function () { Route::middleware('role:admin')->group(function () { Route::post('travels', [Admin\TravelController::class, 'store']); Route::post('travels/{travel}/tours', [Admin\TourController::class, 'store']); }); Route::put('travels/{travel}', [Admin\TravelController::class, 'update']);});
As you can see, for the update()
method, we use a PUT request with Route::put()
. This is a standard practice in REST API systems.
Notice: in this case, we rely on the fact that there are only admin
and editor
roles, so we can assume that the Travel Update endpoint is accessible to any logged-in user. If the system adds more roles in the future, we will need to add something like role:admin,editor
and modify the Middleware to accept a comma-separated role list as a parameter.
We launch it in Postman, and the record is successfully updated!
This one is also simple. We just add one more method to the existing AdminTravelTest
file.
tests/Feature/AdminTravelTest.php:
class AdminTravelTest extends TestCase{ use RefreshDatabase; // ... other methods public function test_updates_travel_successfully_with_valid_data(): void { $this->seed(RoleSeeder::class); $user = User::factory()->create(); $user->roles()->attach(Role::where('name', 'editor')->value('id')); $travel = Travel::factory()->create(); $response = $this->actingAs($user)->putJson('/api/v1/admin/travels/'.$travel->id, [ 'name' => 'Travel name', ]); $response->assertStatus(422); $response = $this->actingAs($user)->putJson('/api/v1/admin/travels/'.$travel->id, [ 'name' => 'Travel name updated', 'is_public' => 1, 'description' => 'Some description', 'number_of_days' => 5, ]); $response->assertStatus(200); $response = $this->get('/api/v1/travels'); $response->assertJsonFragment(['name' => 'Travel name updated']); }}
We launch the test suite, and it's green! We've finished writing the functionality of the project, which is covered by 19 tests, in total.
As a few final steps, we need to perform a cleanup and write the documentation.