laraveleloquentlaravel-apilaravel-exceptions

Understanding Laravel exception handling catching exceptions in the controller that have been thrown in service layer


Trying to create an API server with laravel. I have seen many tutorials that catch the exception thrown in the service layer. However, in Laravel, we have an option to create a custom error handler that has a render function that encapsulates the result as JSON.

When this exception is thrown in the ServiceLayer it automatically returns the response JSON to the caller. There is no need to catch the same error in the controller. But most of the how-tos seem to catch the same custom exception in the controller as well. Is there any reason?

My example code:

class CustomerSpecificException extends Exception
{

 /**
 * Report the exception.
 *
 * @return bool|null
 */
public function report()
{

}

/**
 * Render the exception into an HTTP response.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return \Illuminate\Http\Response
 */
public function render($request)
{                       
    //some more logic to discern the type of exception (but omitted for clarity's sake)
    return response()->json([       
        'error' => true,     
        'message' => 'Customer already exists',
        'message' => $this->getMessage()
    ], 404);
    
}

}

Now, here is my service layer. In the example, I process QueryException within my custom exception to relay back the relevant message here.

public function createOrUpdateCustomer(Request $request, $customer_id) : Customer
{
 try{
    //do something 

    }
    catch(QueryException $e)
    {
        throw new UniqueConstraintException();
    }        
 }

The above code already returns a response even without me catching the same error in the controller. Here is the controller code.

public function store(Request $request, CustomerService $customerService)
{                        
        return $customerService->createCustomer($request);
}

The above code works fine. When I hit the API from Postman, it returns the right error. Most of the how-tos, however, insist on a try-catch around the controller code, i.e., the store function above. Is my above code fine, or is there something that I am missing?


Solution

  • I am going to take a stab at this.

    First I think in theory because this is a runtime exception involving a database connection. I believe if laravel does not attempt to handle it prior to it being thrown up the chain in the controller function it will likely result in an ineffective exception being thrown and caught first... like a general whoops something went wrong, type of error. Therefore, I think if you were to add the exception handling in the controller you would likely want to do it in the controller constructor. That may not be correct, However, also a thing to note is in the exception handler there are a lot of predetermined exception routing being done.

    Also in that Handler class it extends the Handler from the framework where there are some functions based around renderable, reportable, ignore, report,etc...

    Illuminates Handler.php

        protected $internalDontReport = [
            AuthenticationException::class,
            AuthorizationException::class,
            BackedEnumCaseNotFoundException::class,
            HttpException::class,
            HttpResponseException::class,
            ModelNotFoundException::class,
            MultipleRecordsFoundException::class,
            RecordsNotFoundException::class,
            SuspiciousOperationException::class,
            TokenMismatchException::class,
            ValidationException::class,
        ];
    

    I think after looking through that file you will quickly pick up where, when, and how you would like to manage and implement your exception processing.