728x90

우리가 지금까지 만든 Nuxt 애플리케이션은 클라이언트(브라우저)에서 실행되는 프론트엔드 코드였습니다. 하지만 Nuxt는 Nitro 엔진 덕분에 자체적으로 서버 API를 구동할 수 있습니다. 이는 복잡한 백엔드 설정 없이도 사용자 인증, 데이터 유효성 검사 등 서버 로직을 Nuxt 프로젝트 내에서 처리할 수 있게 해줍니다.
이번 실습에서는 server/api/ 디렉토리를 사용하여 POST 요청을 받아 데이터를 처리하는 API 엔드포인트를 만들어 봅시다.
1. 🚀 Nuxt 서버 API의 특징
- 자동 라우팅: server/api/ 폴더 내에 파일을 만들면, 파일명에 따라 자동으로 /api/... 엔드포인트가 생성됩니다.
- 파일 기반 메소드 지정: 파일명에 .post, .get 등을 붙여 해당 HTTP 메소드만 처리하도록 지정할 수 있습니다. (예: user.post.ts는 POST 요청만 받음)
- H3 기반: Nuxt의 서버는 빠르고 가벼운 H3 프레임워크를 기반으로 하며, defineEventHandler를 사용하여 서버 함수를 정의합니다.
2. 👩💻 실습 1: POST 요청을 받는 서버 API 구축
가상의 사용자 정보를 등록(POST)하는 API를 만들어 봅시다.
2.1. POST API 파일 생성
- 프로젝트 루트의 server/api 폴더 안에 register.post.ts 파일을 생성합니다.
// server/api/register.post.ts // defineEventHandler를 사용하여 서버에서 실행될 함수를 정의합니다. export default defineEventHandler(async (event) => { // 1. readBody(event)를 사용하여 클라이언트가 전송한 POST 데이터를 가져옵니다. const body = await readBody(event) // 2. 데이터 유효성 검사: 이름과 이메일이 필수인지 체크합니다. if (!body.name || !body.email) { // 필수 필드가 누락되면, 에러 객체를 생성하여 클라이언트에 400 Bad Request 응답을 보냅니다. throw createError({ statusCode: 400, statusMessage: '이름(name)과 이메일(email)은 필수입니다.', }) } // 3. 가상의 데이터 저장 로직 (실제 DB 저장 로직이 들어갈 부분) const newUser = { id: Date.now(), name: body.name, email: body.email, status: 'registered', } // 4. 처리 결과를 JSON 형태로 클라이언트에 반환합니다. return { success: true, user: newUser, message: `${newUser.name} 님의 등록이 완료되었습니다.`, } })
2.2. 서버 확인
서버가 실행 중인 상태에서 (dev 모드), 외부 툴(Postman, Thunder Client 등)을 사용하여 POST 요청을 http://localhost:3000/api/register로 보내 테스트할 수 있습니다.
- 성공 시: Body에 { "name": "철수", "email": "chulsu@test.com" } 전송 시, 성공 응답이 반환됩니다.
- 실패 시: Body에 { "name": "영희" }만 전송 시, status: 400 에러와 함께 statusMessage가 반환됩니다.
3. 실습 2: 클라이언트 페이지에서 로컬 POST API 호출
이제 클라이언트 페이지를 만들어 사용자의 입력을 받아 방금 만든 서버 API로 데이터를 전송해 봅시다.
- 페이지 파일 생성: pages/signup.vue 파일을 생성합니다.
<template> <div> <AppHeader /> <h1>사용자 회원가입</h1> <form @submit.prevent="submitForm" style="display: flex; flex-direction: column; max-width: 300px;"> <input type="text" v-model="form.name" placeholder="이름" required style="margin-bottom: 10px; padding: 8px;"> <input type="email" v-model="form.email" placeholder="이메일" required style="margin-bottom: 10px; padding: 8px;"> <button type="submit" :disabled="isPending" style="padding: 10px; background-color: #3b82f6; color: white; border: none; cursor: pointer;"> {{ isPending ? '처리 중...' : '가입하기' }} </button> </form> <div v-if="successMsg" style="color: green; margin-top: 15px;"> ✅ {{ successMsg }} </div> <div v-if="errorMsg" style="color: red; margin-top: 15px;"> 🚨 {{ errorMsg }} </div> </div> </template> <script setup> const form = reactive({ name: '', email: '' }) const isPending = ref(false) const successMsg = ref('') const errorMsg = ref('') async function submitForm() { // 상태 초기화 isPending.value = true successMsg.value = '' errorMsg.value = '' try { // useFetch를 사용하여 로컬 API 엔드포인트에 POST 요청 const { data, error } = await useFetch('/api/register', { method: 'POST', body: form // reactive 객체를 body에 전달하면 Nuxt가 JSON으로 자동 변환 }) if (error.value) { // 서버에서 발생한 에러 메시지(400 Bad Request 등) 처리 errorMsg.value = error.value.statusMessage || '서버 오류 발생' } else if (data.value && data.value.success) { successMsg.value = data.value.message // 성공 후 폼 초기화 form.name = '' form.email = '' } } catch (e) { errorMsg.value = '알 수 없는 클라이언트 오류가 발생했습니다.' } finally { isPending.value = false } } </script>
결과 확인: http://localhost:3000/signup에 접속하여 이름과 이메일을 입력하고 가입 버튼을 눌러보세요. 성공 메시지가 뜨면 Nuxt의 서버 API가 클라이언트 요청을 성공적으로 처리한 것입니다.
📝 블로그 마무리: 풀스택 통합 개발 환경
이번 실습을 통해 Nuxt가 제공하는 클라이언트와 서버의 완벽한 통합을 경험했습니다. 별도의 서버 환경 구축 없이도 server/api 폴더를 사용하여 복잡한 서버 로직(데이터 유효성 검사, 저장 처리)을 구현할 수 있게 되었습니다.
728x90
'Nuxt.js 를 배워보자 > ⚙️ 3. Nuxt의 서버 사이드 기능 활용: 서버 API와 미들웨어' 카테고리의 다른 글
| 🔑 인증 상태 전역 관리: useState를 활용한 간단한 상태 관리 (0) | 2025.12.05 |
|---|---|
| 🔒 Nuxt 미들웨어 실습: admin 페이지에 로그인 체크 적용하기 (0) | 2025.12.05 |