
이번에 맡게 된 관리자용 대시보드 프로젝트에서 서버가 준비되지 않은 상황이라, 서버리스 함수랑 Faker 라이브러리를 사용해 Mock 데이터를 만들어봤다. 서버가 아직 연동되지 않은 상황에서 프론트엔드 작업을 진행하려다 보니 임시 데이터가 필요했는데, 이 방법이 꽤 유용했다. 실제로 서버가 완전히 구현되기 전에 데이터 구조를 맞춰두고, 기능 테스트를 할 수 있어서 개발 속도가 꽤 빨라진 것 같다.
Nuxt 프로젝트에서는 서버리스 함수 파일을 server/api 디렉토리에 넣고, 타입 정의 파일은 types 폴더에 정리해두는 식으로 구성했다. 이번 작업의 디렉토리 구조는 아래와 같았다.
📁 project-root
├── 📁 server
│ └── 📁 api
│ └── 📄 products.ts
├── 📁 types
│ └── 📄 product.ts
├── 📄 nuxt.config.ts
└── 📄 package.json
Mock 데이터를 생성하기 위해 @faker-js/faker를 사용했는데, 설치는 간단했다.
yarn add @faker-js/faker
타입스크립트를 사용하다 보니, 데이터 구조를 미리 정의해두는 게 편리했다.
export interface ProductData {
id: number;
name: string;
description: string;
price: number;
imageUrl: string;
category: string;
rating: number;
stock: number;
lastUpdated: string;
}
서버리스 함수에서 Faker를 사용해 더미 데이터를 생성하는 부분을 구현했다. 이 방식으로 실제 서버가 없더라도 데이터 기반 기능들을 미리 테스트할 수 있었다.
import { faker } from '@faker-js/faker';
import { defineEventHandler } from 'h3';
import type { ProductData } from '~/types/product';
export default defineEventHandler((event) => {
const id = Number(event.context.params?.id);
if (!id || isNaN(id)) {
return {
code: 400,
message: '유효하지 않은 제품 ID',
};
}
const productData = generateProductData(id);
return { data: productData };
});
const generateProductData = (id: number): ProductData => ({
id,
name: faker.commerce.productName(),
description: faker.commerce.productDescription(),
price: parseFloat(faker.commerce.price({ min: 10, max: 1000 })),
imageUrl: faker.image.urlPicsumPhotos(),
category: faker.helpers.arrayElement(['Electronics', 'Fashion', 'Home', 'Sports']),
rating: faker.number.float({ min: 1, max: 5, precision: 0.1 }),
stock: faker.number.int({ min: 0, max: 100 }),
lastUpdated: faker.date.recent().toISOString(),
});
서버를 띄운 후, http://localhost:3000/api/products/1로 접근해서 Mock 데이터를 확인해보니, 더미 데이터가 제대로 생성되었다. 실제 API 요청처럼 동작해서 프론트엔드 개발을 빠르게 진행할 수 있었다.
{
"data": {
"id": 1,
"name": "Stylish Leather Wallet",
"description": "편리한 사용감을 자랑하는 가죽 지갑.",
"price": 79.99,
"imageUrl": "https://picsum.photos/200",
"category": "Fashion",
"rating": 4.2,
"stock": 20,
"lastUpdated": "2024-11-12T12:00:00.000Z"
}
}
이제 대시보드 페이지에서 Nuxt의 useFetch를 활용해 서버리스 함수로부터 데이터를 가져오는 예제를 작성해보자.
<template>
<div class="dashboard">
<h1>관리자 대시보드</h1>
<div v-if="loading">로딩 중...</div>
<div v-else-if="error">에러 발생: {{ error.message }}</div>
<div v-else>
<div v-for="product in products" :key="product.id" class="product-card">
<img :src="product.imageUrl" alt="Product Image" />
<h2>{{ product.name }}</h2>
<p>{{ product.description }}</p>
<p>가격: ${{ product.price }}</p>
<p>카테고리: {{ product.category }}</p>
<p>평점: {{ product.rating }} / 5</p>
<p>재고 수량: {{ product.stock }}</p>
<p>마지막 업데이트: {{ product.lastUpdated }}</p>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
interface ProductData {
id: number;
name: string;
description: string;
price: number;
imageUrl: string;
category: string;
rating: number;
stock: number;
lastUpdated: string;
}
const products = ref<ProductData[]>([]);
const loading = ref(true);
const error = ref<Error | null>(null);
const fetchProducts = async () => {
try {
const { data } = await useFetch('/api/products/1');
if (data.value) {
products.value = [data.value.data]; // Mock 데이터가 하나만 있기 때문에 배열로 감싸기
}
} catch (err) {
error.value = err as Error;
} finally {
loading.value = false;
}
};
onMounted(() => {
fetchProducts();
});
</script>
이번 작업에서 서버리스 함수와 Faker를 활용해 Mock 데이터를 생성하고, 프론트엔드 대시보드에서 이를 불러오는 방식까지 구현해봤다. 서버가 아직 준비되지 않은 상황에서도 필요한 데이터를 기반으로 UI를 빠르게 구성할 수 있어서 효율적인 개발이 가능했다.
다만, useFetch를 사용하면서 정적 키 문제 때문에 캐시나 중복 요청 방지 측면에서 한계를 느꼈다. Nuxt의 기본 기능이 단순한 경우에는 충분히 유용하지만, 동적인 상황에서 더 복잡한 요구사항이 필요하다면 TanStack Query를 사용하는 것이 더 나은 선택이라고 판단하여 이후에는 TanStack Query를 적극적으로 도입해볼 계획이다.🚀