Laravel: Better Exception Handling

Wei Zhang
3 min readMay 9, 2021

Few years ago Model View Controller (MVC) become a topic that is too hot to be ignore. In few years time, engineers realise that fat controller or fat model has made the application become too difficult to manage, code logic wasn’t reuse and our code wasn’t organised.

Then we adding more layers in application to solve this problem. “Services” layer and “repositories” layer is added in between controller and model, some engineer team will like to have an extra layer call “logic” layer that lays between controller and service layer. Besides, in Laravel have “Request” for validating and processing request and “Resource” for responses processing.

In Laravel, a request start from path like this.

router -> (middleware) ->(request) -> controller -> (logic) -> (service) -> (repository) -> model

After the data was queries, it will be processed and returning in this path

model ->(repository) -> (service) -> (resources) -> controller -> (view)

(brackets) represent the layer was optional, depends on application type and complexities.

In above request path, we see a request can go through between 3–10 layers of logic. It also describe the complexity to manage and organise a scalable architecture of backend development.

From this architecture, we also see a new problem that is how errors was returned and how to standardise it? Standardisation has become more important when application complexity has increasing as product and team growth.

Let’s code

if (something wrong) {
return response()->json("something wrong", 403);
}

This code was how we can throw error when we working in the simplest form of MVC application. This approach start getting wrong when we adding a service layer and repository layer in application.

// In repository layer
if (something wrong) {
return false;
}
// In service layer
if (false result from repository layer) {
return false;
}
// In controller
if (false result from service layer) {
return response()->json("something wrong", 403);
}

As the application has implemented more layers, there will be more “if” statement appears in every layer in the application. To eliminate this, we can use of exception handling in Laravel.

Create a CustomException by running command php artisan make:exception CustomException then we change the contents like code below.

<?php

namespace App\Exceptions;


class CustomException extends \Exception
{
protected $custom_code;

public function __construct($message, $customCode)
{
parent::__construct($message, 422);

$this->custom_code = $customCode;
}

public function getCustomCode()
{
return $this->custom_code;
}
}

In file Handler.php , we add custom handling for CustomException inside function render.

if ($exception instanceof CustomException) {
return response()->json([
"code" => $exception->getCustomCode(),
'message' => $exception->getMessage()
], $exception->getCode());
}

Add CustomException::class inside $dontReport to skip error reporting in the application.

In command line, we run php artisan make:exception InvalidPasswordException and extend our CustomException.

<?php

namespace App\Exceptions;

class InvalidPasswordException extends CustomException
{
public function __construct()
{
parent::__construct(trans('messages.invalid_password'), 1);
}
}

Now we can return a standardised exception by just throw the exception anywhere in from application.

if (!$this->validatePassword()) {
throw new InvalidPasswordException();
}

The response will be return with header 422that defined in function__construct of file Handler.php and the response body will become this:

{
"code": 1,
"message": "Invalid Password"
}

Document it, spread it.

Documentation often been ignored in many tech teams. IMO, implementing it can be a really good solution to reduce repetitive discussion and improve effective collaboration between teams or engineers.

Exception Documentation

Final

Although this implements was from backend, its impacts for clients integration could be much greater than what we can expect. Therefore, defining standard error response shouldn’t be a decision only from backend. Gathering opinions from people who have different perspective can surely help to make sure the standard design balance every teams needs.

--

--

Wei Zhang

Software Engineer, based in Malaysia. 90% backend 10% frontend. PHP, Typescript, JavaScript, NodeJs, MySQL, DynamoDB, PostgreSQL, VueJS, ReactJS, Laravel