Untuk menjaga Laravel: Kontrak API Stabil, konsistenkan skema request/response, pastikan setiap akses tervalidasi oleh token otentikasi, dan tangani retry dengan header idempotensi. Dengan pendekatan ini, klien publik dapat mengandalkan perilaku API meskipun terjadi gangguan jaringan atau proses downstream.

Lalu, gabungkan middleware keamanan, logging, dan rollback agar kegagalan downstream tidak merusak keadaan sistem. Artikel ini menjelaskan langkah teknis untuk menetapkan kontrak, menegakkan autentikasi, menerapkan retry pintar, dan mengawasi eksekusi secara menyeluruh.

Menetapkan Kontrak Request/Response yang Konsisten

Kontrak API dimulai dari definisi skema yang tetap. Gunakan Laravel Form Request untuk memvalidasi input dan Resource untuk merapikan output. Contoh berikut menunjukkan validasi payload pengiriman data pesanan.

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreOrderRequest extends FormRequest
{
    public function rules()
    {
        return [
            'customer_id' => ['required', 'uuid'],
            'items' => ['required', 'array', 'min:1'],
            'items.*.sku' => ['required', 'string'],
            'items.*.quantity' => ['required', 'integer', 'min:1'],
            'metadata' => ['sometimes', 'array'],
        ];
    }
}

Gunakan Http\Resources untuk memastikan response tidak bocor informasi internal, misalnya hanya menampilkan status transaksi dan ID.

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class OrderResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'order_id' => $this->id,
            'status' => $this->status,
            'processed_at' => $this->processed_at?->toIso8601String(),
            'total' => $this->total_amount,
        ];
    }
}

Selalu dokumentasikan skema ini (misalnya OpenAPI/Swagger) agar tim klien tahu format persis yang diharapkan.

Otentikasi Token dan Verifikasi

Untuk API publik, otentikasi token mencegah permintaan tidak berizin. Laravel menyediakan sanctum atau passport, tapi hal terpenting adalah menjaga format token dan scopenya konsisten.

Implementasikan middleware yang memeriksa keberadaan token di header Authorization: Bearer {token}, kemudian verifikasi terhadap tabel token. Berikut cara sederhana untuk middleware khusus API stabil:

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class EnsureApiTokenIsValid
{
    public function handle(Request $request, Closure $next): Response
    {
        $token = $request->bearerToken();

        if (! $token || ! auth()->guard('api')->setToken($token)->check()) {
            return response()->json(['message' => 'Token tidak valid'], 401);
        }

        // Tambahkan informasi klien untuk logging
        $request->attributes->set('client_id', auth()->guard('api')->user()->client_id);

        return $next($request);
    }
}

Pastikan token dilindungi menggunakan TLS, dan jangan kirimkan token melalui query string. Gunakan scope/read-only bila memungkinkan untuk membatasi dampak kesalahan.

Implementasi Header Idempotensi dan Retry Pintar

Retry yang tidak terkontrol bisa menyebabkan duplikasi. Header idempotensi, misalnya Idempotency-Key, memberi tahu server bahwa permintaan tertentu harus diproses sekali saja.

Langkah teknis:

  • Simpan Idempotency-Key bersama payload yang diproses.
  • Jika permintaan datang lagi dengan header sama, kembalikan response sebelumnya tanpa memicu perubahan state.

Contoh implementasi sederhana menggunakan table idempotency_keys:

public function handle(Request $request, Closure $next)
{
    $key = $request->header('Idempotency-Key');

    if (! $key) {
        return response()->json(['message' => 'Idempotency-Key diperlukan'], 400);
    }

    $record = IdempotencyKey::firstOrCreate(
        ['key' => $key, 'client_id' => $request->attributes->get('client_id')],
        ['response_body' => null, 'status_code' => null]
    );

    if ($record->response_body) {
        return response()->json(json_decode($record->response_body, true), $record->status_code);
    }

    $response = $next($request);

    $record->response_body = $response->getContent();
    $record->status_code = $response->getStatusCode();
    $record->save();

    return $response;
}

Untuk retry pintar, integrasikan queue/backoff agar permintaan yang gagal otomatis dicoba ulang tanpa membebani klien. Misalnya, jika downstream operator pembayaran mengembalikan 500, luangkan queue job dengan retryUntil() dan backoff() agar permintaan tidak langsung diproses ulang tanpa jeda.

Middleware dan Observer untuk Keamanan, Logging, Rollback

Gabungkan keamanan, logging, dan rollback secara operasional:

  • Security Middleware: Validasi token, enforce HTTPS, batasi ukuran payload.
  • Logging Middleware: Rekam request-id, client-id, durasi, serta payload (tanpa data sensitif).
  • Observer/Transaction: Gunakan DB::transaction untuk menjamin rollback saat downstream gagal.

Contoh pattern middleware chaining:

public function handle(Request $request, Closure $next)
{
    $requestId = Str::uuid();
    Log::info('API request', ['id' => $requestId, 'path' => $request->path()]);

    return DB::transaction(function () use ($request, $next, $requestId) {
        $response = $next($request);

        Log::info('API response', ['id' => $requestId, 'status' => $response->status()]);

        return $response;
    });
}

Jika downstream seperti pengiriman email atau notifikasi gagal, tangkap exception dan rollback transaksi. Kemudian gunakan event observer untuk mencatat kesalahan dan memicu retry melalui queue, bukan mengembalikan error mentah ke klien.

Monitoring, Debugging, dan Trade-off

Pastikan pipeline monitoring mencatat header idempotensi dan sumber retry. Jika retry terus gagal, pertimbangkan circuit breaker untuk mencegah beban berlebih.

Catatan penting:

  • Trade-off: Simpanan idempotensi memperbesar tabel, perlu pembersihan berkala.
  • Kesalahan umum: Mengabaikan perbedaan body saat header sama—jangan hanya andalkan kemiripan request.
  • Debugging: Gunakan log request-id dan kirim ke klien agar dapat menautkan ulang ke kejadian di server.

Dengan menggabungkan kontrak skema, token otentikasi, header idempotensi, retry pintar, serta middleware observer untuk keamanan dan rollback, Anda dapat menjaga kontrak API stabil sekaligus memberi klien pengalaman yang dapat diandalkan.