티스토리 뷰
yarn add koa
yarn init -y
cat package.json
yarn add --dev eslint
yarn run eslint --init
yarn add eslint-config-prettier (prettier에서 관리하는 코드 스타일은 eslint에서 관리하지 않도록)
.eslintrc.json
{
"env": {
"browser": true,
"commonjs": true,
"es2021": true,
"node": true
},
"extends": ["eslint:recommended", "prettier"],
"parserOptions": {
"ecmaVersion": 12
},
"rules": {}
}
.prettierrc
{
"singleQuote": true,
"semi": true,
"useTabs": false,
"tabWidth": 2,
"trailingComma": "all",
"printWidth": 80
}
const 선언후 사용하지 않으면 eslint는 오류로 간주, console.log도 막아
이를 막기 위해선
.eslintrc.json에서 rules 두개를 추가해주면 된다.
{
"env": {
"browser": true,
"commonjs": true,
"es2021": true,
"node": true
},
"extends": ["eslint:recommended", "prettier"],
"parserOptions": {
"ecmaVersion": 12
},
"rules": {
"no-unused-vars": "warn",
"no-console": "off"
}
}
Koa 애플리케이션은 미들웨어의 배열로 구성되어 있다.
(ctx, next)=>{}
ctx는 Context의 줄임말. 웹 요청과 응답에 관한 정보
next는 현재 처리 중인 미들웨어의 다음 미들웨어를 호출하는 함수
아래 코드는 http://localhost:4000/?authorized=1 와 나머지 일때 결과가 다르다.
const Koa = require('koa');
const app = new Koa();
app.use((ctx, next) => {
console.log(ctx.url);
console.log(1);
if (ctx.query.authorized !== '1') {
ctx.status = 401; // Unauthorized
return;
}
next();
});
app.use((ctx, next) => {
console.log(2);
next();
});
app.use((ctx) => {
ctx.body = 'hello world';
});
app.listen(4000, () => {
console.log('Listening to port 4000');
});
next 함수는 Promise를 반환
$ node src
Listening to port 4000
/?authorized=1
1
2
END
favicon.ico
1
const Koa = require('koa');
const app = new Koa();
app.use((ctx, next) => {
console.log(ctx.url);
console.log(1);
if (ctx.query.authorized !== '1') {
ctx.status = 401; // Unauthorized
return;
}
next().then(() => {
console.log('END');
});
});
app.use((ctx, next) => {
console.log(2);
next();
});
app.use((ctx) => {
ctx.body = 'hello world';
});
app.listen(4000, () => {
console.log('Listening to port 4000');
});
async/await
app.use(async (ctx, next) => {
console.log(ctx.url);
console.log(1);
if (ctx.query.authorized !== '1') {
ctx.status = 401; // Unauthorized
return;
}
// next().then(() => {
// console.log('END');
// });
await next();
console.log('END');
});
nodemon 사용하기
yarn add --dev nodemon
package.json
"scripts": {
"start": "node src",
"start:dev": "nodemon --watch src/ src/index.js"
}
yarn start : 재시작이 필요 없을 때
yarn start:dev : 재시작이 필요할 때
koa-router 사용하기
yarn add koa-router
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.use(router.routes()).use(router.allowedMethods());
app.listen(4000, () => {
console.log('Listening to port 4000');
});
http://localhost:4000/about/react
http://localhost:4000/posts
http://localhost:4000/posts?id=10
피라미터와 쿼리는 둘 다 주소를 통해 특정 값을 받아 올 때 사용하지만, 용도가 서로 조금씩 다릅니다. 일반적으로 피라미터는 처리할 작업의 카테고리를 받아 오거나, 고유 ID 혹은 이름으로 특정 데이터를 조회할 때 사용합니다. 반면, 쿼리는 옵션에 관련된 정보를 받아 옵니다.
REST API
REST API는 요청 종류에 따라 다른 HTTP 메서드를 사용합니다.
GET : 조회
POST : 등록, 인증
DELETE 지울 때
PUT : 교체할 때
PATCH : 수정할 때
라우트 모듈화
const Router = require('koa-router');
const api = new Router();
api.get('/test', (ctx) => {
ctx.body = 'text 성공';
});
// 라우터를 내보냅니다.
module.exports = api;
router.use('/api', api.routes());
posts 라우트 생성
const Router = require('koa-router');
const posts = 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;
우리가 만든 API를 자바스크립트로 호출하는 대신, 편의상 REST API 요청 테스팅을 쉽게 할 수 있는 Postman이라는 프로그램을 설치해서 사용하겠습니다.
yarn add koa-bodyparser
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/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];
};
api/posts/index.js
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;
'책 > 리다기' 카테고리의 다른 글
리다기 정리14(JST를 통한 회원 인증 시스템 구현하기) (0) | 2021.02.05 |
---|---|
리다기 정리13(몽고디비) (0) | 2021.02.04 |
리다기 정리11(서버 사이드 렌더링) (0) | 2021.01.29 |
리다기 정리10(코드 스플리팅) (0) | 2021.01.28 |
리다기 정리9(리덕스 미들웨어) (0) | 2021.01.27 |