Membuat Aplikasi Ekspedisi Lumen 6 #2: Authentication & Manage Users

Membuat Aplikasi Ekspedisi Lumen 6 #2: Authentication & Manage Users

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.

aplikasi ekspedisi lumen 6 - postman

Kemudian tekan tombol Send, maka kita akan mendapatkan error karena secara default Lumen tidak mengaktifkan Eloquent.

aplikasi ekspedisi lumen 6 - error config

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

aplikasi ekspedisi lumen 6 - get users

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.

aplikasi ekspedisi lumen 6 - store data

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.

aplikasi ekspedisi lumen 6 - get data

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.

aplikasi ekspedisi lumen 6 - update data users

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');

aplikasi ekspedisi lumen 6 - delete users data

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.

aplikasi ekspedisi lumen 6 - authentication

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.

Category:
Share:

Comments