Files
xrlms/API_USAGE.md

13 KiB

API 사용 가이드

이 문서는 데이터베이스에 데이터를 생성하는 API의 사용 방법을 설명합니다.

📋 목차

  1. 기본 설정
  2. 사용자 API
  3. 교육과정 API
  4. 강좌 API
  5. 공지사항 API
  6. 에러 처리
  7. 실전 예제

기본 설정

환경 변수

.env 파일에 데이터베이스 연결 정보가 설정되어 있어야 합니다:

DATABASE_URL="postgresql://user:password@localhost:5432/dbname"

API 기본 URL

  • 개발 환경: http://localhost:3000/api
  • 프로덕션: https://your-domain.com/api

1. 사용자 API

POST /api/users - 사용자 생성

새로운 사용자를 생성합니다.

요청

const response = await fetch('/api/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    email: 'user@example.com',
    password: 'hashed_password_here', // 실제로는 해시화된 비밀번호
    name: '홍길동',
    phone: '010-1234-5678',        // 선택사항
    gender: 'M',                    // 선택사항: 'M' 또는 'F'
    birthdate: '1990-01-01',        // 선택사항: YYYY-MM-DD 형식
    role: 'LEARNER',                // 선택사항: 'LEARNER' 또는 'ADMIN' (기본값: 'LEARNER')
    status: 'ACTIVE',               // 선택사항: 'ACTIVE' 또는 'INACTIVE' (기본값: 'ACTIVE')
  }),
});

const data = await response.json();

성공 응답 (201)

{
  "message": "사용자가 성공적으로 생성되었습니다.",
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "user@example.com",
    "name": "홍길동",
    "phone": "010-1234-5678",
    "gender": "M",
    "birthdate": "1990-01-01T00:00:00.000Z",
    "role": "LEARNER",
    "status": "ACTIVE",
    "joinDate": "2024-11-21T00:00:00.000Z",
    "createdAt": "2024-11-21T00:00:00.000Z",
    "updatedAt": "2024-11-21T00:00:00.000Z"
  }
}

에러 응답

400 Bad Request - 필수 필드 누락

{
  "error": "이메일, 비밀번호, 이름은 필수입니다."
}

409 Conflict - 이메일 중복

{
  "error": "이미 존재하는 이메일입니다."
}

GET /api/users - 사용자 목록 조회

사용자 목록을 조회합니다. 필터링 및 페이지네이션을 지원합니다.

요청

// 전체 사용자 조회
const response = await fetch('/api/users');

// 필터링 및 페이지네이션
const response = await fetch('/api/users?role=LEARNER&status=ACTIVE&page=1&limit=10');

const data = await response.json();

쿼리 파라미터

  • role (선택): LEARNER 또는 ADMIN
  • status (선택): ACTIVE 또는 INACTIVE
  • page (선택): 페이지 번호 (기본값: 1)
  • limit (선택): 페이지당 항목 수 (기본값: 10)

성공 응답 (200)

{
  "users": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "email": "user@example.com",
      "name": "홍길동",
      "role": "LEARNER",
      "status": "ACTIVE",
      ...
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 10,
    "total": 30,
    "totalPages": 3
  }
}

2. 교육과정 API

POST /api/courses - 교육과정 생성

새로운 교육과정을 생성합니다.

요청

const response = await fetch('/api/courses', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    courseName: '웹 개발 기초',
    instructorId: 'instructor-uuid-here',  // 필수: 강사(ADMIN 역할)의 ID
    createdById: 'admin-uuid-here',        // 선택사항: 등록자 ID (기본값: instructorId)
  }),
});

const data = await response.json();

성공 응답 (201)

{
  "message": "교육과정이 성공적으로 생성되었습니다.",
  "course": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "courseName": "웹 개발 기초",
    "instructorId": "instructor-uuid",
    "createdById": "admin-uuid",
    "createdAt": "2024-11-21T00:00:00.000Z",
    "instructor": {
      "id": "instructor-uuid",
      "name": "최예준",
      "email": "instructor@example.com"
    },
    "createdBy": {
      "id": "admin-uuid",
      "name": "관리자"
    }
  }
}

에러 응답

400 Bad Request - 필수 필드 누락

{
  "error": "교육과정명과 강사 ID는 필수입니다."
}

404 Not Found - 강사를 찾을 수 없음

{
  "error": "강사를 찾을 수 없습니다."
}

GET /api/courses - 교육과정 목록 조회

교육과정 목록을 조회합니다.

요청

// 전체 교육과정 조회
const response = await fetch('/api/courses');

// 특정 강사의 교육과정 조회
const response = await fetch('/api/courses?instructorId=instructor-uuid&page=1&limit=10');

const data = await response.json();

쿼리 파라미터

  • instructorId (선택): 강사 ID로 필터링
  • page (선택): 페이지 번호 (기본값: 1)
  • limit (선택): 페이지당 항목 수 (기본값: 10)

3. 강좌 API

POST /api/lessons - 강좌 생성

새로운 강좌를 생성합니다.

요청

const response = await fetch('/api/lessons', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    courseId: 'course-uuid-here',           // 필수: 교육과정 ID
    lessonName: 'HTML 기초',                // 필수: 강좌명
    learningGoal: 'HTML의 기본 문법을 이해하고 활용할 수 있다.', // 선택사항: 학습 목표
    createdById: 'admin-uuid-here',         // 선택사항: 등록자 ID
  }),
});

const data = await response.json();

성공 응답 (201)

{
  "message": "강좌가 성공적으로 생성되었습니다.",
  "lesson": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "courseId": "course-uuid",
    "lessonName": "HTML 기초",
    "learningGoal": "HTML의 기본 문법을 이해하고 활용할 수 있다.",
    "createdAt": "2024-11-21T00:00:00.000Z",
    "course": {
      "id": "course-uuid",
      "courseName": "웹 개발 기초"
    },
    "createdBy": {
      "id": "admin-uuid",
      "name": "관리자"
    },
    "_count": {
      "videos": 0,
      "vrContents": 0,
      "questions": 0
    }
  }
}

GET /api/lessons - 강좌 목록 조회

강좌 목록을 조회합니다.

요청

// 전체 강좌 조회
const response = await fetch('/api/lessons');

// 특정 교육과정의 강좌 조회
const response = await fetch('/api/lessons?courseId=course-uuid&page=1&limit=10');

const data = await response.json();

4. 공지사항 API

POST /api/notices - 공지사항 생성

새로운 공지사항을 생성합니다.

요청

const response = await fetch('/api/notices', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    title: '공지사항 제목',
    content: '공지사항 내용입니다.\n여러 줄로 작성할 수 있습니다.',
    writerId: 'admin-uuid-here',           // 필수: 작성자 ID
    hasAttachment: false,                   // 선택사항: 첨부파일 여부 (기본값: false)
  }),
});

const data = await response.json();

성공 응답 (201)

{
  "message": "공지사항이 성공적으로 생성되었습니다.",
  "notice": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "title": "공지사항 제목",
    "content": "공지사항 내용입니다.\n여러 줄로 작성할 수 있습니다.",
    "writerId": "admin-uuid",
    "views": 0,
    "hasAttachment": false,
    "date": "2024-11-21T00:00:00.000Z",
    "writer": {
      "id": "admin-uuid",
      "name": "관리자",
      "email": "admin@example.com"
    }
  }
}

GET /api/notices - 공지사항 목록 조회

공지사항 목록을 조회합니다.

요청

// 전체 공지사항 조회
const response = await fetch('/api/notices');

// 특정 작성자의 공지사항 조회
const response = await fetch('/api/notices?writerId=admin-uuid&page=1&limit=10');

const data = await response.json();

에러 처리

모든 API는 일관된 에러 응답 형식을 사용합니다:

try {
  const response = await fetch('/api/users', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(userData),
  });

  if (!response.ok) {
    const error = await response.json();
    console.error('에러:', error.error);
    // 에러 처리 로직
    return;
  }

  const data = await response.json();
  console.log('성공:', data);
} catch (error) {
  console.error('네트워크 오류:', error);
}

HTTP 상태 코드

  • 200 - 성공 (GET 요청)
  • 201 - 생성 성공 (POST 요청)
  • 400 - 잘못된 요청 (필수 필드 누락 등)
  • 404 - 리소스를 찾을 수 없음
  • 409 - 충돌 (중복 데이터 등)
  • 500 - 서버 오류

실전 예제

React 컴포넌트에서 사용하기

'use client';

import { useState } from 'react';

export default function CreateUserForm() {
  const [formData, setFormData] = useState({
    email: '',
    password: '',
    name: '',
    role: 'LEARNER',
  });
  const [loading, setLoading] = useState(false);
  const [message, setMessage] = useState('');

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);
    setMessage('');

    try {
      const response = await fetch('/api/users', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(formData),
      });

      const data = await response.json();

      if (!response.ok) {
        setMessage(`오류: ${data.error}`);
        return;
      }

      setMessage('사용자가 성공적으로 생성되었습니다!');
      // 폼 초기화
      setFormData({ email: '', password: '', name: '', role: 'LEARNER' });
    } catch (error) {
      setMessage('네트워크 오류가 발생했습니다.');
    } finally {
      setLoading(false);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="email"
        placeholder="이메일"
        value={formData.email}
        onChange={(e) => setFormData({ ...formData, email: e.target.value })}
        required
      />
      <input
        type="password"
        placeholder="비밀번호"
        value={formData.password}
        onChange={(e) => setFormData({ ...formData, password: e.target.value })}
        required
      />
      <input
        type="text"
        placeholder="이름"
        value={formData.name}
        onChange={(e) => setFormData({ ...formData, name: e.target.value })}
        required
      />
      <select
        value={formData.role}
        onChange={(e) => setFormData({ ...formData, role: e.target.value })}
      >
        <option value="LEARNER">학습자</option>
        <option value="ADMIN">관리자</option>
      </select>
      <button type="submit" disabled={loading}>
        {loading ? '생성 중...' : '사용자 생성'}
      </button>
      {message && <p>{message}</p>}
    </form>
  );
}

Server Component에서 사용하기

// app/admin/users/page.tsx
import { prisma } from '@/lib/prisma';

export default async function UsersPage() {
  const users = await prisma.user.findMany({
    take: 10,
    orderBy: { createdAt: 'desc' },
  });

  return (
    <div>
      <h1>사용자 목록</h1>
      <ul>
        {users.map((user) => (
          <li key={user.id}>
            {user.name} ({user.email}) - {user.role}
          </li>
        ))}
      </ul>
    </div>
  );
}

cURL로 테스트하기

# 사용자 생성
curl -X POST http://localhost:3000/api/users \
  -H "Content-Type: application/json" \
  -d '{
    "email": "test@example.com",
    "password": "test123",
    "name": "테스트 사용자",
    "role": "LEARNER"
  }'

# 사용자 목록 조회
curl http://localhost:3000/api/users?role=LEARNER&page=1&limit=10

# 교육과정 생성
curl -X POST http://localhost:3000/api/courses \
  -H "Content-Type: application/json" \
  -d '{
    "courseName": "웹 개발 기초",
    "instructorId": "instructor-uuid-here"
  }'

🔒 보안 고려사항

  1. 비밀번호 해시화: 실제 프로덕션에서는 bcrypt 등을 사용하여 비밀번호를 해시화해야 합니다.
  2. 인증/인가: 현재 API는 인증이 없습니다. 프로덕션에서는 JWT 또는 세션 기반 인증을 추가해야 합니다.
  3. 입력 검증: 클라이언트 측 검증 외에도 서버 측 검증이 필요합니다.
  4. CORS 설정: 필요시 CORS 설정을 추가해야 합니다.

📚 추가 리소스