Exception and Error Handler Laravel 5.7

Rizal Fauzi Wahyu
6 min readJan 14, 2019

--

Referensi : https://laraveldaily.com/how-to-catch-handle-create-laravel-exceptions/

Laravel exception merupakan salah satu cara bagi para developer web untuk menangani dan menanggapi pesan error yang terjadi, biasanya para developer kurang peduli mengenai hal ini dan ketika terdapat error, laravel menampilkan pesan defaultnya, bisa berupa error code atau yang lain. Tentu saja hal ini bisa membingungkan para pengunjung. Atas dasar inilah mari kita bersama sama belajar bagaimana caranya untuk menangani error dengan cara yang elegan dengan mempresentasikan informasi error yang dapat dipahami oleh pengunjung.

Pada artikel ini kita akan belajar membuat sebuah contoh membuat service kita sendiri dengan menggunakan Dependency Injection, dan menangani exceptionnya melalui service tersebut.

Persiapan: User Search Task

Jadi kita akan membuat contoh yang simpel yaitu sebuah form yang digunakan untuk mecari user berdasarkan ID.

Kita akan membuat dua route di routes/web.php

Route::get('/users', 'UserController@index')->name('users.index');
Route::post('/users/search', 'UserController@search')->name('users.search');

dan kita buat controller UserController dengan perintah artisan :

php artisan make:controller UserController

dan buatlah dua method seperti berikut :

class UserController extends Controller
{
public function index()
{
return view('users.index');
}

public function search(Request $request)
{
$user = User::find($request->input('user_id'));
return view('users.search', compact('user'));
}
}

Setelah itu, buat view nya pada direktori resources/views/users/index.blade.php

<form action="{{ route('users.search') }}" method="POST">
@csrf
<div class="form-group">
<input id="user_id" class="form-control" name="user_id" type="text" value="{{ old('user_id') }}" placeholder="User ID">
</div>
<input class="btn btn-info" type="submit" value="Search">
</form>

Jika kita mencari user berdasarkan ID nya dan itu ditemukan, maka kita akan melihat hasil seperti dibawah ini, tetapi sebelumnya kita buat dulu view nya di resources/views/users/search.blade.php :

<h3 class="page-title text-center">User found: {{ $user->name }}</h3>
<b>Email</b>: {{ $user->email }}
<br>
<b>Registered on</b>: {{ $user->created_at }}

Yup ini adalah skenario ideal kita, tetapi bagaimana jika user ID tidak ditemukan ?

Exception Handling

Mari kita keluar dari zona nyaman. Kita sebelumnya tidak mencari keberadaan user, tetapi kita hanya melakukan ini pada controller kita :

$user = User::find($request->input('user_id'));

dan ketika user tidak ditemukan , kita akan melihat hal ini :

atau bisa saja kita mengatur .env file dengan mengedit APP_DEBUG=false dan selanjutnya browser akan menampilkan halaman kosong yang bertuliskan Whoops, look like something went wrong. Tetapi itu tidak memberikan informasi yang dapat dimengerti oleh pengunjung kita. Cara lain untuk dapat dengan cepat menyelesaikan masalah ini adalah dengan menggunakan User::findOfFail() atau hanya find()- selanjutnya jika user tidak ditemukan, laravel akan memperlihatkan halaman error code 404, tetapi halaman default 404 tetap saja tidak memberikan informasi yang dapat membantu pengunjung kita.

Jadi kita perlu menangkap errornya dan memprosesnya yang kemudian akan kita kembalikan ke form dengan menampilkan pesan error yang dapat dimengerti.

Kita perlu tau tipe exception dan nama class yang akan kita return. Dalam kasus findOrFail() ini akan mengembalikan exception ModelNotFoundException, jadi kita perlu melakukan hal ini dalan UserController :

public function search(Request $request)
{
try {
$user = User::findOrFail($request->input('user_id'));
} catch (ModelNotFoundException $exception) {
return back()->withError($exception->getMessage())->withInput();
}
return view('users.search', compact('user'));
}

Untuk menampilkan pesan error, kita perlu menambahkan hal berikut pada index.blade.php

@if (session('error'))
<div class="alert alert-danger">{{ session('error') }}</div>
@endif

Hasilnya :

kita telah berhasil menampilkan pesan error nya, tetapi tetap saja ini tidak bagus bukan ? Karena itu kita perlu menampilkan pesan dari kita sendiri :

return back()->withError('User not found by ID ' . $request->input('user_id'))->withInput();

Selesai!

Memindahkan Error Message Handling ke Service

Kita telah membuat contoh simple penanganan error message handling di controller. Pada kenyataanya seringkali hal ini akan lebih compleks oleh karena itu controller memanggil beberapa external service atau package method yang mana akan gagal dengan beberapa macam error yang berbeda. Oleh karena itu mari kita belajar untuk membuat sendiri service yang akan melakukan hal yang sama, tetapi akan throw exception, jadi kontroller bahkan tidak perlu tahu teks pesan error yang akan kita berikan.

Mari kita pindahkan Logic kita menuju app/Services/UserService.php:

namespace App\Services;

use App\User;
use Illuminate\Database\Eloquent\ModelNotFoundException;

class UserService
{

public function search($user_id)
{
$user = User::find($user_id);
if (!$user) {
throw new ModelNotFoundException('User not found by ID ' . $user_id);
}
return $user;
}

}

Dan pada kontroller, kita perlu memanggil service ini. Pertama, kita dapat meng inject service ini ke method __contruct() :

use App\Services\UserService;

class UserController extends Controller
{

private $userService;

public function __construct(UserService $userService)
{
$this->userService = $userService;
}

// ...

Jika kalian kurang familiar dengan istilah dependency injection dan bagaimana Laravel IOC container bekerja, ini adalah dokumentasi resmi atau artikel yang bagus tentang ini.

Sekarang, method search() kita akan terlihat seperti ini :

public function search(Request $request)
{
try {
$user = $this->userService->search($request->input('user_id'));
} catch (ModelNotFoundException $exception) {
return back()->withError($exception->getMessage())->withInput();
}
return view('users.search', compact('user'));
}

Perhatikan bahwasanya kita dapat menggunakan $exception->getMessage() lagi, dan semua error validasi atau pesan error akan terjadi di dalam service. Hal ini merupakan salah satu tujuannya, untuk membagi aksi, sehingga controller tidak harus melakukan aksi itu sendiri.

Step Lanjutan : Membuat Exception Class kita sendiri

Akan jauh lebih baik ketika service yang kita buat tadi throws exception nya sendiri yang terkait dengan error yang ditangani, dan dengan ini kita dapat menambahkan multiple exception tergantung pada error itu sendiri.
Kita dapat membuat exception dengan menggunakan perintah artisan :

php artisan make:exception UserNotFoundException

dan exception yang kita buat akan berada pada direktori app/Exception/UserNotFoundException.php

namespace App\Exceptions;

use Exception;

class UserNotFoundException extends Exception
{
//
}

Mari kita tambahkan exception kita dengan beberapa logic. Terdapat dua methods pada class exception ini :

  • report() digunakan ketika kita ingin menambahkan log / mengirim error ke BugSnag, email, Slack dll.
  • render() digunakan ketika kita ingin mengembalikan ke halaman sebelumnya dengan pesan error atau mengembalikan HTTP response (seperti blade file kita) secara langsung dari Exception class.

Pada contoh kali ini , mari kita isi method report() kita :

namespace App\Exceptions;

use Exception;

class UserNotFoundException extends Exception
{
/**
* Report or log an exception.
*
* @return void
*/
public function report()
{
\Log::debug('User not found');
}
}

Pada akhirnya, beginilah proses kita memanggil exception yang kita buat tadi dari kontroller :

public function search(Request $request)
{
try {
$user = $this->userService->search($request->input('user_id'));
} catch (UserNotFoundException $exception) {
report($exception);
return back()->withError($exception->getMessage())->withInput();
}
return view('users.search', compact('user'));
}

Kalian dapat melihat kode program secara penuh dibawah ini :

Sekian belajar kita pada kesempatan kali ini, apabila kalian merasa bingung dengan penjelasan di atas anda dapat mengunjungi sumber aslinya yang tertera di bawah judul, selamat mencoba dan terimakasih :)

--

--

Rizal Fauzi Wahyu

I'm an advocate of project-based learning. I also write technical content around web development.