Skip to content

Instantly share code, notes, and snippets.

@AmoahDevLabs
Created August 10, 2025 12:14
Show Gist options
  • Save AmoahDevLabs/6c4e52119bc8c3ac9399906a31640a8e to your computer and use it in GitHub Desktop.
Save AmoahDevLabs/6c4e52119bc8c3ac9399906a31640a8e to your computer and use it in GitHub Desktop.
Nuxt.js Composables; from messy to Optimization.
// Before and after optimization
// Before
import { useAuthStore } from "@/stores/auth";
export const getAuthHeaders = async () => {
const authStore = useAuthStore();
if (!authStore.hydrated) {
authStore.init();
}
await authStore.validateAndRefreshToken();
if (!authStore.accessToken) {
throw new Error("No access token available. Please log in again.");
}
return { Authorization: `Bearer ${authStore.accessToken}` };
};
// After
// useAuthHeaders.ts
import { useAuthStore } from "@/stores/auth";
export const getAuthHeaders = async () => {
const authStore = useAuthStore();
if (!authStore.hydrated) {
authStore.init();
}
await authStore.validateAndRefreshToken();
if (!authStore.accessToken) {
throw new Error("No access token available. Please log in again.");
}
return { Authorization: `Bearer ${authStore.accessToken}` };
};
// useApiRequest.ts
// composables/useApiRequest.ts
import { ref } from "vue";
import { getAuthHeaders } from "@/composables/useAuthHeaders";
export function useApiRequest() {
const loading = ref(false);
const error = ref<string | null>(null);
const apiRequest = async <T>(url: string, options: any = {}): Promise<T> => {
loading.value = true;
error.value = null;
try {
return await $fetch<T>(url, {
headers: await getAuthHeaders(),
...options,
});
} catch (err) {
error.value = err instanceof Error ? err.message : String(err);
console.error("API error:", err);
throw err;
} finally {
loading.value = false;
}
};
return {
apiRequest,
loading,
error,
};
}
// Finally: Optimized useGuests.ts
// composables/useGuests.ts
import { ref, computed } from "vue";
import type { Ref } from "vue";
import { getFullName } from "~/utils/names";
import { useApiRequest } from "~/composables/useApiRequest";
interface Guest {
id: string;
first_name: string;
last_name: string;
other_name?: string;
sex: string;
address?: string;
city?: string;
date_of_birth?: string;
id_type?: string;
id_number?: string;
phone_number: string;
email?: string;
contact_name?: string;
contact_phone?: string;
}
export function useGuests() {
const config = useRuntimeConfig();
const apiBase = config.public.apiBase;
// Use the centralized API composable
const { apiRequest, loading, error } = useApiRequest();
const guests: Ref<Guest[]> = ref([]);
const guest: Ref<Guest | null> = ref(null);
const getGuests = async () => {
guests.value = await apiRequest<Guest[]>(`${apiBase}/api/guests/`);
};
const getGuest = async (id: string) => {
guest.value = await apiRequest<Guest>(`${apiBase}/api/guests/${id}/`);
};
const createGuest = async (payload: Partial<Guest>) => {
return apiRequest<Guest>(`${apiBase}/api/guests/`, {
method: "POST",
body: payload,
});
};
const updateGuest = async (id: string, payload: Partial<Guest>) => {
return apiRequest<Guest>(`${apiBase}/api/guests/${id}/`, {
method: "PATCH",
body: payload,
});
};
const deleteGuest = async (id: string) => {
await apiRequest<void>(`${apiBase}/api/guests/${id}/`, {
method: "DELETE",
});
};
const guestFullName = computed(() =>
guest.value ? getFullName(guest.value) : ""
);
const guestsWithFullNames = computed(() =>
guests.value.map((g) => ({
...g,
fullName: getFullName(g),
}))
);
return {
guests,
guest,
loading,
error,
guestFullName,
guestsWithFullNames,
getGuests,
getGuest,
createGuest,
updateGuest,
deleteGuest,
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment