This document provides an in-depth overview of the architecture patterns used in this Nuxt 3 starter template.
The template implements a clean service layer architecture that separates API communication from UI components.
Services handle all API communication and are designed as factory functions that receive dependencies (axios, logger).
Example: crudService.ts
export default ($axios: any, resource: string, logger: any) => ({
async fetchAll() {
try {
const response = await $axios.get(`/${resource}`);
return response;
} catch (error) {
logger.error("fetchError", resource);
throw error;
}
},
// ... other methods
});
Services create a contract that can be implemented by either real API services or mocks:
Composables provide a reactive layer over services using Vue’s Composition API:
Example: useCrud.ts
export function useCrud(resource: string) {
const items = ref([]);
const item = ref([]);
const { $api }: any = useNuxtApp();
const model = $api[`${resource}`];
const fetchItems = async () => {
const { data } = await model.fetchAll();
items.value = data.items;
};
// ... other methods
return {
items,
item,
fetchItems,
// ... other methods
};
}
Plugins wire everything together:
Pinia stores manage global state:
The typical data flow in this architecture is:
useCrud('posts').fetchItems())$apiThe mock API mirrors the real API structure:
The directory structure follows Nuxt conventions with additional organization for better maintainability:
composables/: Shared reactive logic
services/: API service modules
schemas/: Validation schemas using Yup
Configuration is managed through Nuxt’s runtime config system in nuxt.config.ts:
runtimeConfig: {
public: {
apiBase: process.env.API_BASE || 'http://localhost:3000/api',
useMockApi: process.env.USE_MOCK_API === 'true' || true,
}
}
This allows for environment-specific settings.