In this lesson, we will finalize our resource Controller with two missing methods: update and delete the category.
First, the update method. The method for the Route is PUT
, and in the Controller, the method is usually update
.
routes/api.php:
Route::get('/user', function (Request $request) { return $request->user();})->middleware('auth:sanctum'); Route::get('categories', [\App\Http\Controllers\Api\CategoryController::class, 'index']);Route::get('categories/{category}', [\App\Http\Controllers\Api\CategoryController::class, 'show']);Route::post('categories', [\App\Http\Controllers\Api\CategoryController::class, 'store']);Route::put('categories/{category}', [\App\Http\Controllers\Api\CategoryController::class, 'update']); Route::get('products', [\App\Http\Controllers\Api\ProductController::class, 'index']);
app/Http/Controllers/Api/CategoryController.php:
class CategoryController extends Controller{ // ... public function update(Category $category, StoreCategoryRequest $request) { $category->update($request->all()); return new CategoryResource($category); }}
In the Controller, we use a Route Model Binding to find a record and the same Form Request for validation. In the update
method, we update the category and return the updated category.
In the client, we can send a PUT request to the /api/categories
endpoint and pass the ID of an existing category.
In the result, we see the updated data.
Now, let's do the delete.
route/api.php:
Route::get('/user', function (Request $request) { return $request->user();})->middleware('auth:sanctum'); Route::get('categories', [\App\Http\Controllers\Api\CategoryController::class, 'index']);Route::get('categories/{category}', [\App\Http\Controllers\Api\CategoryController::class, 'show']);Route::post('categories', [\App\Http\Controllers\Api\CategoryController::class, 'store']);Route::put('categories/{category}', [\App\Http\Controllers\Api\CategoryController::class, 'update']);Route::delete('categories/{category}', [\App\Http\Controllers\Api\CategoryController::class, 'destroy']); Route::get('products', [\App\Http\Controllers\Api\ProductController::class, 'index']);
In the Controller, after the record is deleted, what to return? We don't have the record anymore. We can return a 204 no content status in such cases.
app/Http/Controllers/Api/CategoryController.php:
use Symfony\Component\HttpFoundation\Response; class CategoryController extends Controller{ // ... public function destroy(Category $category) { $category->delete(); return response(null, Response::HTTP_NO_CONTENT); }}
Or, we can use a shorter syntax.
app/Http/Controllers/Api/CategoryController.php:
class CategoryController extends Controller{ // ... public function destroy(Category $category) { $category->delete(); return response(null, Response::HTTP_NO_CONTENT); return response()->noContent(); }}
Let's launch the endpoint from the client.
As you can see, there is no content in the preview, and the status is 204 no content.
Finally, let's wrap all the Routes into a resource. In a typical Laravel project for the CRUD Controllers, you would make a resource Route.
Route::resource('categories', \App\Http\Controllers\Api\CategoryController::class);
But with API, there is a specific method called apiResource
. This method adds five Routes instead of seven. We don't need the create and edit methods when working with the API.
routes/api.php:
Route::get('/user', function (Request $request) { return $request->user();})->middleware('auth:sanctum'); Route::get('categories', [\App\Http\Controllers\Api\CategoryController::class, 'index']); Route::get('categories/{category}', [\App\Http\Controllers\Api\CategoryController::class, 'show']);Route::post('categories', [\App\Http\Controllers\Api\CategoryController::class, 'store']);Route::put('categories/{category}', [\App\Http\Controllers\Api\CategoryController::class, 'update']);Route::delete('categories/{category}', [\App\Http\Controllers\Api\CategoryController::class, 'destroy']); Route::apiResource('categories', \App\Http\Controllers\Api\CategoryController::class); Route::get('products', [\App\Http\Controllers\Api\ProductController::class, 'index']);
Thank you.
when updating and creating data, I would not write : request->all(), but would write the validated data: request->safe()
or
request->validated()
Delete does not work on categories that has products linked to it and throws "Integrity constraint violation: 19 FOREIGN KEY constraint failed" the migration needs to have onDelete
$table->foreignId('category_id')->constrained()->onDelete('cascade');
In theory you wouldn't want to delete products as they would be sold. Also, there's a helper
cascadeOnDelete()