
DAO stands for Data Access Object. It’s a design pattern used to separate the data persistence logic (API calls or database interactions) from business logic or UI logic.
In the early stages of the project, we found that the Vue components were mixed with a lot of API request logic, which made the code difficult to test and maintain. In order to improve the clarity of the architecture, we decided to introduce the DAO design pattern to independently encapsulate the data acquisition logic and lay a good foundation for the entire front-end project.
Design principles of DAO in Vue
Single Responsibility Principle
The DAO (Data Access Object) is solely responsible for handling data requests (e.g., axios calls). It should not contain any business logic or component-specific logic.Abstract and Unified Interface
All requests related to a specific type of resource (e.g., users, products) should be centralized in a single module, providing standardized method names and parameter structures.Decoupled from Components
Vue components should only call the methods provided by the DAO layer and should not use request tools like axios directly.Testability and Reusability
The DAO layer can be independently unit tested and reused across multiple components.Unified Error Handling Support
The DAO can include common error handling or wrap response structures in a consistent way.
Implementing DAO
1. Create DAO module
import axios from "axios";
export async function getCityInfoById(id: number) {
const response = await axios.get("/GetCurrentWeatherByCity/", {
params: {
id: id,
},
});
return response.data;
}
2. Call in Vue component
import { getCityInfoById } from "@/dao/weatherDao";
onMounted(async () => {
hotCityList.value = await getAllHotCityInfo();
const result: any[] = [];
console.log(hotCityList);
for (const city of hotCityList.value) {
try {
const weather = await getCityInfoById(city.id); // Call DAO
result.push({ ...weather, cityname: city.cityname });
} catch (e) {
console.error(`Failed to get ${city.cityname} weather`, e);
}
}
hotCityWeatherList.value = result;
});
<div v-else class="grid-container">
<div
v-for="(city, index) in hotCityWeatherList"
:key="'hot-' + index"
class="weather-card"
@click="OnHotCityClick(city)"
>
<div class="city-header">
<h2>{{ city.cityname }}</h2>
<span class="temp">{{ city.temp }}℃</span>
</div>
<div class="condition">{{ city.simp_desc }}</div>
<div class="high-low">
H:{{ city.temp_max }} L:{{ city.temp_min }}
</div>
</div>
</div>
Some findings and thoughts
- DAO separation significantly improved component readability and maintainability.
- Testing became easier as API logic was isolated and mockable.
- Collaboration improved through clearly defined and reusable API interfaces.