Cara Memanggil API di Vue JS
Desain alternatif untuk menggunakan API dan tiruan pada project Vue
Memanggil API bisa membosankan dalam pengembangan web. Blok kode dapat diulang saat memanggil API yang ditentukan pengguna dari komponen yang berbeda. Dalam kasus seperti itu, Anda mungkin mengimport fungsi yang sama atau menulis URL beberapa kali.
Vue.js memungkinkan pengembang untuk menggunakan plugin yang ditentukan pengguna. Plugin dapat ineject properti ke semua instance Vue. Dalam contoh ini, kita akan menginjeksi properti $api
ke semua instance Vue dan memanggil API melalui properti $api
. Sebelum itu, pertimbangkan cara lain untuk memanggil API.
Memanggil API secara langsung
API dapat dipanggil secara langsung menggunakan API pengambilan browser (atau dengan Axios ). Kelemahan menggunakan API dengan cara ini adalah Anda harus menulis ulang URL yang sama setiap kali Anda perlu memanggil API yang sama. Jika URL berubah, Anda harus mengubahnya di komponen apa pun yang melakukan panggilan secara internal.
//FetchCall.vue
<template>
<div></div>
</template>
<script>
export default {
name: "FetchCall",
async mounted() {
const id = 1
const result = await fetch(`https://swapi.dev/api/people/${id}`).then((response) =>
response.json()
);
console.log(result)
}
}
</script>
Memanggil API melalui fetch API browser
Pengujian Anda harus mengambil tiruan pada objek global dan menulis implementasi tiruan sebelum memanggilnya, atau memodifikasi nilai yang dikembalikan.
//FetchCall.spec.js
import {shallowMount} from '@vue/test-utils'
import FetchCall from "../FetchCall";
describe('FetchCall.vue', () => {
it('should mount component successfully', () => {
global.fetch = jest.fn().mockResolvedValue({
json: () => Promise.resolve({name: "Luke Skywalker"}),
})
const wrapper = shallowMount(FetchCall)
// If you need to change return value after mounting the component
global.fetch.mockResolvedValue({
json: () => Promise.resolve({name: "Dart Wader"}),
})
expect(wrapper.exists()).toBeTruthy()
})
})
Mocking Pemanggilan API dari Browser
Wrapping panggilan API dalam fungsi
Alternatif yang lebih baik adalah membuat panggilan API dalam suatu fungsi dan menerima variabel yang diperlukan oleh panggilan sebagai parameter. Dalam contoh ini, saya membuat file js untuk setiap resource REST dan meletakkannya di folder client.
vue-api-call/
├─ src/
│ ├─ clients/
│ │ ├─ people.js
│ │ ├─ planets.js
Saya memindahkan panggilan semua ke suatu fungsi dan mengambil id sebagai parameter seperti yang ditunjukkan di bawah ini.
//people.js
export function getCharacter(id) {
return fetch(`https://swapi.dev/api/people/${id}`).then((response) =>
response.json()
);
}
fungsi untuk memanggil API
Untuk membuat panggilan di komponen Anda, Anda perlu mengimport dan memanggil fungsi seperti yang ditunjukkan di bawah ini. Keuntungan dari implementasi ini adalah menyediakan beberapa abstraksi tanpa mengulang kode dalam panggilan API.
//FunctionCall.vue
<template>
<div></div>
</template>
<script>
import {getCharacter} from "../clients/people"
export default {
name: "FunctionCall",
async mounted() {
const result = await getCharacter(1);
console.log(result)
}
}
</script>
Pemanggillan Api via Fugsi
bagaimana dengan tesnya? Dalam pengujian saya, saya mengimport fungsi dari file lain di file vue saya, jadi saya perlu meniru import. Jika pengujian Anda perlu mengubah nilai pengembalian. Misalnya, Anda juga harus mengimport fungsi ke file pengujian Anda dan tiruan nilai pengembaliannya.
//FunctionCall.spec.js
import {shallowMount} from '@vue/test-utils'
import FunctionCall from "../FunctionCall";
import {getCharacter} from "../../clients/people"
// To mock imports in a file
jest.mock('../../clients/people', () => ({
getCharacter: jest.fn().mockResolvedValue({name: "Luke Skywalker"})
}))
describe('FunctionCall.vue', () => {
it('should mount component successfully', async () => {
const wrapper = shallowMount(FunctionCall)
// If you need to change return value after mounting the component
// You have to import the function to change returned value as shown below
getCharacter.mockResolvedValue({name: "Dart Wader"})
expect(wrapper.exists()).toBeTruthy()
})
})
Tiruan import dan mengubah return value
Katakanlah Anda memiliki 5 atau 10 fungsi berbeda untuk ditiru dalam file pengujian Anda. Dalam hal ini, fungsi import dan import tiruan membutuhkan banyak kode.
Inject fungsi ke semua instance Vue melalui plugin
Untuk menghilangkan tiruan dan import di kedua komponen dan pengujian Vue, saya sarankan membuat plugin dan inject fungsi ke setiap komponen Vue melalui properti. Dalam contoh ini, plugin berikut inject properti $api
ke semua instance Vue. Berkat plugin ini, setiap instance Vue dapat mengakses semua fungsi di bawah direktori klien tanpa impor apa pun.
//api.js
import * as peopleClient from "../clients/people";
import * as planetClient from "../clients/planets";
export default {
install(Vue) {
Vue.prototype.$api = {
...peopleClient,
...planetClient
};
}
};
injeksi dari fungsi dibawah direktori client untuk plugin
//main.js
import Vue from 'vue'
import App from './App.vue'
import apiPlugin from "./plugins/api";
Vue.config.productionTip = false
Vue.use(apiPlugin);
new Vue({
render: h => h(App),
}).$mount('#app')
Injeksi dari plugin
Metode getCharacter sekarang dengan mudah dipanggil pada properti $api
.
//pluginCall.vue
<template>
<div></div>
</template>
<script>
export default {
name: "PluginCall",
async mounted() {
const result = await this.$api.getCharacter(1);
console.log(result)
}
}
</script>
Memanggil Api via Plugin
Anda tidak perlu lagi meniru fungsi import atau import dalam pengujian. Anda dapat meniru properti $api
seperti yang ditunjukkan di bawah ini.
//plugin.spec.js
import {shallowMount} from '@vue/test-utils'
import PluginCall from "../PluginCall";
describe('PluginCall.vue', () => {
it('should mount component successfully', async () => {
const wrapper = shallowMount(PluginCall, {
mocks: {
$api: {
getCharacter: jest.fn().mockResolvedValue({name: "Luke Skywalker"})
}
}
})
// If you need to change return value after mounting the component
wrapper.vm.$api.getCharacter.mockResolvedValue({name: "Dart Wader"})
expect(wrapper.exists()).toBeTruthy()
})
})
Meniru properi dari vue Instance
keuntungan
abstraksi
Dengan cara ini Anda dapat menyembunyikan implementasi panggilan API. Komponen Vue tidak tahu bagaimana API dipanggil, URL permintaan yang dikirim, atau library yang digunakan. Selain itu, Anda dapat mengembalikan data dummy dari fungsi Anda jika Anda memiliki data tetap atau backend Anda belum siap.
//planets.js
const dummyPlanet = {
name: "Tatooine"
};
export function getPlanet(id) {
return Promise.resolve(dummyPlanet);
}
lebih sedikit refactoring pada perubahan
Jika URL atau return tipe dari API berubah, Anda tidak perlu mengubah kode komponen Vue Anda. Cukup dengan mengubah fungsi di bawah direktori clien.
Lebih sedikit import dan tiruan dalam pengujian
Tidak perlu mengimport fungsi atau impor tiruan dalam pengujian
Peningkatan
Fungsi dalam plugin Vue dapat diproses terlebih dahulu sebelum diinjeksi. Misalnya, jika Anda ingin memanggil Vuex store sebelum atau sesudah panggilan, Anda dapat meneruskan URL dasar sebagai argumen ke fungsi atau mencegat panggilan fungsi.
Implementasi ini dapat diubah menjadi plugin pihak ke-3 yang secara otomatis melakukan import dari fungsionalitas folder. Jadi dalam hal ini pengguna tidak perlu mengganti plugin setiap kali ada resource baru.