본문 바로가기
리액트(React)

블로그 만들기 - 컨트롤러 파일 작성

by 즐거운코딩 2023. 7. 5.
반응형

라우트를 작성시 특정 경로에 미들웨어를 등록할 때는 다음과 같이 두번째 인자에 함수를 선언해서 바로 넣을 수 있습니다.

 

router.get('/', ctx => {

});

 

하지만 각 라우트 처리 함수의 코드가 길면 라우터 설정을 한눈에 보기 어렵습니다. 이에 라우트 처리 함수들을 다른 파일로 따로 분리하여 관리 할 수 있는데 이렇게 라우트 처리 함수만 모아 놓은 파일컨트롤러 라고 합니다.

 

아직 데이터베이스 없이 자바스크립트의 배열 기능을 사용하여 임시로 기능을 구현해 봅니다.

 

API 기능을 본격적으로 구현하기 전에 koa-bodyparser 미들웨어를 적용해야 합니다.

이 미들웨어는 POST/PUT/PATCH 같은 메서드의 Request Body에 JSON 형식으로 데이터를 넣어주면 이를 파싱하여 서버에서 사용할 수 있게 합니다.

 

$ yarn add koa-bodyparser

 

미들웨어 적용은 router 적용하는 코드의 윗부분에서 해야 합니다.

src>index.js 에 bodyparser를 적용합니다.

const Koa = require('koa');
const Router = require('koa-router');
const bodyParser = require('koa-bodyparser');

const api = require('./api');

const app = new Koa();
const router = new Router();

// 라우터 설정
router.use('/api', api.routes()); // api 라우트 적용

// 라우터 적용 전에 bodyparser 적용
app.use(bodyParser());

// app 인스턴스에 라우터 적용
app.use(router.routes()).use(router.allowedMethods());

app.listen(4000, () => {
  console.log('Listening to port 4000');
});

그리고 posts 경로에 posts.ctrl.js 파일을 다음과 같이 만듭니다.

let postId = 1; // id의 초깃값입니다.

// posts 배열 초기 데이터
const posts = [
  {
    id: 1,
    title: '제목',
    body: '내용',
  },
];

/* 포스트 작성
POST /api/posts
{ title, body }
*/
exports.write = (ctx) => {
  // REST API 의 Request Body는 ctx.request.body에서 조회할 수 있습니다.
  const { title, body } = ctx.request.body;
  postId += 1; // 기존 postId 값에 1을 더합니다.
  const post = { id: postId, title, body };
  posts.push(post);
  ctx.body = post;
};

/* 포스트 작성
POST /api/posts
{title, body}
*/
exports.list = (ctx) => {
  ctx.body = posts;
};

/* 특정 포스트 조회
GET /api/posts/:id
*/
exports.read = (ctx) => {
  const { id } = ctx.params;
  // 주어진 id 값으로 포스트를 찾습니다.
  // 파라미터로 받아 온 값은 문자열 형식이므로 파라미터를 숫자로 변환하거나
  // 비교할 p.id 값을 문자열로 변경해야 합니다.
  const post = posts.find((p) => p.id.toString() === id);
  // 포스트가 없으면 오류를 반환합니다.
  if (!post) {
    ctx.status = 404;
    ctx.body = {
      message: '포스트가 존재하지 않습니다.',
    };
    return;
  }
  ctx.body = post;
};

/* 특정 포스트 제거
DELETE /api/posts/:id
*/
exports.remove = (ctx) => {
  const { id } = ctx.params;
  // 해당 id를 가진 post가 몇 번째인지 확인합니다.
  const index = posts.findIndex((p) => p.id.toString() === id);
  // 포스트가 없으면 오류를 반환합니다.
  if (index === -1) {
    ctx.status = 404;
    ctx.body = {
      message: '포스트가 존재하지 않습니다.',
    };
    return;
  }
  // index번째 아이템을 제거합니다.
  posts.splice(index, 1);
  ctx.status = 204; // No content
};

/* 포스트 수정(교체)
PUT /api/posts/:id
{ title, body }
*/
exports.replace = (ctx) => {
  // PUT 메서드는 전체 포스트 정보를 입력하여 데이터를 통째로 교체할 때 사용합니다.
  const { id } = ctx.params;
  // 해당 id를 가진 post가 몇번째인지 확인합니다.
  const index = posts.findIndex((p) => p.id.toString() === id);
  // 포스트가 없으면 오류를 반환합니다.
  if (index === -1) {
    ctx.status = 404;
    ctx.body = {
      message: '포스트가 존재하지 않습니다.',
    };
    return;
  }
  // 전체 객체를 덮어 씌웁니다.
  // 따라서 id를 제외한 정보를 날리고, 객체를 새로 만듭니다.
  posts[index] = {
    id,
    ...ctx.request.body,
  };
  ctx.body = posts[index];
};

/* 포스트 수정(특정 필드 변경)
PATCH /api/posts/:id
{ title, body }
*/
exports.update = (ctx) => {
  // PATCH 메서드는 주어진 필드만 교체합니다.
  const { id } = ctx.params;
  // 해당 id를 가진 post가 몇번째인지 확인합니다.
  const index = posts.findIndex((p) => p.id.toString() === id);
  // 포스트가 없으면 오류를 반환합니다.
  if (index === -1) {
    ctx.status = 404;
    ctx.body = {
      message: '포스트가 존재하지 않습니다.',
    };
    return;
  }
  // 기존 값에 정보를 덮어 씌웁니다.
  posts[index] = {
    ...posts[index],
    ...ctx.request.body,
  };
  ctx.body = posts[index];
};

컨트롤러를 만들면서 exports.이름 = ...  형식으로 함수를 내보내 줍니다.

이렇게 내보낸 코드는 다음 형식으로 불러올 수 있습니다.

 

const 모듈이름 = require('파일이름');

모듈이름.이름( );

 

require('./posts.ctrl') 을 입력하여 방금 만든 posts.ctrl.js 파일을 불러온다면 다음 객체를 불러오게 됩니다.

 

{

write: Function,

list: Function,

read: Function,

remove: Function,

replace: Function,

update: Function,

};

 

컨트롤러 함수들을 한번 각 라우트에 연결해봅니다.

const Router = require('koa-router');
const postsCtrl = require('./posts.ctrl');

const posts = new Router();

posts.get('/', postsCtrl.list);
posts.post('/', postsCtrl.write);
posts.get('/:id', postsCtrl.read);
posts.delete('/:id', postsCtrl.remove);
posts.put('/:id', postsCtrl.replace);
posts.patch('/:id', postsCtrl.update);

module.exports = posts;

list, read, remove 를 제외한 API는 요청할 때 Request Body가 필요합니다.

Postman 에서 어떻게 사용하는지 보겠습니다.

메서드를 POST 로 변경하고 Body 탭을 선택하고 raw 를 JSON 으로 선택하여 데이터를 입력합니다.

Send 버튼을 선택하면 하단에 입력된 결과가 보입니다. 신규 글쓰기시 id 가 2 번으로 등록 됩니다.

Postman - POST 글등록 하기

등록된 post는 GET 메서드로 조회하면 됩니다.

Postman - GET 조회 결과

update와 replace 함수는 용도는 비슷하지만 구현 방식이 다릅니다.

update(PATCH) 는 기존 값은 유지하면서 변경되는 값만 업데이트 되며, replace(PUT)은 id 를 제외한 모든 값을 대체합니다.

 

아래와 같이 post 1번의 title 을 "수정하기" 로 변경하여 비교해봅니다.

PATCH 는 body는 그대로 있고 title 만 변경되고, PUT은 title 만 남고 body 는 삭제됩니다.

Postman 에서 PATCH, PUT 메서드 비교하기

지금까지 REST API 작동방법은 자바스크립트 배열을 사용하여 구현하였는데 이렇게 구현하면 서버를 재시작할 때마다 데이터가 소멸됩니다. 

실제 프로젝트에서는 데이터베이스에 정보를 저장하여 관리하므로 이제 MongoDB 를 사용하여 백엔드를 구현해보겠습니다.

반응형