3

I am developing a Laravel API and am encountering issues with my ::put method. I can successfully create and retrieve a model, but when I attempt to delete or update, I receive Laravel's 404 page instead of the expected JSON response. If I use ::post to update the model, it works beautifully, but ::put should work as well and it doesn't.

In Postman, I first run the login route to authenticate the user. Then, I create a model successfully. However, when I attempt to update, it returns a 404 error instead of my expected JSON response of 'Badge not found'.

Here are the relevant parts of my BadgeController for update and destroy methods:

public function update(StoreBadgeRequest $request, Badge $badge): JsonResponse
{
    // Check if the badge exists
    if (!$badge->exists) {
        return new JsonResponse([
            'message' => 'Badge not found.'
        ], Response::HTTP_NOT_FOUND);
    }

    // Check if user has permission to edit badges
    if (!auth()->user()->can('edit-badge')) {
        return new JsonResponse([
            'message' => 'You are not authorized to edit a badge.'
        ], Response::HTTP_FORBIDDEN);
    }

    $badge->update($request->validated());

    return new JsonResponse([
        'message' => 'Badge updated successfully.'
    ], Response::HTTP_OK);
}

public function destroy(Badge $badge): JsonResponse
{
    // Check if user has permission to delete badges
    if (!auth()->user()->can('delete-badge')) {
        return new JsonResponse([
            'message' => 'You are not authorized to delete a badge.'
        ], Response::HTTP_FORBIDDEN);
    }

    $badge->delete();

    return new JsonResponse(
        [
            'message' => 'Badge deleted successfully.'
        ],
        Response::HTTP_OK
    );
}

API Endpoints:

Route::middleware('auth:api')->group(function () {
    // Badges Routes
    Route::put('/badges/{badge}', [BadgeController::class, 'update']);
    Route::patch('/badges/{badge}', [BadgeController::class, 'update']);
    Route::delete('/badges/{badge}', [BadgeController::class, 'destroy']);
});
1
  • It is an API with a react frontend but i am testing with Postman. It works beautifully when using POST but it should work when updating a model using PUT. Commented Dec 4, 2024 at 1:18

1 Answer 1

3

If the model does not exist Laravel automatically throws a ModelNotFoundException when using Model route bindings, which will respond with the Laravel 404 exception page.

The following post explains how you can change the default handling of this exception for your API: https://laraveldaily.com/post/laravel-api-404-response-return-json-instead-of-webpage-error

You should in theory be able to leverage the exceptions getModel method to create a dynamic response for every resource:

use Illuminate\Database\Eloquent\ModelNotFoundException;

// ...

public function render($request, Exception $exception)
{
    if ($exception instanceof ModelNotFoundException && $request->wantsJson()) {
        if(empty($exception->getModel()){
            return response()->json(['message' => 'Not Found!'], Response::HTTP_NOT_FOUND);
        }

        return response()->json([
            'message' => sprintf('%s not Found!', $exception->getModel())
        ], Response::HTTP_NOT_FOUND);
    }

    return parent::render($request, $exception);
}

If you want to apply custom behavior per route, you can either:

  1. Disable Model Bindings and query the model yourself.
  2. Use the Laravel missing method to customize the response per route: https://laravel.com/docs/11.x/routing#customizing-missing-model-behavior
Sign up to request clarification or add additional context in comments.

2 Comments

The model exists. It wouldnt be throwing a 404. That is what's weird. It works when I update using ::post, but not put
Ah, it just seemed like your question was about the correct handling of the not found exception. Anyways you might have to look into some of the solutions from this question: stackoverflow.com/questions/50691938/…. I don't really like the _method="PUT" solution. So if you are not uploading files I would recommend changing the 'Content-Type' to either 'raw' or 'application/x-www-form-urlencoded'. And when testing with Postman you could also use one of these options instead

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.