board 추가/보기(페이징)/수정/삭제 APIReact+REST API 게시판 구현/BE - TypeORM2021. 9. 20. 18:51
Table of Contents
참고
What to do?
- board entity를 추가/보기/수정/삭제하는 API를 만들어보자.
- https://duckgugong.tistory.com/226
- 우선 위 링크에 들어가서 기본적인 API 설계를 하자.
board 관련 API 설계
컨트롤 모듈화
- board와 관련된 API의 입력과 출력을 담당해줄 BoardController.ts 파일을 src 아래 controller 폴더에 만들어주자.
src/controller/BoardController.ts
// board entity
import {Board} from "../entity/Board";
import {getConnection} from "typeorm";
export class BoardController {
}
라우팅 모듈화
- board 와 관련된 API는 /api/board/[~]의 경로를 가지고 있다.
- /api/board 뒤의 서브 라우팅을 처리해 줄 board.ts 파일을 src 아래 router 폴더에 만들어주자.
src/router/board.ts
import {Router} from "express";
import {BoardController} from "../controller/BoardController";
const routes = Router();
export default routes;
- 그리고 /board를 처리해 줄 부분을 src 아래 router 폴더에 있는 index.ts 파일에 추가하자.
src/router/index.ts
import {Router} from "express";
// src/router/board.ts 라우팅 모듈
import board from "./board";
const routes = Router();
routes.use('/board', board)
export default routes;
board 추가 API 구현
- HTTP 메서드: POST
- url: /api/board
controller 모듈
src/controller/BoardController.ts
- board 인스턴스를 만들고 save를 하면 ORM이 insert 구문을 실행하여 DB에 반영한다!
// board entity
import {Board} from "../entity/Board";
import {getConnection} from "typeorm";
export class BoardController {
static addBoard = async (req, res) => {
const {title, content} = req.body;
const board = new Board();
board.title = title;
board.content = content;
const result = await getConnection().getRepository(Board).save(board);
res.send(result);
}
}
라우팅 모듈
src/router/board.ts
import {Router} from "express";
// controller 모듈
import {BoardController} from "../controller/BoardController";
const routes = Router();
routes.post('', BoardController.addBoard);
export default routes;
board 전체 보기
- HTTP 메서드: GET
- url: api/board/list
controller 구현
src/controller/BoardController.ts
// board entity
import {Board} from "../entity/Board";
import {getConnection} from "typeorm";
export class BoardController {
...
static findAllBoard = async (req, res) => {
const boards = await getConnection().getRepository(Board).find();
res.send(boards);
}
}
라우팅 모듈
src/router/index.ts
import {Router} from "express";
// controller 모듈
import {BoardController} from "../controller/BoardController";
const routes = Router();
...
routes.get('/list', BoardController.findAllBoard);
export default routes;
board 하나 보기
- HTTP 메서드: GET
- url: /api/board/:id
controller 구현
src/controller/BoardController.ts
// board entity
import {Board} from "../entity/Board";
import {getConnection} from "typeorm";
export class BoardController {
...
static findOneBoard = async (req, res) => {
const {id} = req.params;
const board = await getConnection().getRepository(Board).findOne({id});
res.send(board);
}
}
라우팅 모듈
src/router/board.ts
import {Router} from "express";
// controller 모듈
import {BoardController} from "../controller/BoardController";
const routes = Router();
...
routes.get('/board/:id', BoardController.findOneBoard);
export default routes;
board 보기 (페이지네이션)
- 목록이 많아지면 페이지네이션을 구현해야 하는데, 클라이언트에서 페이지네이션을 구성하기 위한 세가지가 있다.
- 전체 목록 갯수 (서버로부터 리턴 받아야 함)
- 페이지 사이즈
- 현재 페이지 번호
- 예를 들어 3번째 페이지에서 10개를 가져온다고 하자.
- 페이지 사이즈: 2
- 현재 페이지 번호: 1
- MariaDB에서는 LIMIT offset, size와 같은 쿼리문이 있어서 이를 계산할 수 있다.
- offset: (현재 페이지 번호 - 1) * 페이지 사이즈 => 2 (offset은 0부터)
- size: 페이지 사이즈 = 10
- Contoller 에 page_number, page_size 두개의 파라미터를 받고 둘다 null이 아니면 skip과 take를 계산해서 페이징을 수행하자! 만약 둘 중 하나라도 null이면 전체 보기를 리턴하자!
- 위에 있는 board 전체보기(findAllBoard)를 아래처럼 수정하고 목록의 전체 갯수를 리턴하는 API를 추가해주자!
페이지네이션 or 목록 전체 보기 API
- HTTP 메서드: GET
- url: /api/boards/list
- 쿼리파라미터로 페이지 번호와 페이지 사이즈를 넘긴다!
목록의 전체 갯수 리턴 API
- HTTP 메서드: GET
- url: /api/board/count
controller 구현
src/controller/BoardController.ts
// board entity
import {Board} from "../entity/Board";
import {getConnection} from "typeorm";
export class BoardController {
...
static findAllBoard = async (req, res) => {
const {page_number, page_size} = req.query;
const options = {};
options['select'] = ["id", "title", "content", "created", "updated"];
options['order'] = {id: 'DESC'};
// 쿼리 파라미터가 넘어오지 않으면 전체 목록 리턴!
if (page_number && page_size) {
options['skip'] = (page_number - 1) * page_size;
options['take'] = page_size;
}
const boards = await getConnection().getRepository(Board).find(options);
res.send(boards);
}
// 목록의 전체 갯수 리턴
static countBoard = async (req, res) => {
const total = await getConnection().getRepository(Board).count();
res.send({total});
}
}
라우팅 모듈
src/router/board.ts
import {Router} from "express";
import {BoardController} from "../controller/BoardController";
const routes = Router();
routes.post('', BoardController.addBoard);
routes.get('/list', BoardController.findAllBoard);
routes.get('/:id', BoardController.findOneBoard);
routes.get('/count', BoardController.countBoard);
export default routes;
- 테스트해보면 결과가 나오지 않는다. 왜 그럴까?
- 앞에서 목록 하나 보기는 /api/board/:id 이고 카운트 api는 /api/board/count 이다.
- 스프링에서는 에러가 나지 않았는데 여기서 에러가 나는 이유는 스프링에서는 id 부분을 숫자 타입이라고 지정했기 때문에 스트링 타입이면 count로 매핑하고 숫자이면 게시판 상세보기로 매핑했기 때문이다.
- 여기서는 둘다 스트링으로 매핑되었기 때문에 /api/board/count 가 목록 하나 보기로 매핑이 되어버려서 결과가 나오지 않는다. 따라서 이 api를 목록 하나 보기보다 위로 올린다. 그러면 먼저 count를 매핑하고 없으면 아래로 내려가서 매핑하게 된다.
src/router/board.ts
import {Router} from "express";
import {BoardController} from "../controller/BoardController";
const routes = Router();
routes.post('', BoardController.addBoard);
routes.get('/list', BoardController.findAllBoard);
routes.get('/count', BoardController.countBoard);
routes.get('/:id', BoardController.findOneBoard);
export default routes;
board 수정
- HTTP 메서드: PUT
- url: /api/board
- 수정할 board의 id, title, content 값을 json 형식으로 body에 넣어서 입력한다!
controller 구현
src/controller/BoardController.ts
// board entity
import {Board} from "../entity/Board";
import {getConnection} from "typeorm";
export class BoardController {
...
static modifyBoard = async (req, res) => {
const {id, title, content} = req.body;
const updateOption = {};
if (title) {
updateOption['title'] = title;
}
if (content) {
updateOption['content'] = content;
}
const result = await getConnection().createQueryBuilder().update(Board)
.set(updateOption)
.where("id = :id", {id})
.execute();
res.send(result);
}
}
라우팅 모듈
src/router/board.ts
import {Router} from "express";
import {BoardController} from "../controller/BoardController";
const routes = Router();
...
routes.put('', BoardController.modifyBoard);
export default routes;
- 아래처럼 수정하는 API를 호출하고
- 해당 id 값을 가지는 board를 보여주는 API를 호출하면 아래와 같이 잘 반영이 되었다!
board 삭제
- HTTP 메서드: DELETE
- url: /api/board/:id
- 삭제할 board의 id를 uri 파라미터로 넘겨서 DB에서 삭제한다!
controller 구현
src/controller/BoardController.ts
// board entity
import {Board} from "../entity/Board";
import {getConnection} from "typeorm";
export class BoardController {
...
static removeBoard = async (req, res) => {
const {id} = req.params;
const result = await getConnection()
.createQueryBuilder()
.delete()
.from(Board)
.where("id = :id", {id})
.execute();
res.send(result);
}
}
라우팅 모듈
src/router/board.ts
import {Router} from "express";
import {BoardController} from "../controller/BoardController";
const routes = Router();
...
routes.delete('/:id', BoardController.removeBoard);
export default routes;
- id가 2인 board를 삭제하는 API를 호출하고
- 모든 board를 보여주는 API를 호출하면 id가 2인 board가 삭제되었다!
전체코드
controller 구현
src/controller/BoardController.ts
// board entity
import {Board} from "../entity/Board";
import {getConnection} from "typeorm";
export class BoardController {
static addBoard = async (req, res) => {
const {title, content} = req.body;
const board = new Board();
board.title = title;
board.content = content;
const result = await getConnection().getRepository(Board).save(board);
res.send(result);
}
static findAllBoard = async (req, res) => {
const {page_number, page_size} = req.query;
const options = {};
options['select'] = ["id", "title", "content", "created", "updated"];
options['order'] = {id: 'DESC'};
// 쿼리 파라미터가 넘어오지 않으면 전체 목록 리턴!
if (page_number && page_size) {
options['skip'] = (page_number - 1) * page_size;
options['take'] = page_size;
}
const boards = await getConnection().getRepository(Board).find(options);
res.send(boards);
}
// 목록의 전체 갯수 리턴
static countBoard = async (req, res) => {
const total = await getConnection().getRepository(Board).count();
res.send({total});
}
static findOneBoard = async (req, res) => {
const {id} = req.params;
const board = await getConnection().getRepository(Board).findOne({id});
res.send(board);
}
static modifyBoard = async (req, res) => {
const {id, title, content} = req.body;
const updateOption = {};
if (title) {
updateOption['title'] = title;
}
if (content) {
updateOption['content'] = content;
}
const result = await getConnection().createQueryBuilder().update(Board)
.set(updateOption)
.where("id = :id", {id})
.execute();
res.send(result);
}
static removeBoard = async (req, res) => {
const {id} = req.params;
const result = await getConnection()
.createQueryBuilder()
.delete()
.from(Board)
.where("id = :id", {id})
.execute();
res.send(result);
}
}
라우팅 모듈
src/router/board.ts
import {Router} from "express";
import {BoardController} from "../controller/BoardController";
const routes = Router();
routes.post('', BoardController.addBoard);
routes.get('/list', BoardController.findAllBoard);
routes.get('/count', BoardController.countBoard);
routes.get('/:id', BoardController.findOneBoard);
routes.put('', BoardController.modifyBoard);
routes.delete('/:id', BoardController.removeBoard);
export default routes;
'React+REST API 게시판 구현 > BE - TypeORM' 카테고리의 다른 글
commet CRUD API (0) | 2021.09.24 |
---|---|
board에 image 추가하기 (0) | 2021.09.24 |
컨트롤러, 라우팅 모듈화 (0) | 2021.09.19 |
IDEA에서 DataGrip 연결하기 + entity 설계 (1) | 2021.09.17 |
typeORM 설정 (0) | 2021.09.17 |
@덕구공 :: Duck9s'
주니어 개발자에욤
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!