[프로그래머스] Node기반 REST API 구현(4)

Lina Hongbi Ko·2024년 10월 4일
0

Programmers_BootCamp

목록 보기
29/76
post-thumbnail

2024년 10월 4일

✏️ 도서 테이블 생성

  • users 테이블 고치기

  • books 테이블 생성

  • 어떤 테이터베이스를 쓰든, 프로그래밍 언어를 사용하든 충돌이 일어날 가능성이 있으므로 예약어 쓰지 말도록!

✏️ BookController

  • 도서 등록 API가 없으니깐 일단 도서 데이터 테이블에 넣어주고 시작

*데이터베이스를 위한 파일 생성 : data.sql

  • 이제 BookController을 등록해보자 (카테고리별 도서 조회는 쿼리로 받을 예정)
// books.js

const express = require("express");
const router = express.Router();
router.use(express.json());
const {
  allBooks,
  bookDetail,
  booksByCategory,
} = require("../controller/BookController");

// 전체 도서 조회
router.get("/", allBooks);

// 개별 도서 조회
router.get("/:id", bookDetail);

// 카테고리별 도서 목록 조회
router.get("/", booksByCategory);
// 쿼리 스트링은 res.query.categoryId를 이용할 예정

module.exports = router;
// BookController.js

const conn = require("../mariadb"); // db 모듈
const { StatusCodes } = require("http-status-codes"); // status code 모듈

const allBooks = (req, res) => {
  res.json("전체 도서 조회");
};

const bookDetail = (req, res) => {
  res.json("개별 도서 조회");
};

const booksByCategory = (req, res) => {
  res.json("카테고리별 도서 조회");
};

module.exports = { allBooks, bookDetail, booksByCategory };

💡 도서 전체 조회

: 요약된 전체 도서 리스트를 보여줘야 함 ⇒ 필요한 데이터만 프론트에서 선별해 구현하도록 하기

// BookController.js

const conn = require("../mariadb"); // db 모듈
const { StatusCodes } = require("http-status-codes"); // status code 모듈

const allBooks = (req, res) => {
  // (요약된) 전체 도서 리스트
  let sql = "SELECT * FROM books";
  conn.query(sql, (err, results) => {
    if (err) {
      console.log(err);
      return res.status(StatusCodes.BAD_REQUEST).end();
    }

    return res.status(StatusCodes.OK).json(results);
  });
};

POSTMAN) GET + localhost:9999/books

💡 개별 도서 조회

// BookController.js

const conn = require("../mariadb"); // db 모듈
const { StatusCodes } = require("http-status-codes"); // status code 모듈

const bookDetail = (req, res) => {
  let { id } = req.params;
  id = parseInt(id);

  let sql = "SELECT * FROM books WHERE id = ?";
  conn.query(sql, id, (err, results) => {
    if (err) {
      console.log(err);
      return res.status(StatusCodes.BAD_REQUEST).end();
    }

    if (results[0]) {
      return res.status(StatusCodes.OK).json(results[0]); // 책 한권만 보여주기
    } else {
      return res.status(StatusCodes.NOT_FOUND).end();
    }
  });
};

POSTMAN) GET + localhost:9999/2

✏️ picsum

: picsum 사이트 이용해서 이미지를 써보자

  • id만 있으면 이미지 쉽게 사용 가능

  • 데이터베이스에 이미지 url 들어갈 데이터 자리 마련

  • books 테이블에 img 칼럼 추가

  • 이미지 번호 테이블에 넣기 & API 설계도에 response body에 img 넣기

💡 카테고리별 도서 목록 조회

: 카테고리별 도서 목록 조회는 쿼리 스트링으로 조회할 예정

  • books테이블에 category_id 컬럼 추가

  • 카테고리 숫자 데이터를 넣어줘보자

  • 쿼리를 찍어 확인해보자
    => SELECT * FROM books WHERE category_id=0;

  • 이제 API를 만들어보자

// BookController.js

const conn = require("../mariadb"); // db 모듈
const { StatusCodes } = require("http-status-codes"); // status code 모듈

const booksByCategory = (req, res) => {
  let { category_id } = req.query;
  category_id = parseInt(category_id);

  let sql = "SELECT * FROM books WHERE category_id = ?";
  conn.query(sql, category_id, (err, results) => {
    if (err) {
      console.log(err);
      return res.status(StatusCodes.BAD_REQUEST).end();
    }

    if (results.length) {
      return res.status(StatusCodes.OK).json(results);
    } else {
      return res.status(StatusCodes.NOT_FOUND).end();
    }
  });
};

POSTMAN) GET + localhost:9999/books?category_id=0

생각과는 다르게 책의 전체 목록이 나온다.
why??

우선 순위에 밀렸음 -> 전체 도서 조회 코드에게 밀림 (api가 같을때 코드가 먼저 써진 우선 순위를 따름)

그럼, 전체 도서 조회 라우터 순서를 카테고리별 도서 조회 밑으로 내려보자

// books.js

... 생략 ...
// 개별 도서 조회
router.get("/:id", bookDetail);
// 전체 도서 조회
router.get("/", allBooks);

카테고리별 도서 조회는 잘나오지만, 전체 도서 조회를 하면 다시 에러 발생!

  • 해결 방법 : api를 합쳐서 분기시킴 → 카테고리별 조회 API를 전체 도서 API의 조건문으로 분기시켜 사용
// BookController.js

const conn = require("../mariadb"); // db 모듈
const { StatusCodes } = require("http-status-codes"); // status code 모듈

const allBooks = (req, res) => {
  let { category_id } = req.query;

  if (category_id) {
  // 카테고리별 도서 리스트
    let sql = "SELECT * FROM books WHERE category_id = ?";
    conn.query(sql, category_id, (err, results) => {
      if (err) {
        console.log(err);
        return res.status(StatusCodes.BAD_REQUEST).end();
      }

      if (results.length) {
        return res.status(StatusCodes.OK).json(results);
      } else {
        return res.status(StatusCodes.NOT_FOUND).end();
      }
    });
  } else {
    // (요약된) 전체 도서 리스트
    let sql = "SELECT * FROM books";
    conn.query(sql, (err, results) => {
      if (err) {
        console.log(err);
        return res.status(StatusCodes.BAD_REQUEST).end();
      }

      return res.status(StatusCodes.OK).json(results);
    });
  }
};

module.exports = { allBooks, bookDetail };
// books.js

const express = require("express");
const router = express.Router();
router.use(express.json());
const {
  allBooks,
  bookDetail
} = require("../controller/BookController");

// 전체 도서 조회
router.get("/", allBooks);

// 개별 도서 조회
router.get("/:id", bookDetail);

module.exports = router;

POSTMAN) GET + localhost:9999/books?category_id=0

POSTMAN) GET + localhost:9999/books

✏️ 카테고리

: 카테고리별 도서까지 조회되는 것을 확인했다.
그런데, 우리는 category_id값이 아니라, 카테고리 name을 보여줘야 한다.
ex) 카테고리: 소설

  • 카테고리 테이블에 id와 name을 매핑해서 프론트가 이름이 필요하면 백엔드가 알려줘야한다. 카테고리는 많을 것이므로 데이터베이스로 관리해줘야함(둘 중 하나가 관리해줘야 안전)

  • 따라서, 카테고리 테이블부터 만들어보자

  • 데이터도 넣어주자

  • 카테고리 API를 설계해보자

  • 이제 카테고리 전체 목록 조회 API를 구현해보자
// app.js

// express 모듈
const express = require("express");
const app = express();

// dotenv 모듈
const dotenv = require("dotenv");
dotenv.config();

app.listen(process.env.PORT);

const userRouter = require("./routes/users");
const bookRouter = require("./routes/books");
const categoryRouter = require("./routes/category");
const likeRouter = require("./routes/likes");
const cartRouter = require("./routes/carts");
const orderRouter = require("./routes/orders");

app.use("/users", userRouter);
app.use("/books", bookRouter);
app.use("/category", categoryRouter);
app.use("/likes", likeRouter);
app.use("/carts", cartRouter);
app.use("/orders", orderRouter);
// category.js

const express = require("express");
const router = express.Router();
router.use(express.json());

const { allCategory } = require("../controller/CategoryController");

router.get("/", allCategory); // 카테고리 전체 목록 조회

module.exports = router;
// CategoryController.js

const conn = require("../mariadb"); // db 모듈
const { StatusCodes } = require("http-status-codes"); // status code 모듈

const allCategory = (req, res) => {
    // 카테고리 전체 목록 리스트
    let sql = "SELECT * FROM category";
    conn.query(sql, (err, results) => {
      if (err) {
        console.log(err);
        return res.status(StatusCodes.BAD_REQUEST).end();
      }

      return res.status(StatusCodes.OK).json(results);
    });
  }
};

module.exports = {allCategory};

POSTMAN) GET + localhost:9999/category

  • books테이블의 category_id 말고, category 테이블의 name을 사용하기 위해 JOIN을 이용해보자
  • 나의 예상 쿼리 : SELECT * FROM books LEFT JOIN category ON books.category_id = category.name;

🍎🍏 오늘의 느낀점 : 오늘도 어제와 비슷하게 테이블을 생성하고 데이터들을 넣어보는 작업을 했보았다. API 설계도 바뀌고, 직접 어떻게 프론트와 통신해야할지 생각해보면서 API를 구현해보니, 어떻게 하면 효율적으로 잘 소통할 수 있을지 고민해보는게 정말 중요할 것 같다. 그리고 오늘 아주 작은 실수때문에 골머리를 앓았는데,, module을 만들어 줄때 구조분해할당을 통해 가져왔으면 exports도 그렇게 해야하므로 대괄호 {}를 넣어야 했었다. 이런 사소한 경험 하나가 다 중요하겠지?🥹😱

profile
프론트엔드개발자가 되고 싶어서 열심히 땅굴 파는 자

0개의 댓글