Pelajari cara membuat reusable API composable di Nuxt JS 4 dengan useFetch agar kode fetching lebih rapi, reusable, dan mudah dipelihara.
Cara Membuat Reusable API Composable di Nuxt JS 4
Setelah memahami cara mengambil data API menggunakan useFetch di Nuxt JS 4, langkah berikutnya adalah membuat kode API fetching yang lebih reusable.
Dalam aplikasi yang semakin besar, penggunaan useFetch secara langsung pada setiap halaman dapat menyebabkan kode yang sama ditulis berulang kali.
Misalnya beberapa halaman membutuhkan data artikel:
<script setup>
const config = useRuntimeConfig()
const { data, error, status } = await useFetch(
`${config.public.apiBase}/articles`
)
</script>Jika pola tersebut digunakan di banyak halaman, lama-kelamaan kode menjadi sulit dikelola.
Solusinya adalah membuat reusable composable.
Dengan composable, logic untuk mengambil data API dapat dipisahkan dari komponen sehingga dapat digunakan kembali di berbagai halaman atau komponen Nuxt JS 4.
Apa Itu Composable di Nuxt JS 4?
Composable adalah fungsi yang digunakan untuk mengenkapsulasi dan menggunakan kembali logic pada aplikasi Vue atau Nuxt.
Nuxt menyediakan folder khusus bernama:
composables/File yang berada di dalam folder tersebut dapat digunakan sebagai composable dalam aplikasi.
Contohnya:
composables/
└── useArticles.tsKemudian composable tersebut dapat digunakan dari halaman atau komponen:
<script setup>
const { data } = await useArticles()
</script>Pendekatan ini membuat komponen menjadi lebih sederhana karena logic API fetching tidak perlu ditulis berulang kali.
Mengapa Perlu Membuat Reusable API Composable?
Bayangkan sebuah aplikasi memiliki beberapa halaman:
Halaman daftar artikel
Halaman kategori artikel
Halaman pencarian artikel
Halaman detail artikel
Halaman artikel terbaru
Tanpa composable, masing-masing halaman mungkin memiliki logic seperti:
useFetch(...)beserta konfigurasi API, query parameter, error handling, dan transformasi response.
Jika terdapat perubahan pada endpoint API, Anda mungkin harus mengubah banyak file.
Dengan reusable composable, logic tersebut dapat dipusatkan pada satu tempat.
Keuntungannya antara lain:
Mengurangi duplikasi kode.
Mempermudah maintenance.
Membuat halaman lebih bersih.
Memudahkan perubahan endpoint API.
Memudahkan penggunaan ulang logic.
Membuat struktur aplikasi lebih scalable.
Membuat Composable useArticles
Sebagai contoh, kita akan membuat composable untuk mengambil daftar artikel.
Struktur project:
app/
├── components/
├── pages/
├── composables/
│ └── useArticles.ts
└── ...Pada composables/useArticles.ts:
export const useArticles = () => {
const config = useRuntimeConfig()
return useFetch(`${config.public.apiBase}/articles`)
}Sekarang composable dapat digunakan dari halaman.
Contohnya:
<script setup lang="ts">
const { data, error, status } = await useArticles()
</script>
<template>
<div v-if="status === 'pending'">
Memuat artikel...
</div>
<div v-else-if="error">
Gagal mengambil artikel.
</div>
<article
v-else
v-for="article in data?.data"
:key="article.id"
>
<h2>{{ article.title }}</h2>
</article>
</template>Sekarang halaman tidak perlu mengetahui bagaimana URL API dibentuk.
Halaman hanya perlu mengetahui bahwa useArticles() digunakan untuk mengambil data artikel.
Membuat Composable dengan Query Parameter
Reusable composable akan menjadi lebih berguna ketika dapat menerima parameter.
Misalnya API artikel memiliki fitur pencarian:
/api/articles?search=nuxtComposable dapat dibuat seperti berikut:
export const useArticles = (search?: MaybeRefOrGetter<string>) => {
const config = useRuntimeConfig()
return useFetch(`${config.public.apiBase}/articles`, {
query: {
search
}
})
}Kemudian digunakan:
<script setup lang="ts">
const search = ref('nuxt')
const { data, error, status } = await useArticles(search)
</script>Dengan pendekatan tersebut, composable tetap reusable karena nilai pencarian dapat diberikan dari halaman atau komponen yang menggunakannya.
Menggunakan Parameter untuk Pagination
Composable juga dapat menangani pagination.
Misalnya API memiliki parameter:
/api/articles?page=1&per_page=10Composable dapat dibuat:
interface ArticleOptions {
page?: MaybeRefOrGetter<number>
perPage?: MaybeRefOrGetter<number>
}
export const useArticles = (options: ArticleOptions = {}) => {
const config = useRuntimeConfig()
return useFetch(`${config.public.apiBase}/articles`, {
query: {
page: options.page,
per_page: options.perPage
}
})
}Kemudian:
<script setup lang="ts">
const page = ref(1)
const { data, error, status } = await useArticles({
page,
perPage: 10
})
</script>Ketika nilai page berubah, dependency reactive tersebut dapat digunakan oleh useFetch untuk memperbarui request.
Pendekatan seperti ini sangat berguna untuk halaman artikel, produk, pengguna, transaksi, dan berbagai resource lain yang menggunakan pagination.
Membuat Composable untuk Detail Artikel
Selain daftar artikel, kita juga dapat membuat composable khusus untuk mengambil detail berdasarkan slug.
Misalnya endpoint:
/api/articles/belajar-nuxt-js-4Buat file:
composables/
└── useArticle.tsKemudian:
export const useArticle = (
slug: MaybeRefOrGetter<string>
) => {
const config = useRuntimeConfig()
return useFetch(
() => `${config.public.apiBase}/articles/${toValue(slug)}`
)
}Composable tersebut dapat digunakan pada halaman detail:
<script setup lang="ts">
const route = useRoute()
const { data, error, status } = await useArticle(
() => String(route.params.slug)
)
</script>Kemudian template:
<template>
<div v-if="status === 'pending'">
Memuat artikel...
</div>
<div v-else-if="error">
Artikel tidak ditemukan.
</div>
<article v-else-if="data">
<h1>{{ data.data.title }}</h1>
<div v-html="data.data.content"></div>
</article>
</template>Dengan cara ini, logic pengambilan artikel berdasarkan slug tidak perlu ditulis ulang.
Memisahkan Logic API dengan Tampilan
Salah satu manfaat terbesar reusable composable adalah pemisahan tanggung jawab.
Tanpa composable, sebuah halaman dapat berisi:
Page
├── API URL
├── Query
├── Fetching
├── Error handling
├── Loading state
└── TemplateDengan composable:
Composable
├── API URL
├── Query
└── Fetching
Page
├── Menampilkan loading
├── Menampilkan error
└── Menampilkan dataKomponen menjadi lebih fokus pada presentation layer.
Sementara logic pengambilan data berada di composable.
Pendekatan ini sangat membantu ketika aplikasi mulai memiliki banyak halaman dan resource API.
Membuat Composable yang Lebih Fleksibel
Pada aplikasi yang lebih besar, sebaiknya composable tidak terlalu spesifik jika logic yang digunakan sebenarnya sama.
Misalnya daripada membuat banyak fungsi:
useArticles()
useProducts()
useUsers()
useCategories()untuk logic yang benar-benar identik, Anda dapat membuat abstraction tertentu sesuai kebutuhan.
Namun jangan terlalu cepat membuat generic composable.
Abstraction yang terlalu kompleks justru dapat membuat kode lebih sulit dipahami.
Contoh yang sederhana dan mudah dipelihara sering kali lebih baik:
export const useArticles = (
options: ArticleOptions = {}
) => {
const config = useRuntimeConfig()
return useFetch(`${config.public.apiBase}/articles`, {
query: {
search: options.search,
page: options.page,
per_page: options.perPage
}
})
}Pendekatan tersebut masih mudah dibaca sekaligus cukup fleksibel untuk kebutuhan aplikasi.
Menambahkan TypeScript pada API Response
Jika backend menggunakan response JSON yang konsisten, penggunaan TypeScript dapat membuat composable lebih aman.
Misalnya backend mengembalikan:
{
"data": [
{
"id": 1,
"title": "Belajar Nuxt JS 4"
}
]
}Buat interface:
interface Article {
id: number
title: string
}
interface ArticleResponse {
data: Article[]
}Kemudian gunakan generic pada useFetch:
export const useArticles = () => {
const config = useRuntimeConfig()
return useFetch<ArticleResponse>(
`${config.public.apiBase}/articles`
)
}Sekarang editor dapat membantu memberikan autocomplete dan mendeteksi kesalahan tipe data.
Contohnya:
<script setup lang="ts">
const { data } = await useArticles()
const articles = computed(() => data.value?.data ?? [])
</script>Penggunaan TypeScript semakin bermanfaat ketika struktur response API semakin kompleks.
Reusable Composable untuk API Laravel
Jika Nuxt JS 4 digunakan sebagai frontend dan Laravel sebagai backend API, struktur seperti berikut dapat digunakan:
Nuxt JS 4
│
├── pages/
├── components/
├── composables/
│ ├── useArticles.ts
│ ├── useArticle.ts
│ └── useCategories.ts
│
└── runtimeConfig
│
▼
Laravel API
│
├── /api/articles
├── /api/articles/{slug}
└── /api/categoriesBase URL Laravel dapat disimpan pada environment:
NUXT_PUBLIC_API_BASE=https://api.example.com/apiKemudian:
const config = useRuntimeConfig()digunakan oleh composable.
Dengan demikian, ketika domain API berubah antara development dan production, konfigurasi dapat diubah melalui environment tanpa mengubah setiap halaman.
Jangan Menaruh Semua Logic ke Dalam Satu Composable
Reusable bukan berarti semua API harus berada dalam satu file.
Hindari membuat:
composables/
└── useApi.tsyang berisi ratusan fungsi untuk seluruh resource aplikasi.
Struktur tersebut dapat menjadi sulit dipelihara ketika aplikasi berkembang.
Lebih baik mengelompokkan composable berdasarkan domain atau resource:
composables/
├── useArticles.ts
├── useArticle.ts
├── useCategories.ts
├── useProducts.ts
└── useUsers.tsDengan struktur tersebut, setiap composable memiliki tanggung jawab yang lebih jelas.
useFetch atau $fetch di Dalam Composable?
Pemilihan useFetch dan $fetch tetap bergantung pada kebutuhan.
Gunakan useFetch ketika composable digunakan untuk mengambil data yang menjadi bagian dari state halaman dan membutuhkan integrasi dengan lifecycle data fetching Nuxt.
Contohnya:
export const useArticles = () => {
const config = useRuntimeConfig()
return useFetch(`${config.public.apiBase}/articles`)
}Sedangkan $fetch lebih cocok untuk operasi langsung seperti:
export const createArticle = async (
payload: CreateArticlePayload
) => {
const config = useRuntimeConfig()
return $fetch(`${config.public.apiBase}/articles`, {
method: 'POST',
body: payload
})
}Contoh tersebut dapat digunakan ketika pengguna melakukan submit form.
Jangan menggunakan $fetch dan useFetch hanya karena salah satunya terlihat lebih sederhana. Pilih berdasarkan lifecycle dan kebutuhan data pada aplikasi.
Hal yang Perlu Diperhatikan Saat Membuat Composable
Ada beberapa prinsip yang sebaiknya diperhatikan.
1. Hindari Duplikasi Logic
Jika logic fetching yang sama digunakan pada beberapa halaman, pertimbangkan untuk memindahkannya ke composable.
2. Jangan Membuat Abstraction Berlebihan
Tidak semua API request membutuhkan generic composable.
Jika abstraction membuat kode lebih sulit dibaca, gunakan composable yang lebih spesifik.
3. Gunakan TypeScript
Untuk aplikasi berskala menengah hingga besar, typing pada request dan response dapat mengurangi error ketika struktur API berubah.
4. Pisahkan Data Layer dari UI
Composables dapat menjadi tempat yang baik untuk menempatkan logic data fetching sehingga halaman lebih fokus pada tampilan.
5. Perhatikan SSR
Composable yang menggunakan useFetch tetap perlu dirancang dengan mempertimbangkan SSR, terutama ketika endpoint membutuhkan authentication atau informasi khusus dari request pengguna.
6. Jangan Hardcode Environment
Base URL API sebaiknya tetap berasal dari runtimeConfig, bukan ditulis berulang kali pada setiap composable.
Kesimpulan
Reusable API composable merupakan langkah penting setelah memahami useFetch di Nuxt JS 4.
Dengan memindahkan logic API fetching ke composable, kode aplikasi menjadi lebih terstruktur dan lebih mudah digunakan kembali.
Beberapa hal penting yang perlu diingat:
Gunakan folder
composables/untuk reusable logic.Gunakan
useFetchuntuk data fetching yang terintegrasi dengan Nuxt.Gunakan parameter reactive untuk membuat composable lebih fleksibel.
Gunakan
runtimeConfiguntuk base URL API.Gunakan TypeScript untuk membantu menjaga konsistensi response API.
Pisahkan logic data fetching dari presentation layer.
Hindari abstraction yang terlalu kompleks.
Gunakan composable berdasarkan domain atau resource ketika aplikasi semakin besar.
Setelah memahami reusable API composable, tahap berikutnya adalah membuat API layer yang lebih terstruktur, misalnya memisahkan HTTP client, authentication, interceptor, error handling, dan endpoint API agar aplikasi Nuxt JS 4 tetap mudah dikembangkan ketika jumlah fitur semakin besar.
Baca juga artikel serupa :

