Data fetching
One of Nuxt 3 key features is the ability to seamlessly integrate data from various sources, making it easy to handle asynchronous data fetching and provide a consistent API for working with data.
Setting up a reusable data integration structure via the composable folder.
The composables folder is used to store reusable functions in a Nuxt 3 project. These functions provide shared logic that can be accessed globally without needing to import them manually in every file.
The process of integrating data into a Nuxt 3 application using a custom composable approach involves handling errors, managing endpoints and API requests.
Example Structure
// composables/api.js
import { ref } from 'vue'
import { useUserDetailsStore } from '@/store/userDetailsStore'
import { storeToRefs, createPinia } from 'pinia'
const pinia = createPinia();
const userDetailsStore = useUserDetailsStore(pinia);
const { token } = storeToRefs(userDetailsStore);
export function useApiRequest() {
const runtimeConfig = useRuntimeConfig()
const baseURL = runtimeConfig.public.BASE_URL
const sendRequest = async (params) => {
const {
method = 'GET', // HTTP method, default to 'GET'
endpoint, // API endpoint
data = null, // Data for POST, PUT, PATCH requests
queryParams = {},// Query parameters
customOptions = {}, // Additional options (e.g., headers)
id = null // Optional ID to append to the URL
} = params;
const { handleError } = useErrorHandler()
const queryString = new URLSearchParams(queryParams).toString()
let url;
if (endpoints[endpoint]) {
url =
baseURL + endpoints[endpoint] + (id ? `/${id}` : '') + (queryString ? `?${queryString}` : "");
} else {
url = baseURL + endpoint + (queryString ? `?${queryString}` : "");
}
const headers = {
Authorization: `Bearer ${token.value}`,
'Content-Type': 'application/json',
...customOptions.headers,
}
const requestOptions = {
method,
headers,
...customOptions,
}
// If it's not a GET request and data exists
if (method !== 'GET' && data) {
// Check if data is an instance of FormData
if (data instanceof FormData) {
// Let the browser automatically handle Content-Type for FormData
delete requestOptions.headers['Content-Type'];
requestOptions.body = data;
} else {
// If it's not FormData, handle it as JSON
requestOptions.body = JSON.stringify(data);
}
}
try {
const response = await useFetch(url, requestOptions)
if (response.error.value) {
throw response.error.value.data
}
return response.data.value
} catch (err) {
await handleError(err)
throw err
}
}
return { sendRequest }
}
Functions
useApiRequest: Initializes the API request function.- Parameters:
params: An object containing the request details.method(string): HTTP method (default is 'GET').endpoint(string): API endpoint.data(object|null): Data for POST, PUT, PATCH requests.queryParams(object): Query parameters.customOptions(object): Additional options (e.g., headers).id(string|null): Optional ID to append to the URL.
- Returns: An object containing the
sendRequestfunction.
- Parameters:
sendRequest: Sends an API request based on the provided parameters.- Parameters:
- Returns: The response data.
- Throws: An error if the request fails.
Example Usage Structure
import { ref } from 'vue'
const { handleError } = useErrorHandler();
const { sendRequest } = useApiRequest();
const errors = ref({});
const useApiStructure = async () => {
isLoading.value = true;
try {
const Data = {};
const queryParams = {};
const Params = {
method: "",
endpoint: "",
data: ,
queryParams: queryParams
}
const { data } = await sendRequest(Params);
} catch (err) {
handleError(err); // Call the error handler
} finally {
isLoading.value = false; // Stop loading
}
};