프로그래머스 데브코스TIL북 스토어 프로젝트

[week6] 프로젝트 : Node.js 기반의 Rest API 구현 (6)

이규현2026-02-13
[week6] 프로젝트 : Node.js 기반의 Rest API 구현 (6)

지난 시간에 이어서 계속 진행해보겠습니다. 👉🏻 지난시간 확인하기

도서 API 구현

도서 테이블 생성

도서 테이블을 생성해보겠습니다.

CREATE TABLE `books` (
  id INT NOT NULL AUTO_INCREMENT,
  title VARCHAR(45) NOT NULL,
  `format` VARCHAR(45) NOT NULL,
  isbn VARCHAR(45) NOT NULL,
  summary VARCHAR(500) NULL,
  `description` LONGTEXT NULL,
  author VARCHAR(45) NOT NULL,
  pages INT NOT NULL,
  `index` LONGTEXT NULL,
  price INT NOT NULL,
  pub_date DATE NULL,
  PRIMARY KEY (`id`),
  UNIQUE INDEX `isbn_UNIQUE` (`isbn` ASC)
);

컬럼명 변경

방금 위에서 만들 테이블에서 format, description, index에는 백팁을 사용한 이유가 무엇을까? 그 이유는 format, description, index는 mysql에서 사용하고 있는 예약어이기 때문이다.

예약어란?

데이터베이스 시스템이 자기만의 특수한 목적을 위해 이미 '찜'해놓은 단어들을 말한다.

MySQL에서 사용하는 예약어

  • index "데이터를 빨리 찾기 위해 색인(Index)을 만들어라"라는 아주 중요한 명령어이다. 그래서 이걸 컬럼명으로 쓰면 DB는 "색인을 만들라는 거야, 아니면 컬럼 이름이라는 거야?"라며 헷갈려서 에러를 낸다.

  • format 특정 데이터의 형식을 바꾸는 함수 이름으로 예약되어 있다.

  • description 특정 데이터의 상세 구조를 보여달라는 명령(DESC)과 비슷하여 혼동을 줄 수 있다.

컬럼명 수정

그래서 해당 컬럼명을 바꿔주도록 하겠습니다. format -> form description -> detail index -> contents

ALTER TABLE books CHANGE COLUMN `format` form VARCHAR(45) NOT NULL;
ALTER TABLE books CHANGE COLUMN `description` detail LONGTEXT NULL;
ALTER TABLE books CHANGE COLUMN `index` contents LONGTEXT NULL;

데이터 넣기

만들어둔 도서 테이블에 데이터를 집어넣어줄겁니다. 자세한건 👉🏻 데이터 삽입 SQL문 해당 링크를 통해서 확인해주시면 되겠습니다.

도서 전체 조회 구현

우선 전체 도서 조회 api 구현하고 postman을 통해 확인해보겠습니다.

bookController

export const getAllbooks = (req, res) => {
  const sql = `SELECT * FROM books`;

  conn.query(sql, (err, results) => {
    if (err) {
      console.error('도서 전체 조회 요청 DB 에러:', err);
      return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json(err);
    }
    return res.status(StatusCodes.OK).json(results);
  });
};

books.js

import express from 'express';
import { getAllbooks, getBookById } from '../controller/bookController.js';

const router = express.Router();

router.get('/', getAllbooks);

export default router;

결과 화면

개별 도서 조회 구현

bookController

// getAllBooks() 아래에 작성하면 됩니다.
export const getBookById = (req, res) => {
  const { id } = req.params;
  const sql = `SELECT * FROM books WHERE id = ?`;

  conn.query(sql, [id], (err, results) => {
    if (err) {
      console.error('도서 개별 조회 요청 DB 에러:', err);
      return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json(err);
    }
    if (results[0]) {
      return res.status(StatusCodes.OK).json(results[0]);
    } else {
      return res.status(StatusCodes.NOT_FOUND).json({
        message: '존재하지 않는 도서입니다.',
      });
    }
  });
};

books.js

router
  .get('/', getAllbooks)

  .get('/:id', getBookById);

결과화면

piksum, 이미지 경로 추가

piksum 웹사이트 레이아웃을 잡거나 테스트를 할 때, 실제 이미지가 준비되기 전 임시로 사용하는 플레이스홀더(Placeholder) 이미지 서비스입니다.

특징 별도의 API 키나 가입 없이 URL 주소만으로 이미지를 불러올 수 있습니다.

URL 끝에 가로/세로 해상도를 적으면 원하는 크기로 이미지를 생성해 줍니다.

매번 다른 이미지를 보여주거나, 특정 ID 값을 지정해 고정된 이미지를 가져올 수 있습니다.

books 테이블에 이미지 컬럼 추가

ALTER TABLE books ADD COLUMN img INT NULL AFTER title;

카테고리별 도서 목록 조회

books 테이블에 category_id 컬럼 추가

ALTER TABLE books ADD COLUMN category_id INT NULL AFTER img;

bookController getAllBooks 수정

export const getAllbooks = (req, res) => {
  const { category_id } = req.query;
  if (category_id) {
    const sql = `SELECT * FROM books WHERE category_id=?`;
    conn.query(sql, [caategory_id], (err, results) => {
      if (err) {
        console.error('카테고리별 조회 요청 DB 에러:', err);
        return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json(err);
      }
      return res.status(StatusCodes.OK).json(results);
    });
  } else {
    const sql = `SELECT * FROM books`;

    conn.query(sql, (err, results) => {
      if (err) {
        console.error('도서 전체 조회 요청 DB 에러:', err);
        return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json(err);
      }
      return res.status(StatusCodes.OK).json(results);
    });
  }
};

결과

카테고리 API 구현

카테고리 테이블 생성

CREATE TABLE category (
  id INT NOT NULL,
  name VARCHAR(100) NOT NULL,
  PRIMARY KEY(id)
);

데이터 삽입

INSERT INTO category (id, name)
VALUES
  (0, '동화'),
  (1, '소설'),
  (2, '사회');

구현

categoryController

import conn from '../db/mysql_connect.js';
import { StatusCodes } from 'http-status-codes';

export const getAllCategory = (req, res) => {
  const sql = `SELECT * FROM category`;

  conn.query(sql, (err, results) => {
    if (err) {
      console.error('카테고리 전체 조회 요청 DB 에러:', err);
      return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json(err);
    }
    return res.status(StatusCodes.OK).json(results);
  });
};

category.js

import express from 'express';
import { getAllCategory } from '../controller/categoryController.js';

const router = express.Router();

router.get('/', getAllCategory);

export default router;

app.js 라우터 추가

import categoryRouter from './routes/category.js';

app.use('/category', categoryRouter);

결과

다음 시간

다음 시간에 카테고리별 도서 조회할 때 0,1,2 값이 아닌 category 테이블에 name (동화,소설,사회)처럼 나오도록 구현해볼 예정입니다.