[React] React + Node.js 풀스택 CRUD 만들기 (Prisma + SQLite)

2026. 3. 13. 18:43·💻 개발/🦕 React
728x90
반응형

| 서론

안녕하세요, 팡일입니다.

 

이전 글에서는 React + Node.js 기반의 풀스택 모노레포 환경을 구축하는 과정을 정리했고,

이번 글에서는 그 환경 위에서 실제로 데이터를 저장하고 조회할 수 있는 CRUD 기능을 구현해보겠습니다.

 

전체 데이터 흐름은 다음과 같습니다.

React
 ↓
Express API
 ↓
Prisma
 ↓
SQLite Database

 

간단한 Todo API를 만들어 React에서 데이터를 저장하고 조회해보겠습니다.

 

 

 

 

| 1단계 : Prisma 설치

1) Prisma ORM

Node 서버에서 데이터베이스를 사용하기 위해 Prisma ORM을 사용합니다.

 

Prisma는 TypeScript 환경에서 매우 사용하기 편한 ORM입니다.

  • 타입 자동 생성
  • DB 마이그레이션 지원
  • 직관적인 API

 

2) 설치

: 먼저 api 패키지에 Prisma를 설치합니다.

pnpm add prisma@6 @prisma/client@6 --filter api

 

Prisma CLI도 설치합니다.

pnpm add -D prisma@6 --filter api

 

 

 

| 2단계 : Prisma 초기화

이제 Prisma 설정을 생성합니다.

cd apps/api
npx prisma init

 

생성 후에는 다음과 같은 구조가 생성됩니다.

apps/api
 ├ prisma
 │   └ schema.prisma
 ├ .env
 └ prisma.config.ts

 

 

 

| 3단계 : SQLite 데이터베이스 설정

이번 프로젝트에서는 로컬에서 간단히 테스트할 수 있는 SQLite를 사용합니다.

 

.env 파일을 수정합니다.

DATABASE_URL="file:./dev.db"

 

SQLite는 별도의 데이터베이스 서버를 설치하지 않아도 되기 때문에 로컬 환경에서 빠르게 CRUD 기능을 테스트할 수 있습니다.

 

 

 

 

| 4단계 : 데이터 모델 정의

schema.prisma 파일에서 Todo 모델을 정의합니다.

model Todo {
  id        Int      @id @default(autoincrement())
  title     String
  completed Boolean  @default(false)
  createdAt DateTime @default(now())
}

 

이 모델을 기준으로 데이터베이스 테이블이 생성됩니다.

 

 

 

 

| 5단계 : 데이터베이스 마이그레이션

모델을 정의했다면 실제 데이터베이스를 생성합니다.

npx prisma migrate dev --name init

 

이 명령을 실행하면 다음 작업이 수행됩니다.

  • SQLite DB 생성
  • migration 파일 생성
  • Prisma Client 생성

 

실행 후 다음 파일이 생성됩니다.

apps/api/prisma/dev.db

 

 

 

| 6단계 : Prisma Client 생성

Prisma Client는 Node.js에서 데이터베이스를 제어하는 역할을 합니다.

 

1) 생성

: 아래의 명령어로 Prisma Client를 사용할 파일을 생성합니다.

npx prisma generate

 

 

 

2) 작성

: src/prisma.ts 파일에 아래의 내용을 작성합니다.

import { PrismaClient } from "@prisma/client";

export const prisma = new PrismaClient();

 

이제 Express 서버에서 Prisma를 통해 데이터베이스에 접근할 수 있습니다.

 

 

 

 

| 7단계 : Todo CRUD API 구현

이제 Express 서버에 CRUD API를 구현합니다.

 

1) src/index.ts

import express from "express";
import cors from "cors";
import { prisma } from "./prisma";

const app = express();

app.use(cors());
app.use(express.json());

app.get("/api/todos", async (req, res) => {
  const todos = await prisma.todo.findMany();
  res.json(todos);
});

app.post("/api/todos", async (req, res) => {
  const { title } = req.body;

  const todo = await prisma.todo.create({
    data: { title },
  });

  res.json(todo);
});

app.patch("/api/todos/:id", async (req, res) => {
  const id = Number(req.params.id);

  const todo = await prisma.todo.update({
    where: { id },
    data: { completed: true },
  });

  res.json(todo);
});

app.delete("/api/todos/:id", async (req, res) => {
  const id = Number(req.params.id);

  await prisma.todo.delete({
    where: { id },
  });

  res.json({ success: true });
});

app.listen(3001, () => {
  console.log("server running on 3001");
});

 

 

 

| 8단계 : React에서 API 호출

이제 React에서 API를 호출합니다.

 

1) App.tsx

import { useEffect, useState } from "react";

type Todo = {
  id: number;
  title: string;
  completed: boolean;
};

function App() {
  const [todos, setTodos] = useState<Todo[]>([]);
  const [title, setTitle] = useState("");

  const fetchTodos = async () => {
    const res = await fetch("http://localhost:3001/api/todos");
    const data = await res.json();
    setTodos(data);
  };

  const createTodo = async () => {
    await fetch("http://localhost:3001/api/todos", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ title }),
    });

    setTitle("");
    fetchTodos();
  };

  useEffect(() => {
    fetchTodos();
  }, []);

  return (
    <div style={{ padding: 40 }}>
      <h1>Todo List</h1>

      <input
        value={title}
        onChange={(e) => setTitle(e.target.value)}
      />

      <button onClick={createTodo}>추가</button>

      <ul>
        {todos.map((todo) => (
          <li key={todo.id}>{todo.title}</li>
        ))}
      </ul>
    </div>
  );
}

export default App;

 

 

 

| 9단계 : 실행 및 테스트

1) 개발 서버 실행

: 프로젝트 루트에서 다음 명령어를 실행합니다.

pnpm dev

 

2) 접속

http://localhost:5173

 

Todo를 추가하면 다음 흐름으로 데이터가 저장됩니다.

React
 ↓
fetch API
 ↓
Express
 ↓
Prisma
 ↓
SQLite

 

그리고 API를 직접 확인할 수도 있습니다.

http://localhost:3001/api/todos

 

 

 

 

| 트러블슈팅

1) CORS 오류

React 개발 서버와 Express 서버는 서로 다른 origin이기 때문에 브라우저에서 API 요청이 차단될 수 있습니다.

 

이를 해결하기 위해 Express에 cors 미들웨어를 추가했습니다.

import cors from "cors";

app.use(cors());

 

 

 

2) Prisma Client 타입 오류

Prisma Client를 생성하지 않으면 다음 오류가 발생할 수 있습니다.

'@prisma/client' 모듈에 PrismaClient가 없습니다

 

이 경우 다음 명령어로 Prisma Client를 생성합니다.

npx prisma generate

 

 

 

| 결론

이번 글에서는 풀스택 모노레포 환경 위에서 실제 CRUD 기능을 구현하는 과정을 정리했습니다.

 

이를 통해 전체 스택은 다음과 같습니다.

  • React + Vite
  • Node.js + Express
  • Prisma ORM
  • SQLite
  • Turborepo
  • pnpm workspace

이 구조를 사용하면 프론트엔드와 백엔드를 하나의 프로젝트에서 함께 관리할 수 있고, 빠르게 풀스택 기능을 개발할 수 있습니다.

 

728x90
반응형

'💻 개발 > 🦕 React' 카테고리의 다른 글

[React] React + Node.js 풀스택 모노레포 환경 세팅 (pnpm + Turborepo)  (0) 2026.03.13
[React] API 모듈 정리하다 터진 404와 export 오류 원인 정리  (0) 2026.02.27
[React] React Router 중첩 라우트에서 index 대신 Navigate를 선택한 이유  (0) 2026.01.19
[React] React + Vite + TS + Firebase Hosting + Github Action 구축하기  (0) 2026.01.18
[React] TanStack Query(React Query) 활용하기 - useMutation으로 데이터 생성·수정·삭제 마스터하기  (0) 2026.01.15
'💻 개발/🦕 React' 카테고리의 다른 글
  • [React] React + Node.js 풀스택 모노레포 환경 세팅 (pnpm + Turborepo)
  • [React] API 모듈 정리하다 터진 404와 export 오류 원인 정리
  • [React] React Router 중첩 라우트에서 index 대신 Navigate를 선택한 이유
  • [React] React + Vite + TS + Firebase Hosting + Github Action 구축하기
pangil_kim
pangil_kim
기록을 통해 지속적인 성장을 추구합니다.
  • pangil_kim
    멈추지 않는 기록
    pangil_kim
  • 전체
    오늘
    어제
  • 📝 글쓰기
      ⚙️ 관리

    • 분류 전체보기 (434) N
      • 💻 개발 (188) N
        • ※ 참고 지식 (10)
        • 🦕 React (16)
        • 🎩 Next.js (25)
        • 📘 TypeScript (4)
        • 📒 JavaScript (9)
        • 🟩 Node.js (7)
        • 📀 MySQL (24)
        • 🌸 Spring Boot (5)
        • 👷 SveleteKit (24)
        • 🩵 Flutter (11)
        • 🌀 Dart (2)
        • 🌈 CSS (5)
        • 🔸Git (1)
        • 🔥 Firebase (4)
        • 🧑🏻‍💻 코테 (29)
        • 🕸️ 알고리즘 (5)
        • 🌤️ AWS (1)
        • 🤖 AI Agent (1)
        • 🧬 Backend (2)
        • 🅰️ Angular (3) N
      • 📋 프로젝트 (6)
        • ☄️ 트러블 슈팅 (3)
        • 🧑🏻‍💻 서비스 소개 (3)
      • ✍🏻 회고 (67)
        • ☀️ 취준일지 (13)
        • 🍀 우테코 (32)
        • 👋 주간회고 (6)
      • 📰 정보 공유 (12)
      • 🧑🏻‍💻 개발자라면? (1)
      • 🏫 한동대학교 (153)
        • Database (15)
        • Software Engineering (18)
        • EAP (22)
        • 일반화학 (26)
        • 25-1 수업 정리 (19)
        • Computer Networking (36)
        • OPIc (2)
        • 미술의 이해 (15)
  • 최근 글

  • 인기 글

  • 태그

    GLS
    computer networks and the internet
    어노인팅
    한동대학교
    전산전자공학부
    typeScript
    네트워킹
    프론트엔드
    웹개발
    csee
    우테코 8기
    웹 프론트엔드 8기
    찬양
    부트캠프
    고윤민교수님
    글로벌리더십학부
    QT
    묵상
    날마다 솟는 샘물
    프리코스
    주일
    예배
    데이터베이스
    우아한테크코스
    CCM
    FE
    컴네
    날솟샘
    설교
    우테코
  • 최근 댓글

  • 250x250
  • hELLO· Designed By정상우.v4.10.4
pangil_kim
[React] React + Node.js 풀스택 CRUD 만들기 (Prisma + SQLite)
상단으로

티스토리툴바