All Articles

Node.js의 Koa 프레임워크


Koa는 v7 이상부터 사용하는 것을 권장합니다. v7 이상부터는 async/await를 바벨을 이용하여 트랜스파일링하지 않고 바로 실행할 수 있기 때문입니다.


Koa 프레임워크

Node.js 환경에서 웹 서버를 구축할 때는 보통 Express, Hapi, Koa 등 웹 프레임워크를 사용합니다.

현재 웹 프레임워크 중에서 Express가 가장 사용률이 높기는 합니다. 하지만 이 프레임워크는 오픈 소스의 소유권이 IBM 계열사인 StringLoop로 이전되어 유지 보수는 하고 있지만 인지도는 조금씩 잃고 있습니다.

Koa 프레임워크는 Express의 기존 개발 팀이 소유권을 IBM에 넘기기 전부터 개발해 오던 프로젝트로, Express를 리팩토링한 결과물이며, 기존 Express에 비해 아키텍처가 많이 바뀌어서 버전을 높이지 않고 새 이름을 붙였다고 합니다.

Koa는 Express에 비해 훨씬 가볍고, Node v7.6부터 정식으로 지원하는 async/await 문법을 아주 편하게 사용할 수 있습니다. 따라서 콜백을 무수하게 사용하는 콜백 지옥을 겪을 일도 없고, 비동기 작업도 편리하게 관리할 수 있습니다.


프로젝트 생성

$ mkdir blog
$ cd blog
$ mkdir blog-backend
$ cd blog-backend
$ yarn init
$ yarn add koa
$ cat package.json

ESLint 설정

서버 파일을 작성하기 전에 먼저 자바스크립트 문법과 코드 스타일을 검토하는 ESLint 도구를 설치하고 적용하는 방법을 알아보겠습니다.

$ yarn global add eslint
$ eslint -v

eslint -v를 실행했을 때 오류가 발생한다면, npm install -g esling를 실행해 보세요


설치가 끝나면 현재 프로젝트에 적용해 보겠습니다.

$ yarn add eslint
$ eslint --init
ESLint 커스터마이징

.eslintrc.js

module.exports = {
  "extends": "airbnb-base",
  "rules": {
    "no-unused-vars": 1,
    "comma-dangle": 0,
    "eol-last": 0,
    "no-console": 0
  }
};


Koa 기본 사용법

src/index.js

const Koa = require('koa');

const app = new Koa();

app.use((ctx) => {
    ctx.body = 'hello world';
});

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

$ node src 명령어를 실행한 후, http://localhost:4000/ 에 접속하면 hello world가 잘 보입니다.



미들웨어

Koa 애플리케이션은 미들웨어의 배열로 구성되어 있습니다. 앞서 코드에 app.use 함수를 사용했는데, 이 함수는 미들웨어를 애플리케이션에 등록합니다.

app.use 파라미터로 함수가 하나의 미들웨어입니다. Koa의 미들웨어 함수에서는 두 가지 파라미터를 받습니다. 첫 번째는 이 코드에도 나오는 ctx이며, 두 번째는 next입니다.

ctx는 웹 요청과 응답 정보를 지니고 있습니다. 그리고 next는 현재 처리 중인 미들웨어의 다음 미들웨어를 호출하는 함수입니다. 미들웨어를 등록하고 next를 실행하지 않으면 그다음 미들웨어를 처리하지 않습니다.

미들웨어는 app.use로 등록하는 순서대로 처리합니다. 다음과 같이 기록하는 미들웨어 두 개를 기존 미들웨어 위쪽에 넣어 보세요.


next()는 프로미스다

next를 실행하면 프로미스를 반환합니다. 따라서 다음 작업들이 끝나고 난 후 특정 작업을 수행할 수도 있습니다. 한번 첫 번째 미들웨어를 다음과 같이 수정하고, 서버를 재시작한 후 페이지를 새로고침해 보세요.

app.use((ctx, next) => {
  console.log(1);
  next().then(() => {
    console.log('bye');
  });
});

async/await 사용

Koa에서는 async/await를 정식으로 지원하지만, Express는 아직 정식으로 지원하지 않으므로 오류를 처리하는 부분이 제대로 작동하지 않아 편법을 사용해야 합니다.

async/await는 서버에서 매우 유용하게 사용합니다.

특히 데이터베이스에 요청할 때 콜백을 사용할 필요가 없으므로 코드를 깔끔하게 작성할 수 있습니다.

작업이 끝나면 bye라고 콘솔에 기록하는 미들웨어를 async/await를 사용하여 구현해 보겠습니다.

app.use(async(ctx, next) => {
  console.log(1);
  await next();
  console.log('bye');
});


Nodemon 사용

서버 코드를 변경할 때마다 서버를 재시작하는 것이 꽤 번거롭습니다. Nodemon 도구를 사용하면 코드를 변경할 때 서버를 자동으로 재시작합니다.

$ yarn add --dev nodemon

package.json

{
  ...
  "devDependencies": {
    ...
    "nodemon": "^1.19.2"
  },
  "scripts": {
    "start": "node src",
    "start:dev": "nodemon --watch src/ src/index.js"
  }
}

start:dev 스크립트가 실행되면 nodemon도 실행되게 했는데, 이 때 nodemon은 src 디렉터리를 주시하면서 src/index.js 파일을 실행하도록 설정했습니다. 따라서 src 디렉터리 내부의 어떤 파일이 변경된다면 src/index.js 파일이 재시작하는 것입니다.

이제부터는 서버를 시작할 때 다음 명령어로 시작할 수 있습니다.

$ yarn start

  • 앞서 실행한 node src/ 명령어와 동일하게 단순히 서버를 실행시킵니다.

$ yarn start:dev

  • 코드를 변경할 때마다 서버를 재시작시킵니다.

koa-router 사용

리액트에서 웹 브라우저의 라우팅을 돕는 react-router 라이브러리를 사용하듯, Koa를 사용할 때도 다른 주소로 요청이 들어올 때, 다른 작업을 처리할 수 있도록 라우터를 사용해야 합니다. 이 기능은 Koa 자체에 내장되어 있지 않으므로 koa-router 모듈을 설치해 주어야 합니다.

$ yarn add koa-router

src/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');
});


파라미터와 쿼리를 사용하는 라우트
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');
});

http://localhost:4000/about/react http://localhost:4000/posts http://localhost:4000/posts?id=10



REST API

웹 어플리케이션을 만들려면 데이터베이스에 정보를 입력하고 읽어 와야 합니다. 그런데 웹 브라우저에서 데이터베이스에 직접 접속해서 데이터를 변경한다면 보안상 문제가 되겠죠? 그래서 REST API를 만들어서 사용합니다.

클라이언트가 서버에 자신이 데이터를 조회, 생성, 삭제, 업데이트하겠다고 요청하면, 서버는 필요한 로직에 따라 데이터베이스에 접근하여 작업을 처리합니다.

REST API는 요청 종류에 따라 다른 HTTP 메서드를 사용합니다.

  • GET - 데이터를 조회

  • POST - 데이터를 덩록 (인증 작업을 거칠 때도 사용)

  • DELETE - 데이터를 삭제

  • PUT - 데이터를 새 정보로 통째로 교체할 때 사용

  • PATCH - 데이터의 특정 필드를 수정할 때 사용


라우트 모듈화

소스코드 예제



컨트롤러 파일 작성

라우트 처리 함수의 코드 길이가 길다면 라우터 설정을 한눈에 보기 힘들어집니다.

이 라우트 처리 함수들을 따로 다른 파일로 분리해서 관리할 수도 있는데, 이 라우트 처리 함수만 모아 놓은 파일을 컨트롤러라고 합니다. 컨트롤러에서는 백엔드 기능을 구현합니다.

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

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

$ yarn add koa-bodyparser



출처 : 리액트를 다루는 기술