Tutorial Laravel 12 API Next JS 15 dan Tailwind CSS #8 Membuat API Service

Belajar membangun aplikasi fullstack modern dengan backend Laravel 12 RESTful API, frontend Next.js, dan desain menggunakan Tailwind CSS. Tutorial ini membahas step-by-step mulai dari setup environment, pembuatan API, konsumsi API di Next.js, hingga integrasi UI responsif.

✅ Telah dilihat 315 kali

Rating: 5.00 ⭐

... 13 August 2025, 20:33

API Service

Pada pertemuan sebelumnya kita sudah membahas bagaimana membuat Helper API Global, yaitu sebuah fungsi yang bisa digunakan untuk melakukan komunikasi dengan backend agar kode kita lebih rapi dan konsisten.

Nah, sekarang kita akan melangkah lebih jauh. Kali ini kita akan membuat sebuah service khusus untuk resource "Product". Tujuannya adalah agar segala interaksi dengan API yang berhubungan dengan produk (misalnya mengambil daftar produk, menambahkan produk baru, menghapus produk, dan sebagainya) terkumpul dalam satu tempat yang terorganisir.

Langkah-langkahnya sebagai berikut:

  1. Buat folder baru bernama services Folder ini sebaiknya kita letakkan sejajar dengan folder app. Folder ini nantinya akan berisi berbagai service untuk resource lain juga (misalnya usersorders, dan sebagainya), sehingga strukturnya lebih modular.
  2. Tambahkan file products.ts di dalam folder services File ini akan berfungsi sebagai tempat kita menuliskan semua fungsi yang berkaitan dengan resource produk.

Jika kita gambarkan dalam bentuk hirarki folder, hasil akhirnya akan terlihat seperti berikut:

project-root/
│
├── app/
│   └── ...
│
├── lib/
│   └── api.ts
│
├── services/
│   └── products.ts
│
└── ...

Dengan struktur seperti ini, kode kita akan lebih mudah dipelihara. Setiap resource memiliki service-nya sendiri, dan semuanya bisa memanfaatkan helper API global yang sudah kita buat sebelumnya.

Silakan buka file products.ts kemudian masukkan kode berikut ini:

import { apiFetch } from "@/lib/api";

// Definisikan tipe Product sesuai API Laravel-mu
export interface Product {
  id: number;
  name: string;
  description?: string;
  price: number;
  stock: number;
  created_at?: string;
  updated_at?: string;
}

// Data untuk create/update
export type ProductPayload = Omit<Product, "id" | "created_at" | "updated_at">;

// List produk — ambil langsung array dari res.data
export const getProducts = async (): Promise<Product[]> => {
  const res = await apiFetch<{ status: boolean; message: string; data: Product[]; meta?: any }>("/products");
  return res.data;
};

// Detail produk — ambil res.data
export const getProduct = async (id: number): Promise<Product> => {
  const res = await apiFetch<{ status: boolean; message: string; data: Product }>(`/products/${id}`);
  return res.data;
};

// Create
export const createProduct = (data: ProductPayload) =>
  apiFetch<Product>("/products", {
    method: "POST",
    body: JSON.stringify(data),
  });

// Update
export const updateProduct = (id: number, data: ProductPayload) =>
  apiFetch<Product>(`/products/${id}`, {
    method: "PUT",
    body: JSON.stringify(data),
  });

// Delete
export const deleteProduct = (id: number) =>
  apiFetch<{ message: string }>(`/products/${id}`, {
    method: "DELETE",
  });

1. Import Helper API Global

import { apiFetch } from "@/lib/api";

Di sini kita mengimpor helper apiFetch yang sudah kita buat sebelumnya. Fungsi ini bertugas melakukan request HTTP (GET, POST, PUT, DELETE, dll.) ke backend (aravel API) dengan cara yang konsisten dan reusable.


2. Definisi Tipe Product

export interface Product {
  id: number;
  name: string;
  description?: string;
  price: number;
  stock: number;
  created_at?: string;
  updated_at?: string;
}

Bagian ini mendefinisikan interface Product. Fungsinya adalah untuk memberi tahu TypeScript bagaimana bentuk data produk yang dikembalikan dari API.

  • idnamepricestock → wajib ada.
  • descriptioncreated_atupdated_at → opsional (? artinya bisa ada, bisa tidak).

Dengan definisi ini, kita bisa menulis kode yang lebih aman karena TypeScript akan memberi peringatan kalau ada properti yang salah.


3. Tipe Payload untuk Create/Update

export type ProductPayload = Omit<Product, "id" | "created_at" | "updated_at">;

ProductPayload adalah tipe khusus untuk kebutuhan input data produk baru atau update produk.

  • Kita menghapus field idcreated_at, dan updated_at dari Product, karena saat create/update kita tidak perlu mengirimkan itu (ID biasanya auto increment, created_at & updated_at dikelola oleh database/Laravel).

4. Ambil List Produk

export const getProducts = async (): Promise<Product[]> => {
  const res = await apiFetch<{ status: boolean; message: string; data: Product[]; meta?: any }>("/products");
  return res.data;
};

Fungsi ini melakukan request GET /products ke backend.

  • apiFetch dipanggil dengan generic type { status, message, data, meta } → sesuai format respons API Laravel pada umumnya.
  • Hasilnya res.data adalah array Product[], dan itu yang dikembalikan.

5. Ambil Detail Produk

export const getProduct = async (id: number): Promise<Product> => {
  const res = await apiFetch<{ status: boolean; message: string; data: Product }>(`/products/${id}`);
  return res.data;
};

Fungsi ini request GET /products/{id}.

  • Parameter id dipakai untuk menentukan produk mana yang diambil.
  • Hasilnya adalah satu object Product.

6. Create Produk

export const createProduct = (data: ProductPayload) =>
  apiFetch<Product>("/products", {
    method: "POST",
    body: JSON.stringify(data),
  });

Fungsi ini request POST /products.

  • Body request diisi dengan ProductPayload (data produk tanpa id & timestamp).
  • Hasil response bertipe Product, yaitu data produk yang baru saja dibuat.

7. Update Produk

export const updateProduct = (id: number, data: ProductPayload) =>
  apiFetch<Product>(`/products/${id}`, {
    method: "PUT",
    body: JSON.stringify(data),
  });

Fungsi ini request PUT /products/{id}.

  • Dipakai untuk mengubah data produk tertentu.
  • id menentukan produk mana yang diupdate, data berisi informasi baru.

8. Hapus Produk

export const deleteProduct = (id: number) =>
  apiFetch<{ message: string }>(`/products/${id}`, {
    method: "DELETE",
  });

Fungsi ini request DELETE /products/{id}.

  • Menghapus produk berdasarkan ID.
  • Biasanya API akan merespons pesan sukses, misalnya { message: "Produk berhasil dihapus" }.

Kesimpulan

File ini bertugas sebagai Product Service → tempat semua fungsi CRUD produk dikumpulkan. Dengan pendekatan ini:

  • Kode jadi lebih modular (setiap resource punya service sendiri).
  • Reusable (semua fungsi pakai apiFetch).
  • Aman secara tipe (TypeScript memastikan data sesuai struktur Product).

🔥 Flash Sale


📜 Table Of Contents


📌 Daftar Episode


Daftar eBook