Restful API Laravel 11

Tutorial

Pada tutorial kali ini, kita akan mempelajari tentang pembuatan RESTful API di Laravel 11, untuk pemula. Tutorial ini akan menerangkan langkah-langkah awal menginstall Laravel 11 hingga pengujian API yang telah dibuat. Selama proses pembuatan API, kita juga akan belajar cara mengupload gambar di Laravel 11. Selain itu, kita akan memanfaatkan fitur bawaan Laravel yang dikenal sebagai API Resources. Dengan menggunakan fitur ini, kita dapat dengan mudah dan cepat menampilkan data dari model ke format JSON.

Membuat Project Laravel 11

Tahapan awal yang perlu dilakukan adalah menginstal Composer pada komputer. Untuk menginstal Composer, kalian dapat mengikuti panduan yang disediakan oleh situs resminya di sini.

Jika composer telah terinstall, maka kita dapat membuat sebuah projek laravel baru dengan menggunakan perintah berikut pada terminal/CMD.

terminal/CMD
composer create-project --prefer-dist laravel/laravel:^11.0 laravel11-restapi

Dalam beberapa kasus, instalasi laravel 11 akan gagal dan menampilkan error seperti berikut.

Hal ini disebabkan karena secara default, laravel 11 menggunakan sqlite sebagai driver database default. Untuk menghilangkan error ini, bisa dengan mengaktifkan ekstensi pdo_sqlite pada php nya. Jika ekstensi pdo_sqlite pada php sudah diaktifkan, maka proses instalasi tidak akan error. Kalian juga bisa mengabaikan error ini karena nanti kita akan menggunakan mysql sebagai dirver database nya.

Sekarang kita dapat masuk ke dalam folder project dan menjalankan project laravel 11 yang baru kita install.

terminal/CMD
cd laravel11-restapi
php artisan serve

Perintah tersebut digunakan untuk menjalankan server local Laravel. Jika berhasil, proyek kita akan berjalan di localhost dengan port 8000. Kalian dapat membukanya di browser dengan mengetikkan http://localhost:8000. Jika berhasil, akan ditampilkan hasil seperti berikut ini.

Menjalankan Storange Link

Karena kita akan mengupload gambar, maka kita perlu menjalankan perintah storage:link di Laravel. Hal ini kita lakukan agar nantinya kita dapat mengakses file yang telah kita upload pada Projek Laravel. Silahkan mengetik perintah berikut pada terminal/CMD dan pastikan kalian berada pada folder projek laravel.

terminal/CMD
php artisan storage:link

Membuat Model dan Migration

Untuk membuat file Model dan Migration. kita dapat menjalankan perintah berikut pada terminal/CMD.

terminal/CMD
php artisan make:model Post -m

Jika berhasil, maka akan ada 2 file baru pada folder Model dan Migration.

  1. app/Models/Post.php
  2. database/migrations/ xxx_xx_xx_xxxxxx_create_posts_table.php

untuk nama file migration akan random sesuai waktu pembuatannya.

Kemudian kita dapat mengubah file migration untuk menambahkan Field / Kolom pada method up.

xx_create_posts_table.php
/**
* Run the migrations.
*/
public function up(): void
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->string('title');
        $table->string('image');
        $table->text('content');
        $table->timestamps();
    });
}

Kita sudah menambahkan 3 field baru di dalam file migration, yaitu title, image, dan content. Berikut ini detailnya.

FieldType DataKeterangan
titleStringuntuk menyimpan judul post.
imageStringuntuk menyimpan nama gambar yang di upload.
contentTextuntuk menyimpan isi post.

Kita juga perlu mengubah file Model, agar field yang telah kita tambahkan dapat menyimpan nilai ke dalam database. Silahkan buka file app/Models/Post.php dan tambahkan kode berikut.

app/Models/Post.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;
    
    /**
     * fillable
     *
     * @var array
     */
    protected $fillable = [
        'image',
        'title',
        'content',
    ];
    
    /**
     * image
     *
     * @return Attribute
     */
    protected function image(): Attribute
    {
        return Attribute::make(
            get: fn ($image) => url('/storage/posts/' . $image),
        );
    }
}

Pada kode di atas, kita menambahkan properti baru dengan nama $fillable. properti tersebut disebut dengan Mass Assignment dan di dalamnya berisikan fields yang sesuai di dalam file migration.

Kita juga membuat method baru dengan nama image(). Hal ini disebut Accessor yang memungkinkan kita untuk mengubah nilai pada field. Dalam method ini, kita mengembalikan field image untuk menghasilkan URL lengkap dari folder storage. Jadi, saat kita memanggil field image, outputnya akan otomatis seperti ini:

http://localhost:8000/storage/posts/nama-file.png

Kemudian kita harus melakukan konfigurasi database mysql. Silahkan buka file .env , kemudian tambahkan kode berikut ini.

.env
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel11-restapi
DB_USERNAME=root
DB_PASSWORD=
DB_COLLATION=utf8mb4_unicode_ci

SESSION_DRIVER=database
SESSION_LIFETIME=120

Setelah semua berhasil dibuat, berikutnya kita dapat menjalankan perintah migrate. Dengan menjalankan perintah ini, maka database beserta tabel dan juga field-nya akan digenerate.

Silahkan jalankan perintah berikut ini di dalam terminal/CMD di dalam project Laravel-nya.

terminal/CMD
php artisan migrate

Jika muncul pertanyaan seperti ini, maka silahkan pilih Yes dan tekan Enter.

Membuat API Resources

Selanjutnya kita akan membuat API resources. Tujuan dari API Resources ini adalah untuk mengonversi data dari Model ke dalam format JSON sesuai kebutuhan, termasuk penambahan informasi status dan pesan yang akan ditampilkan.

Silahkan jalankan perintah berikut ini di dalam terminal/CMD di dalam project Laravel-nya.

terminal/CMD
php artisan make:resource ApiResource

Perintah di atas akan membuat sebuah file baru pada folder app/Http/Resources/ApiResource.php. Silahkan membuka file tersebut dan rubah semua kode nya menjadi seperti berikut ini:

app/Http/Resources/ApiResource.php
<?php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class ApiResource extends JsonResource
{
    /**
     * __construct
     *
     * @param mixed $status
     * @param mixed $message
     * @param mixed $data
     * @return void
     */
    public function __construct(public $status, public $message, public $data){ }

    /**
     * toArray
     *
     * @param mixed $request
     * @return array
     */
    public function toArray(Request $request): array
    {
        return [
            'status'  => $this->status,
            'message' => $this->message,
            'data'    => $this->data
        ];
    }
}

Dari perubahan kode di atas, pertama-tama, kita membuat method _construct yang menerima 3 parameter: $status, $message, dan $data, yang akan digunakan untuk menginisialisasi nilai dari properti $status dan $message sesuai dengan nilai yang diberikan oleh Controller.

Setelah itu, di dalam method toArray, kita mengubah bagian return-nya agar menghasilkan format JSON yang sesuai dengan kebutuhan. ApiResource ini dapat digunakan berulang agar format JSON yang ditampilkan seragam, lalu jika kita membutuhkan format JSON yang lain maka kita dapat membuat file Resource baru.

CRUD Post

Silahkan jalankan perintah berikut ini di dalam terminal/CMD di dalam project Laravel-nya.

terminal/CMD
php artisan make:controller Api/PostController

Perintah di atas akan membuat sebuah file baru pada folder app/Http/Controllers/Api/PostController.php. Silahkan membuka file tersbut dan rubah semua kode nya menjadi seperti berikut ini:

PostController.php
<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Resources\ApiResource;
use App\Models\Post;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;

class PostController extends Controller
{
    /**
     * index
     *
     * @return void
     */
    public function index()
    {
        //get latest posts
        $posts = Post::latest()->paginate(10);

        //return response
        return new ApiResource(true, 'All Posts', $posts);
    }

    /**
     * store
     *
     * @param mixed $request
     * @return void
     */
    public function store(Request $request)
    {
        //define validation rules
        $validator = Validator::make($request->all(), [
            'image'   => 'required|image|mimes:webp,jpeg,png,jpg|max:2048',
            'title'   => 'required',
            'content' => 'required',
        ]);

        //check if validation fails
        if ($validator->fails()) {
            //return error response
            return response()->json($validator->errors(), 422);
        }

        //upload image
        $image = $request->file('image');
        $image->storeAs('public/posts', $image->hashName());

        //create new post
        $post = Post::create([
            'image'   => $image->hashName(),
            'title'   => $request->title,
            'content' => $request->content,
        ]);

        //return response
        return new ApiResource(true, 'Post Created!', $post);
    }

    /**
     * show
     *
     * @param mixed $id
     * @return void
     */
    public function show($id)
    {
        //find post by ID
        $post = Post::find($id);

        //return single post resource
        return new ApiResource(true, 'Post Detail', $post);
    }

    /**
     * update
     *
     * @param mixed $request
     * @param mixed $id
     * @return void
     */
    public function update(Request $request, $id)
    {
        //define validation rules
        $validator = Validator::make($request->all(), [
            'title'   => 'required',
            'content' => 'required',
        ]);

        //check if validation fails
        if ($validator->fails()) {
            return response()->json($validator->errors(), 422);
        }

        //find post by ID
        $post = Post::find($id);

        //check if image is not empty
        if ($request->hasFile('image')) {
            //upload image
            $image = $request->file('image');
            $image->storeAs('public/posts', $image->hashName());

            //delete old image
            Storage::delete('public/posts/' . basename($post->image));

            //update post
            $post->update([
                'image'   => $image->hashName(),
                'title'   => $request->title,
                'content' => $request->content,
            ]);
        } else {
            //update post without upload image
            $post->update([
                'title'   => $request->title,
                'content' => $request->content,
            ]);
        }

        //return response
        return new ApiResource(true, 'Post Updated!', $post);
    }
    
    /**
     * destroy
     *
     * @param mixed $id
     * @return void
     */
    public function destroy($id)
    {
        //find post by ID
        $post = Post::find($id);

        //delete image
        Storage::delete('public/posts/'.basename($post->image));

        //delete post
        $post->delete();

        //return response
        return new ApiResource(true, 'Post Deleted!', null);
    }
}

Membuat Route Rest API

Pada Laravel 11 route api sudah tidak tersedia secara default saat membuat projek baru. Oleh karena itu kita harus menginstallnya terlebih dahulu. Silahkan jalankan perintah berikut ini di dalam terminal/CMD di dalam project Laravel-nya.

terminal/CMD
php artisan install:api

Sekarang route Untuk Rest API sudah tersedia di dalam folder routes/api.php. Silahkan membuka file tersebut dan mengubahnya menjadi seperti berikut:

routes/api.php
<?php

use App\Http\Controllers\Api\PostController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::get('/user', function (Request $request) {
    return $request->user();
})->middleware('auth:sanctum');

//posts
Route::apiResource('/posts', PostController::class);

Pada kode di atas, kita menambahkan route baru dengan jenis apiResource dan memiliki path /posts yang mengarah kepada PostController. Untuk memastikan route tersebut berhasil ditambahkan, jalankan perintah berikut ini di dalam terminal/CMD.

terminal/CMD
php artisan route:list

Uji Coba Rest API

Dalam pengujian ini, kita akan menggunakan Postman.

Insert Post

Sekarang buka aplikasi Postman, kemudian masukkan URL berikut ini http://localhost:8000/api/posts dan method-nya silahkan pilih POST. Kemudian masuk ke tab body, lalu pilih form data dan masukkan data sebagai berikut:

KEYTYPEVALUE
titletextjudul post 1
imagefilepilih gambar dari PC
contenttextini adalah content dari post pertama

Klik tombol Send. Jika berhasil maka akan menampilkan hasil seperti gambar di bawah ini. Silahkan menambahkan post beberapa kali untuk menyimpan lebih banyak data ke dalam database.

Menampilkan Post

Pada postman, silahkan mengganti method nya menjadi GET. Jika tidak ada error, maka akan menampilkan data Post terbaru sebagai berikut:

{
    "status": true,
    "message": "All Posts",
    "data": {
        "current_page": 1,
        "data": [
            {
                "id": 4,
                "title": "judul post 4",
                "image": "http://localhost:8000/storage/posts/sB4pLt3pcVPZ5rcSR6SaHzbr0NDXCvlVynRWrKuv.webp",
                "content": "Ini adalah content dari post keempat",
                "created_at": "2024-04-02T04:37:37.000000Z",
                "updated_at": "2024-04-02T04:37:37.000000Z"
            },
            {
                "id": 3,
                "title": "judul post 3",
                "image": "http://localhost:8000/storage/posts/538muPLLP19GgNWPgUkkPtEeVeWe3q4ot3GksoVI.webp",
                "content": "Ini adalah content dari post ketiga",
                "created_at": "2024-04-02T04:37:28.000000Z",
                "updated_at": "2024-04-02T04:37:28.000000Z"
            },
            {
                "id": 2,
                "title": "judul post 2",
                "image": "http://localhost:8000/storage/posts/sW7mZKhHWeriE5O5v1APX9GCr61dLsAc2LBTFK1E.webp",
                "content": "Ini adalah content dari post kedua",
                "created_at": "2024-04-02T04:37:21.000000Z",
                "updated_at": "2024-04-02T04:37:21.000000Z"
            },
            {
                "id": 1,
                "title": "judul post 1",
                "image": "http://localhost:8000/storage/posts/dWmZugz5b1gSIhzeoU4BGGDVXCRqJTYkdSPyeyrE.webp",
                "content": "Ini adalah content dari post pertama",
                "created_at": "2024-04-02T04:24:07.000000Z",
                "updated_at": "2024-04-02T04:24:07.000000Z"
            }
        ],
        "first_page_url": "http://localhost:8000/api/posts?page=1",
        "from": 1,
        "last_page": 1,
        "last_page_url": "http://localhost:8000/api/posts?page=1",
        "links": [
            {
                "url": null,
                "label": "« Previous",
                "active": false
            },
            {
                "url": "http://localhost:8000/api/posts?page=1",
                "label": "1",
                "active": true
            },
            {
                "url": null,
                "label": "Next »",
                "active": false
            }
        ],
        "next_page_url": null,
        "path": "http://localhost:8000/api/posts",
        "per_page": 10,
        "prev_page_url": null,
        "to": 4,
        "total": 4
    }
}

Menampilkan Detail Post

Tambahkan ID pada akhir URL pada Postman. Sebagai contoh, saya akan menampilkan detail Post dengan ID = 3. Maka URL nya menjadi http://localhost:8000/api/posts/3. Berikut hasil dari detail post.

{
    "status": true,
    "message": "Post Detail",
    "data": {
        "id": 3,
        "title": "judul post 3",
        "image": "http://localhost:8000/storage/posts/538muPLLP19GgNWPgUkkPtEeVeWe3q4ot3GksoVI.webp",
        "content": "Ini adalah content dari post ketiga",
        "created_at": "2024-04-02T04:37:28.000000Z",
        "updated_at": "2024-04-02T04:37:28.000000Z"
    }
}

Mengupdate Data Post

Sebagai contoh kita akan mengupdate Post dengan ID = 2. Maka ubah URL nya menjadi: http://localhost:8000/api/posts/2. Pilih Method menjadi POST, dan pada tab body isikan form-data sebagai berikut dan klik Send.

KEYTYPEVALUE
_methodtextPUT
titletextjudul post 1
imagefilepilih gambar dari PC
contenttextini adalah content dari post pertama

Jika berhasil, maka akan menampilkan hasil sebagai berikut:

Menghapus Data Post

Silahkan mengubah URL nya menjadi: http://localhost:8000/api/posts/4 untuk menghapus Post dengan ID=4. Rubah method nya menjadi DELETE. Jika berhasil akan menampilkan output Sebagai Berikut:

{
    "status": true,
    "message": "Post Deleted!",
    "data": null
}

Kita telah selesai membuat Sebuah Projek Restfull API pada Larevel 11. Pada artikel selanjutnya kita akan membuat Authentikasi Pada Laravel 11 dengan menggunakan Sanctum.

Recent Post