koa-router 사용
Koa를 사용할 때에도 라우트 작업을 해줘야 하는데,
Koa에는 라우터 기능이 내장되어 있지 않기에 koa-router 모듈을 설치해야 한다.
npm i koa-router
1. 기본 사용법
index.js에서 라우터를 불러와 적용하는 방법이다.
const Koa = require('koa');
const Router = require('koa-router');
const app = new Koa();
const router = new Router();
// 라우터 설정
router.get('/', ctx => {
ctx.body = '홈';
});
router.get('/about', ctx => {
ctx.body = '소개';
});
// app 인스턴스에 라우터 적용
app.use(router.routes()).use(router.allowedMethods());
// 서버 포트 설정
app.listen(4000, () => {
console.log('Listening to port 4000');
});
koa-router를 불러온 뒤 이를 사용해 Router 인스턴스를 만들었다.
또한 각각의 경로를 지정하여 보여주는 텍스트 또한 지정했다.
라우트를 설정할 때, router.get의 첫 번째 파라미터는 라우트의 경로를 넣고,
두 번째 파라미터에는 해당 라우트에 적용할 미들웨어 함수를 넣는다.
여시서 get 키워드는 해당 라우트에서 사용할 HTTP 메서드를 의마한다.
(get대신 post, put, delete 등 다양한 키워드를 넣을 수 있다)
http://localhost:4000/와 http://localhost:4000/about 페이지에 들어가 보면 설정한 페이지가 잘 보인다.
2. 라우트 파라미터와 쿼리
라우터의 파라미터를 설정할 때는 콜론(:)을 사용하여 라우트 경로를 지정한다.
또한, 파라미터가 없을 수 도 있다면 끝에 물음표 ? 를 사용한다. ex) /about/:name?
이렇게 설정한 파라미터는 함수의 ctx.params 객체에서 조회할 수 있다.
라우터의 쿼리는 /post/?id=10 같은 형식으로 요청이 됬다면, 해당 값은 ctx.query에서 조회할 수 있다.
쿼리 문자열은 자동으로 객체 행태로 파싱되며 별도로 파싱 함수를 돌릴 필요가 없다.
(문자열 형태의 쿼리 문자열을 조회해야 할 때는 ctx.querystring을 사용한다)
const Koa = require('koa');
const Router = require('koa-router');
const app = new Koa();
const router = new Router();
// 라우터 설정
router.get('/', ctx => {
ctx.body = '홈';
});
// 파라미터 설정
router.get('/about/:name?', ctx => {
const { name } = ctx.params;
// name의 존재 유무에 따라 다른 결과 출력
ctx.body = name ? `${name}의 소개` : '소개';
});
// 쿼리 설정
router.get('/posts', ctx => {
const { id } = ctx.query;
// id의 존재 유무에 따라 다른 결과 출력
ctx.body = id ? `포스트 #${id}` : `포스트 아이디가 없습니다.`;
});
// app 인스턴스에 라우터 적용
app.use(router.routes()).use(router.allowedMethods());
// 서버 포트 설정
app.listen(4000, () => {
console.log('Listening to port 4000');
});
파라미터와 쿼리는 둘 다 주소를 통해 측정 값을 받아 올 때 사용하지만,용도가 서로 조금씩 다르다.
일반적으로 파라미터는 처리할 작업의 카테고리를 받아 오거나,고유 ID 혹은 이름으로 측정 데이터를 조회할 때 사용한다.
쿼리는 옵션에 관련된 정보를 받아온다
예를 들어 여러 항목을 리스팅하는 API라면, 어떤 조건을 만족하는 항목을 보여줄지 또는
어떤 기준으로 정렬할지를 정해야 할 때 쿼리를 사용한다.
3. REST API
웹 애플리케이션을 만들려면 데이터 베이스에 정보를 입력하고 읽어와야 한다.
하지만, 데이터 베이스에 직접적으로 접속하게 되면 보안상 문제가 되므로
REST API를 만들어서 사용한다.
REST API는 요청 종류에 따라 다른 HTTP 메서드를 사용한다.
메서드 | 설명 |
GET | 데이터를 조회할 때 사용 |
POST | 데이터를 등록할 때 사용. 인증 작업을 거칠 때 사용하기도 함 |
DELETE | 데이터를 지울 때 사용 |
PUT | 데이터를 새 정보로 통때로 교체할 때 사용 |
PATCH | 데이터의 특정 필드를 수정할 때 사용 |
REST API를 설계할 때는 API 주소와 메서드에 따라 어떤 역할을 하는지 쉽게 파악할 수 있도록 작성해야 한다.
4. 라우트 모듈화
많은 라우터를 한곳에 작성해 관리하면 코드가 길어지고 유지 보수하기 힘들어진다.
이때는 라우터를 여러 파일에 분리시켜서 작성하고, 이를 불러와 적용해보자
src/api/index.js
const Router = require('koa-router');
const api = new Router();
api.get('/test', ctx => {
ctx.body = 'test 성공';
});
module.exports = api;
모듈화 한 라우터를 적용시켜보자
const Koa = require('koa');
const Router = require('koa-router');
const api = require('./api');
const app = new Koa();
const router = new Router();
// 라우터 설정
router.use('/api', api.routes()); // api 라우트 적용
// app 인스턴스에 라우터 적용
app.use(router.routes()).use(router.allowedMethods());
// 서버 포트 설정
app.listen(4000, () => {
console.log('Listening to port 4000');
});
5. posts 라우트 생성
api 디렉터리 내부에 posts 라우트르르 만들어 보자
const Router = require('koa-router');
const api = new Router();
const printInfo = ctx => {
ctx.body = {
method: ctx.method,
path: ctx.path,
params: ctx.params
};
};
posts.get('/', printInfo);
posts.post('/', printInfo);
posts.get('/:id', printInfo);
posts.delete('/:id', printInfo);
posts.put('/:id', printInfo);
posts.patch('/:id', printInfo);
module.exports = posts;
posts 라우트에 여러 종류의 라우트를 설정한 후 모든 printInfo 함수를 호출하도록 설정했다.
이 객체에는 현재 요청의 메서드, 경로, 파라미터를 담았다.
이제 연결해보자 src/api/index.js
const Router = require('koa-router');
const posts = require('./posts');
const api = new Router();
api.use('/posts', posts.routes());
module.exports = api;
http://localhost:4000/api/posts 웹 브라우저를 가보면 잘 나타난다.
이때 우리가 만든 API를 JS로 호출하는 대신
REST API 요청 테스팅을 쉽게할 수 있는 Postman 이라는 프로그램을 사용해 보자
이제는 컨트롤러 파일을 작성해보자
라우트를 작성하는 과정에서 특정 경로에 미들웨어를 등록할 때는 다음과 같이
두 번째 인자에 함수를 선언해서 바로 넣어 줄 수 있다.
router.get('/', ctx => {
});
하지만, 각 라우트 처리 함수의 코드가 길면 가독성이 좋지 않다.
그렇기에 라우트 처리 함수들을 다른 파일로 따로 분리해서 관리할 수있다.
이 라우트 처리 함수만 모아 놓은 파일을 컨트롤러라 한다.
API 기능을 본격적으로 구현하기 전에 koa-bodyparser 미들웨어를 적용해야 한다.
이 미들웨어는 POST/PUT/PATCH 같은 메서드의 Request Body에 JSON 형식으로 데이터를 넣어 주면,
이를 파싱하여 서버에서 사용할 수 있게 한다.
우선 설치를 해보자.
npm i koa-bodyparser
그리고 미들웨어를 불러와 적용해보자. src/index.js
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;
};
/* 포스트 목록 조회
GET /api/posts
*/
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/psts/:id
*/
exports.remove = ctx => {
const { id } = ctx.params;
// 해당 id를 가진 post가 몇번째 인지 확인
const index = posts.findIndex(p => p.id.toString() === id)
// 포스트가 없다면 오류 반환
if (index === -1) {
ctx.statue = 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('파일이름');
모듈이름.이름();
이제 만든 컨트롤러 함수들을 라우트에 연결해 보자
const Router = require('koa-router');
const postsCtrl = require('./posts.ctrl');
const posts = new Router();
const printInfo = ctx => {
ctx.body = {
method: ctx.method,
path: ctx.path,
params: ctx.params,
};
};
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;
이제 Postman에서 Body 탭을 누른 뒤 raw 옵션에서 데이터 타입을 JSON으로 설정한 뒤
{
"title": "테스팅",
"body": "테스팅"
}
JSON을 입력 후 PUT, DELETE, PATCH등과 같은 명령을 해보자.
'React' 카테고리의 다른 글
React) 로그인 기능 구현 (완) (1) | 2022.12.13 |
---|---|
React) 로그인 구현 1 단계 (0) | 2022.11.15 |
React) 21장 백엔드 프로그래밍: nodemon 사용하기 (0) | 2022.07.07 |
React) 21장 백엔드 프로그래밍: Koa 1 (0) | 2022.07.06 |
React) React 18의 SSR이 가능해진 React.lazy와 Suspense (0) | 2022.06.03 |