Tutorial REST API


REST API adalah arsitektur yang digunakan untuk membangun layanan web yang dapat diakses melalui HTTP. Dalam blog ini, kita akan membahas bagaimana cara membuat REST API dengan menggunakan Laravel.

View on GitHub

Application Programming Interface (API)

Pengertian API

API (Application Programming Interface) merupakan sekumpulan aturan dan protokol yang memungkinkan aplikasi berbeda platform untuk berkomunikasi dan saling terintegrasi. API (Application Programming Interface) adalah media untuk komunikasi antara aplikasi yang berbeda. Dalam era digital saat ini, hampir semua aplikasi modern menggunakan API untuk:

Agar lebih memahami konsep dasar API berikut analogi API pemesanan makanan pada restoran.

Card image cap Card image cap

Berikut ini merupakan ilustrasi komponen utama API

Pengertian RESTful API

REST (Representational State Transfer) adalah arsitektur untuk merancang web services. REST bukan protokol atau standar, melainkan seperangkat prinsip desain.

Metode HTTP REST

HTTP Method Endpoint Deskripsi
GET /api/users Mendapatkan semua users
GET /api/users/1 Mendapatkan user dengan ID 1
POST /api/users Membuat user baru
PUT /api/users/1 Update user dengan ID 1
DELETE /api/users/1 Hapus user dengan ID 1
HTTP Method Deskripsi
GET Digunakan untuk mendapatkan data, GET bersifat idempoten (hasil yang sama meski dipanggil berulang) dan tidak mengubah state server
GET Digunakan untuk membuat resource baru dan tidak idempoten
PUT Update seluruh resource yang ada, PUT bersifat idempoten
PATCH Update sebagian field dan bersifat idempoten
DELETE Menghapus resources dan itempoten

Status HTTP

Kategori Kode Deskripsi
2xx Success 200 OK Request berhasil
201 Created Resource berhasil dibuat
204 No Content Request berhasil, tidak ada content
4xx Client Error 400 Bad Request Request tidak valid
401 Unauthorized Autentikasi diperlukan
403 Forbidden Akses ditolak
404 Not Found Resource tidak ditemukan
422 Unprocessable Entity Validation error
5xx Server Error 500 Internal Server Error Error di server
502 Bad Gateway Gateway error
503 Service Unavailable Service tidak tersedia

Persiapan Proyek

Mulai proyek dengan mengetik perintah ini di terminal. Dalam proyek ini, kita membutuhkan library API yang berupa abstraksi dari metode API.

composer create-project laravel/laravel api-project
cd api-project
php artisan install:api
php artisan serve

Pembuatan Migrasi

Pertama-tama, buat file migrasi dengan mengetikkan perintah di bawah ini ke terminal

php artisan make:migration create_products_table

Dalam proyek ini, kita membutuhkan tabel produk yang memiliki nama, deskripsi, harga, dan stok. Kode dari migrasi akan terlihat seperti yang di bawah.

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('products', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->text('description');
            $table->decimal('price', 10, 2);
            $table->integer('stock');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('products');
    }
};

Setelah itu, jalankan migrasi dengan menjalankan perintah

php artisan migrate

Pembuatan Model Produk

Model adalah data yang akan kita tampilkan kepada pengguna dan didasari oleh basis data yang telah disusun. Dalam laravel, data akan diletakkan di app/Models dengan perintah

php artisan make:model Product

Kodenya seperti ini

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    protected $fillable = [
        'name',
        'description',
        'price',
        'stock'
    ];

    protected $casts = [
        'price' => 'decimal:2'
    ];
}

Pembuatan Kontroler Produk dan Menjalankan API

Kontroler digunakan untuk mengendalikan request dan response yang akan ditampilkan kepada pengguna. Pada kontroler produk, terdapat metode index, store, show, update, delete. Untuk membuatnya, cukup dengan mengetik

php artisan make:controller ProductController --api

Setelah itu, buat kode sementara untuk program. Kode ini belum selesai karena hanya indexnya saja yang berfungsi. Oleh karena itu, dibutuhkan improvisasi yang akan ditampilkan nanti.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Product;

class ProductController extends Controller
{
    public function index()
    {
        $products = Product::all();
        return response()->json([
            'status' => 'success',
            'data' => $products
        ]);
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'description' => 'required|string',
            'price' => 'required|numeric|min:0',
            'stock' => 'required|integer|min:0'
        ]);

        $product = Product::create($validated);

        return response()->json([
            'status' => 'success',
            'message' => 'Product created successfully',
            'data' => $product
        ], 201);
    }

    public function show(Product $product)
    {
        return response()->json([
            'status' => 'success',
            'data' => $product
        ]);
    }

    public function update(Request $request, Product $product)
    {
        $validated = $request->validate([
            'name' => 'sometimes|string|max:255',
            'description' => 'sometimes|string',
            'price' => 'sometimes|numeric|min:0',
            'stock' => 'sometimes|integer|min:0'
        ]);

        $product->update($validated);

        return response()->json([
            'status' => 'success',
            'message' => 'Product updated successfully',
            'data' => $product
        ]);
    }

    public function destroy(Product $product)
    {
        $product->delete();

        return response()->json([
            'status' => 'success',
            'message' => 'Product deleted successfully'
        ]);
    }
}

Tambahkan rute API berdasarkan kontroler yang telah disusun

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProductController;

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

Sebenarnya API sudah dapat dijalankan dengan "php artisan migrate" akan tetapi dia akan selalu mengalami error ketika ada kesalahan pengambilan dan input data. Oleh karena itu, kita improvisasi dan tambahkan penganganan error.

Improvisasi dengan Resource dan Error Handling

Pembuatan Http Resource

Fitur yang memungkinkan untuk mentransformasi model data atau collection menjadi format JSON yang konsisten dan mudah dikustomisasi untuk API response. API Resource berfungsi sebagai layer transformasi antara model Eloquent dan JSON response yang dikirim ke client sehingga dapat digunakan untuk Mengontrol format output JSON, Menyembunyikan field sensitive, Menambahkan field computed dan Membuat response yang konsisten.

php artisan make:resource ProductResource

Kodenya akan terlihat seperti di bawah

404: Not Found

Error Handling

Pertama-tama, kita buat validasi request untuk metode store dan update dari API.

php artisan make:request StoreProductRequest

Kodenya terlihat seperi di bawah

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreProductRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'name' => 'required|string|max:255',
            'description' => 'required|string',
            'price' => 'required|numeric|min:0',
            'stock' => 'required|integer|min:0'
        ];
    }

    public function messages()
    {
        return [
            'name.required' => 'Nama produk wajib diisi',
            'price.min' => 'Harga tidak boleh negatif'
        ];
    }
}

Kemudian, kita buat exceptionnya yang akan memberikan persan informatif terhadap hasil request yang dikirimkan pengguna.

<?php

namespace App\Exceptions;

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Validation\ValidationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Throwable;

class Handler extends ExceptionHandler
{
    /**
     * The list of the inputs that are never flashed to the session on validation exceptions.
     *
     * @var array<int, string>
     */
    protected $dontFlash = [
        'current_password',
        'password',
        'password_confirmation',
    ];

    /**
     * Register the exception handling callbacks for the application.
     */
    public function register(): void
    {
        $this->reportable(function (Throwable $e) {
            //
        });
    }

    /**
     * Render an exception into an HTTP response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Throwable  $exception
     * @return \Illuminate\Http\Response
     */
    public function render($request, Throwable $exception)
    {
        if ($request->wantsJson()) {
            if ($exception instanceof ValidationException) {
                return response()->json([
                    'status' => 'error',
                    'message' => 'Validation failed',
                    'errors' => $exception->errors()
                ], 422);
            }

            if ($exception instanceof ModelNotFoundException) {
                return response()->json([
                    'status' => 'error',
                    'message' => 'Resource not found'
                ], 404);
            }
        }

        return parent::render($request, $exception);
    }
}

Penulisan Ulang Kontroler

Metode index dan show ditulis ulang dengan mengembalikan resource dari produk dibandingkan membuat secara manual beserta verifikasi produk sudah ada. Untuk metode delete, tambahkan validasi produk sudah ada. Pada metode store dan update, ditambahkan validasi input yang benar berdasarkan validator input yang sudah dibuat. Kode fungsinya seperti di bawah ini:

<?php

namespace App\Http\Controllers;

use App\Http\Requests\StoreProductRequest;
use Illuminate\Http\Request;
use App\Models\Product;
use App\Http\Resources\ProductResource;
use Illuminate\Support\Facades\Validator;

class ProductController extends Controller
{
    public function index()
    {
        $products = Product::all();
        return ProductResource::collection($products);
    }

    public function show($id)
    {
        $product = Product::find($id);
        if (!$product) {

            return response()->json([
                'status' => 'error',
                'message' => 'Resource not found'
            ], 404);
        }
        return new ProductResource($product);
    }

    public function store(Request $request)
    {
        $storeProductRequest = new StoreProductRequest();
        $validator = Validator::make($request->all(), $storeProductRequest->rules(), $storeProductRequest->messages());
        if ($validator->fails()) {
            return response()->json([
                'message' => 'Validation failed.',
                'errors' => $validator->errors(),
            ], 422);
        }
        $validated = $validator->validated();
        $product = Product::create($validated);

        return response()->json([
            'status' => 'success',
            'message' => 'Product created successfully',
            'data' => $product
        ], 201);
    }



    public function update(Request $request, Product $product)
    {
        $storeProductRequest = new StoreProductRequest();

        $validator = Validator::make($request->all(), $storeProductRequest->rules(), $storeProductRequest->messages());
        if ($validator->fails()) {
            return response()->json([
                'message' => 'Validation failed.',
                'errors' => $validator->errors(),
            ], 422);
        }
        $validated = $validator->validated();

        $product->update($validated);

        return response()->json([
            'status' => 'success',
            'message' => 'Product updated successfully',
            'data' => $product
        ]);
    }

    public function destroy($id)
    {
        $product = Product::find($id);
        if (!$product) {

            return response()->json([
                'status' => 'error',
                'message' => 'Product not found'
            ], 404);
        }
        $product->delete();

        return response()->json([
            'status' => 'success',
            'message' => 'Product deleted successfully'
        ]);
    }
}

API yang kita buat telah jadi, sehingga dapat diketik perintah di bawah ini untuk menjalankan server

php artisan serve

Pengujian dengan Postman

Postman adalah aplikasi penguji API yang gratis dengan menguji endpoint spesifik dari route API kita. Kita akan melakukan pengujian blackbox dengan API yang sudah disusun dengan menguji tiap fungsi dan mencocokannya dengan hasil yang diharapkan.

Index

Method GET
URL http://localhost:8000/products
Penjelasan API dipanggil dengan metode GET pada /products untuk mengambil keseluruhan data berdasarkan fungsi index() dari kontroler.
Hasil yang Diharapkan API Akan mengambil keseluruhan data produk.
Header Accept: application/json
Content-Type: application/json
Status 200 OK
Hasil Respons

API mengambil keseluruhan data produk. Hasil sesuai dengan diharapkan.

Card image cap

Show

Method GET
URL http://localhost:8000/products/1
Penjelasan API dipanggil oleh pengguna dengan produk yang sudah ada di dalam database sehingga API akan mengeembalikan data dengan id yang sesual.
Hasil yang Diharapkan API mengirimkan data yang tepat dengan id.
Header Accept: application/json
Content-Type: application/json
Status 200 OK
Hasil Respons

API mengambil keseluruhan data produk. Hasil sesuai dengan diharapkan.

Card image cap
Method GET
URL http://localhost:8000/products/2
Penjelasan Pengguna memanggil produk yang tidak berada di dalam database sehingga fungsi show() melakukan fungsi fallbask dengan mengirimkan error 404 ke pengguna. Pada skenario ini, API dipanggil untuk memanggil produk yang tidak ada dalam database. ID dipilih "2" karena tidak ada produk yang memiliki ID 2.
Hasil yang Diharapkan API Akan mengirim error 404 ke pemanggil API
Header Accept: application/json
Content-Type: application/json
Status 404 NOT FOUND
Hasil Respons

Karena data tidak ditemukan, API berhasil mengirimkan pesan error ke pemanggilnya.

Card image cap

Store

Method POST
URL http://localhost:8000/products
Penjelasan Data yang diberikan sesuai dengan kriteria.
Hasil yang Diharapkan API akan menyimpan data ke database dan mengirimkan status kepada pengguna
Header Accept: application/json
Content-Type: application/json
Status 200 OK
Hasil Respons

API mengambil keseluruhan data produk. Hasil sesuai dengan diharapkan.

Card image cap
Method POST
URL http://localhost:8000/products
Penjelasan Input memiliki harga yang tidak sesuai dengan yang diminta, misalnya memasukkan harga string ke kolom yang hanya bertujuan untuk angka saja.
Hasil yang Diharapkan API Akan mengembalikan error yang sesuai dengan apa yang pengguna masukkan.
Header Accept: application/json
Content-Type: application/json
Status 422 UNPROCESSABLE CONTENT
Hasil Respons

API mengambil keseluruhan data produk. Hasil sesuai dengan diharapkan.

Card image cap

Update

Method PUT
URL http://localhost:8000/products
Penjelasan Pengguna akan mengubah data dengan memanggil API yang tersedia. Data yang dikirim pengguna tersebut telah tervalidasi.
Hasil yang Diharapkan API Akan mengubah data pengguna dengan data yang telah tervalidasi
Header Accept: application/json
Content-Type: application/json
Status 200 OK
Hasil Respons

API mengambil keseluruhan data produk. Hasil sesuai dengan diharapkan.

Card image cap
Method PUT
URL http://localhost:8000/products
Penjelasan Data yang diberikan oleh siswa tidak tervalidasi dengan baik.
Hasil yang Diharapkan Terdapat pesan error untuk semua orang di sini.
Header Accept: application/json
Content-Type: application/json
Status 422 UNPROCESSABLE CONTENT
Hasil Respons

API mengambil keseluruhan data produk. Hasil sesuai dengan diharapkan.

Card image cap

Delete

Method DELETE
URL http://localhost:8000/products/5
Penjelasan ID produk sesuai dengan database kita buat. Dalam kasus ini, "5" terdapat salah satu siswa mahasiswa.
Hasil yang Diharapkan API mengirimkan pesan rahasiswas kepada user
Header Accept: application/json
Content-Type: application/json
Status 422 UNPROCESSABLE CONTENT
Hasil Respons

API mengambil keseluruhan data produk. Hasil sesuai dengan diharapkan.

Card image cap Card image cap

Kesimpulan

API adalah konsep yang menjebatani frontend dan backend dan bertugas untuk mengirim data antar dua bagian tersebut. REST (Representational State Transfer) adalah arsitektur untuk merancang web services. REST bukan protokol atau standar, melainkan seperangkat prinsip desain yang meminimalisir perubahan state aplikasi. Dalam blog ini, kita telah menyusun API CRUD sederhana yang telah divalidasi.

Document