Pendahuluan
Aplikasi ekspedisi pengiriman barang menggunakan Lumen, dimana aplikasi ini merupakan aplikasi internal untuk mengelola usaha dari sebuah ekspedisi pengiriman. Sehingga diperlukan proses otentikasi dalam mengakses data yang dimilikinya, sekaligus kita akan membuat fitur untuk mengelola data users dan memberikan response berupa json untuk setiap request yang dilakukan.
Data user terdiri dari administrator, drivers dan pegawai lainnya, dimana sebagai langkah awal kita akan membuat CRUD melalui API (Application Programming Interface). Berikut adalah cara membuat fitur authentication dan manage users di Lumen.
Baca Juga: Membuat Aplikasi Ekspedisi Lumen 6 #1: Schema Database
Membuat Restful API Manage Users
Bagian pertama yang akan diselesaikan adalah restful API (Application Programming Interface) untuk mengelola data users, dimana fitur ini akan memiliki 5 buah fungsi, yakni: menampilkan semua data, menyimpan data, mengambil single data, memperbaharui data dan menghapus data. Masing-masing dari fungsi ini hanya akan menerima request dan memberikan response dalam bentuk json. Sehingga, sepanjang artikel seri Lumen ini, kita tidak akan pernah melihat adanya layout atau tampilan yang akan dibuat.
Get All Users
Poin pertama adalah menampilkan semua data, buat file UserController.php
secara manual di dalam folder app\Http\Controllers
karena Lumen tidak memiliki artisan command untuk men-generate controller. Kemudian masukkan struktur code berikut
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use App\User;
class UserController extends Controller
{
//METHOD UNTUK RESTFUL API AKAN DITEMPATKAN DISINI
}
Masih dengan file yang sama, tambahkan method index()
public function index()
{
//QUERY UNTUK MENGAMBIL DATA DARI TABLE USERS DAN DI-LOAD 10 DATA PER HALAMAN
$users = User::orderBy('created_at', 'desc')->paginate(10);
//KEMBALIKAN RESPONSE BERUPA JSON DENGAN FORMAT
//STATUS = SUCCESS
//DATA = DATA USERS DARI HASIL QUERY
return response()->json(['status' => 'success', 'data' => $users]);
}
Jangan lupa untuk untuk menambahkan use statement.
use App\User;
Kemudian buka file routes/web.php
dan definisikan routing-nya
$router->get('/users', 'UserController@index');
Untuk melakukan uji coba dari fungsi di atas, buka Postman dan masukkan url dw-logistik-api.test/users
jika menggunakan Valet atau sesuaikan url project kamu, dimana pada intinya adalah host/users
. Gunakan method GET karena routing yang didefinisikan menggunakan get.
Kemudian tekan tombol Send, maka kita akan mendapatkan error karena secara default Lumen tidak mengaktifkan Eloquent.
Untuk mengatasi masalah ini, buka file bootstrap/app.php
dan tambahkan code berikut
//[.. CODE SEBELUMNY ..]
$app->configure('app'); //TAMBAHKAN CODE INI
return $app;
Masih dengan file yang sama, uncomment code $app->withEloquent();
untuk mengatifkan penggunaan Eloquent. Maka hasil yang akan kita peroleh akan terlihat seperti gambar di bawah
Store User Data
Tugas selanjutnya adalah membuat fitur untuk menyimpan data ke database, tepatnya ke dalam table users
. Buka file UserController.php
dan tambahkan method berikut untuk meng-handle data yang dikirimkan oleh users.
public function store(Request $request)
{
//DEFAULTNYA FILENAME ADALAH NULL KARENA USER YANG TIPENYA BUKAN DRIVER, BISA MENGOSONGKAN FOTO DIRI
$filaname = null;
//KEMUDIAN CEK JIKA ADA FILE YANG DIKIRIMKAN
if ($request->hasFile('photo')) {
//MAKA GENERATE NAMA UNTUK FILE TERSEBUT DENGAN FORMAT STRING RANDOM + EMAIL
$filaname = Str::random(5) . $request->email . '.jpg';
$file = $request->file('photo');
$file->move(base_path('public/images'), $filaname); //SIMPAN FILE TERSEBUT KE DALAM FOLDER PUBLIC/IMAGES
}
//SIMPAN DATA USER KE DALAM TABLE USERS MENGGUNAKAN MODEL USER
User::create([
'name' => $request->name,
'identity_id' => $request->identity_id,
'gender' => $request->gender,
'address' => $request->address,
'photo' => $filaname, //UNTUK FOTO KITA GUNAKAN VALUE DARI VARIABLE FILENAME
'email' => $request->email,
'password' => app('hash')->make($request->password), //PASSWORDNYA KITA ENCRYPT
'phone_number' => $request->phone_number,
// 'api_token' => 'test', //BAGIAN INI HARUSNYA KOSONG KARENA AKAN TERISI JIKA USER LOGIN
'role' => $request->role,
'status' => $request->status
]);
return response()->json(['status' => 'success']);
}
Dengan file yang sama, tambahkan use statement
use Illuminate\Support\Str;
use Illuminate\Http\Request;
Kemudian definisikan routing-nya dengan method POST, buka file routes/web.php
dan tambahkan code
$router->post('/users', 'UserController@store');
Karena api_token
belum nullable, sehingga field tersebut mengharuskan kita memasukkan value ke dalamnya, jadi generate migration baru untuk mengubahnya jadi nullable. Dari command line, jalankan command
php artisan make:migration change_api_token_nullable_to_users_table
Kemudian buka file migration baru tersebut dan modifikasi menjadi
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class ChangeApiTokenNullableToUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('api_token', 40)->nullable()->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->string('api_token', 40)->change();
});
}
}
Sebelum mengeksekusinya, install doctrine/dbal karena dibutuhkan package ini untuk menjalankan fungsi change()
.
composer require doctrine/dbal
Dari command line, jalankan perintah php artisan migrate
untuk menerapkan migration di atas.
Izinkan mass assignment agar bisa menyimpan data menggunakan Eloquent, buka file User.php
dan modifikasi menjadi
<?php
namespace App;
use Illuminate\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Database\Eloquent\Model;
use Laravel\Lumen\Auth\Authorizable;
class User extends Model implements AuthenticatableContract, AuthorizableContract
{
use Authenticatable, Authorizable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
// protected $fillable = [
// 'name', 'email',
// ];
protected $guarded = [];
/**
* The attributes excluded from the model's JSON form.
*
* @var array
*/
protected $hidden = [
'password',
];
}
Kembali ke Postman, hit ke url yang baru dengan method POST sambil mengirimkan data user untuk disimpan ke database.
Note: Pada field photo
, ganti type dari text menjadi file agar bisa memilih file yang akan disimpan.
Get Single Data
Selanjutnya adalah fungsi untuk mengambil single data berdasarkan id, buka file UserController.php
dan tambahkan code.
public function edit($id)
{
//MENGAMBIL DATA BERDASARKAN ID
$user = User::find($id);
//KEMUDIAN KIRIM DATANYA DALAM BENTUL JSON.
return response()->json(['status' => 'success', 'data' => $user]);
}
Definisikan routing-nya, buka file routes/web.php
dan tambahkan route.
$router->get('/users/{id}', 'UserController@edit');
Akses datanya dari url /users/{id}
dimana id diambil dari data yang ada di-table users.
Update User Data
Memperbaharui data user berdasarkan id, dimana skenarionya untuk saat ini adalah semua data akan di-update kecuali email. Buka file UserController.php
dan tambahkan method.
public function update(Request $request, $id)
{
$user = User::find($id); //GET DATA USER
//JIKA PASSWORD YANG DIKIRIMKAN USER KOSONG, BERARTI DIA TIDAK INGIN MENGGANTI PASSWORD, MAKA KITA AKAN MENGAMBIL PASSWORD SAAT INI UNTUK DISIMPAN KEMBALI
//JIKA TIDAK KOSONG, MAKA KITA ENCRYPT PASSWORD YANG BARU
$password = $request->password != '' ? app('hash')->make($request->password):$user->password;
//LOGIC YANG SAMA ADALAH DEFAULT DARI $FILENAME ADALAH NAMA FILE DARI DATABASE
$filaname = $user->photo;
//JIKA ADA FILE GAMBAR YANG DIKIRIM
if ($request->hasFile('photo')) {
//MAKA KITA GENERATE NAMA DAN SIMPAN FILE BARU TERSEBUT
$filaname = Str::random(5) . $user->email . '.jpg';
$file = $request->file('photo');
$file->move(base_path('public/images'), $filaname); //
//HAPUS FILE LAMA
unlink(base_path('public/images/' . $user->photo));
}
//KEMUDIAN PERBAHARUI DATA USERS
$user->update([
'name' => $request->name,
'identity_id' => $request->identity_id,
'gender' => $request->gender,
'address' => $request->address,
'photo' => $filaname,
'password' => $password,
'phone_number' => $request->phone_number,
'role' => $request->role,
'status' => $request->status
]);
return response()->json(['status' => 'success']);
}
Kembali lagi, definisikan routing-nya, buka file routes/web.php
dan tambahkan code
$router->put('/users/{id}', 'UserController@update');
Entah kenapa jika kita menggunakan method PUT di Postman, tidak ada data yang dikirimkan jika menggunakan form-data, jadi untuk uji coba, gunakan method POST dengan menambahkan satu field baru yakni _method
dengan value PUT.
Delete User Data
Fitur terakhir adalah menghapus data user berdasarkan id, buka file UserController.php
dan tambahkan method.
public function destroy($id)
{
$user = User::find($id);
unlink(base_path('public/images/' . $user->photo));
$user->delete();
return response()->json(['status' => 'success']);
}
Buat routing terakhir, buka file routes/web.php
dan tambahkan code
$router->delete('/users/{id}', 'UserController@destroy');
Mengaktifkan API Authentication di Lumen
Dari semua fitur yang dibuat di atas, belum ada fungsi untuk membatasi akses hanya kepada user yang memiliki akses / akun saja. Adapun proses otentikasi API diidentifikasi dengan token yang dikirimkan melalui headers, jadi pada setiap request yang dikirimkan harus disertakan api_token
.
Pertama kita bungkus routing yang sudah dibuat, dengan route group middleware auth. Buka file routes/web.php
dan modifikasi menjadi
$router->group(['middleware' => 'auth'], function() use($router) {
$router->get('/users', 'UserController@index');
$router->post('/users', 'UserController@store');
$router->get('/users/{id}', 'UserController@edit');
$router->put('/users/{id}', 'UserController@update');
$router->delete('/users/{id}', 'UserController@destroy');
});
Agar dapat menggunakan middleware auth
, aktifkan terlebih dahulu fungsi tersebut. Buka file bootstrap/app.php
dan uncomment beberapa code berikut.
$app->routeMiddleware([
'auth' => App\Http\Middleware\Authenticate::class,
]);
$app->register(App\Providers\AppServiceProvider::class);
$app->register(App\Providers\AuthServiceProvider::class);
Kemudian buka file app/Providers/AuthServiceProvider.php
dan modifikasi method boot()
menjadi
public function boot()
{
// Here you may define how you wish users to be authenticated for your Lumen
// application. The callback which receives the incoming request instance
// should return either a User instance or null. You're free to obtain
// the User instance via an API token or any other method necessary.
$this->app['auth']->viaRequest('api', function ($request) {
// if ($request->input('api_token')) {
// return User::where('api_token', $request->input('api_token'))->first();
// }
//JIKA ADA HEADER AUTHORIZATION YANG DIKIRIMKAN
if ($request->header('Authorization')) {
//MAKA EXPLODE KARENA FORMATNYA ADA BEARER + TEKEN
//SEDANGKAN YANG DIINGINKAN HANYA TOKENNYA SAJA
$explode = explode(' ', $request->header('Authorization'));
//KEMUDIAN FIND USER BERDASARKAN TOKEN YANG DITERIMA
return User::where('api_token', $explode[1])->first();
}
});
}
Tahap terakhir adalah membuat default user yang sudah memiliki api_token
, karena fitur login belum dibuat pada seri kali ini. Generate seeder untuk membuat data users tersebut, dari command line, jalankan perintah.
php artisan make:seeder UsersTableSeeder
Kemudian buka file database/seeds/UsersTableSeeder.php
dan modifikasi menjadi
<?php
use Illuminate\Database\Seeder;
use Illuminate\Support\Str;
use App\User;
class UsersTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
User::create([
'name' => 'Daengweb',
'identity_id' => '12345678345',
'gender' => 1,
'address' => 'Jl Sultan Hasanuddin',
'photo' => 'daengweb.png', //note: tidak ada gambar
'email' => '[email protected]',
'password' => app('hash')->make('secret'),
'phone_number' => '085343966997',
'api_token' => Str::random(40),
'role' => 0,
'status' => 1
]);
}
}
Eksekusi seeder di atas dengan command php artisan db:seed --class=UsersTableSeeder
.
Setiap kali melakukan hit ke API, pastikan mengirimkan header Authorization.
Adapun token-nya bisa anda ambil dari value yang ada pada field api_token
dari table users.
[Issue] Set Nullable Field Photo
Fitur untuk menyimpan foto user sifatnya opsional, karena skenario yang diinginkan adalah hanya user dengan tipe driver yang akan diambil fotonya untuk didata. Adapun user lain yang sifatnya menetap dikantor ekspedisi tidak diperlukan. Sehingga kita perlu mengubah field photo
menjadi nullable.
Dari command line, generate migration baru dengan command
php artisan make:migration change_photo_nullable_to_users_table
Buka file migration yang baru, kemudian modifikasi menjadi.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class ChangePhotoNullableToUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('photo')->nullable()->change(); //SET NULLABLE
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->string('photo')->change();
});
}
}
Jangan lupa untuk mengeksekusinya dengan command php artisan migrate
.
Baca Juga: Aplikasi E-Commerce Laravel 6 #18: Membuat Fitur Afiliasi
Kesimpulan
Sepanjang artikel seri ke-2 dalam membuat aplikasi ekspedisi menggunakan Lumen, dimana kita telah belajar bagaimana cara membuat restful API yang terdiri dari fitur get, post, update dan delete. Kita juga telah belajar bagaimana mengaktifkan fungsi authentication di Lumen.
Adapun dokumentasi code dari artikel ini bisa dilihat di Github.
Comments