Node.js 의 koa 프레임워크

리린·2021년 8월 3일
1

koa

목록 보기
1/3

시작하기

  1. 폴더 만들고 package 초기 설정 생성
  • 콘솔
    mkdir blog
    cd blog
    mkdir blog-backend
    cd blog-backend
    yarn init-y
  1. koa 패키지 설치
  • 콘솔
    yarn add koa
  1. ESLint 설정
  • 콘솔
    yarn add --dev eslint
    yarn run eslint --init
    (각종 설정에 잘 대답하기 -타입스크립트 배워야겠다. )
  1. Prettier 만들기
  • 설정 파일 만들기
    (blog-backend/prettierrc)
{
  "singleQuote": true,
  "semi": true,
  "useTabs": false,
  "tabWidth": 2,
  "trailingComma": "all",
  "printWidth": 80
}
  1. ESLint가 prettier에서 관리하는 코드를 제외하도록 설정
  • 콘솔
    yarn add eslint-config-prettier
  • 설정 파일 만들기
    (blog-backend/.eslintrc.json)
{
  "env": {
    "browser": true,
    "commonjs": true,
    "es2021": true
  },
  "extends": ["eslint:recommended", "prettier"],
  "globals": {
    "Atomics": "readOnly",
    "ShareArrayBuffer": "readOnly"
  },
  "parserOptions": {
    "ecmaVersion": 12
  },
  "rules": {}
}
  1. .eslintrc.json
{
  "env": {
    "browser": true,
    "commonjs": true,
    "es2021": true
  },
  "extends": ["eslint:recommended", "prettier"],
  "globals": {
    "Atomics": "readOnly",
    "ShareArrayBuffer": "readOnly"
  },
  "parserOptions": {
    "ecmaVersion": 12
  },
  "rules": {
    "no-unsued-vars": "warn,
    "no-console": "off"
  }
}
  • console.log 사용을 지양하지만, 예제에서는 console.log를 사용하니까 허용함

서버 띄우기

  1. index.js 만들기
const Koa = require('koa');
const app=new Koa();

//ctx는 요청과 응답에 관한 정보를 담음. 
//next는 현재 처리 중인 미들웨어의 다음 미들웨어를 호출하는 함수 

app.use(async (ctx, next)=>{
    console.log(ctx.url);
    console.log(1);
    if(ctx.query.authorized!=='1'){
        ctx.status=401;
        return ; 
    }
    await 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');
})


tip. ctx 객체(미들웨어 함수의 첫 번째 인자)의 생김새

{
  request: {
    method: 'GET',
    url: '/favicon.ico',
    header: {
      host: 'localhost:4000',
      connection: 'keep-alive',
      pragma: 'no-cache',
      'cache-control': 'no-cache',
      'sec-ch-ua': '"Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92"',
      'sec-ch-ua-mobile': '?0',
      'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36',
      accept: 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8',
      'sec-fetch-site': 'same-origin',
      'sec-fetch-mode': 'no-cors',
      'sec-fetch-dest': 'image',
      referer: 'http://localhost:4000/',
      'accept-encoding': 'gzip, deflate, br',
      'accept-language': 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7'
    }
  },
  response: {
    status: 404,
    message: 'Not Found',
    header: [Object: null prototype] {}
  },
  app: { subdomainOffset: 2, proxy: false, env: 'development' },
  originalUrl: '/favicon.ico',
  req: '<original node req>',
  res: '<original node res>',
  socket: '<original node socket>'
}
  • ctx.body 의 생김새
{
    "method": "DELETE",
    "path": "/api/posts/3",
    "params": {
        "id": "3"
    }
}
  1. nodemon 사용하기
  • 콘솔설치
    yarn add --dev nodemon
  • script 추가
{
  "name": "blog-backend",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "eslint-config-prettier": "^8.3.0",
    "koa": "^2.13.1"
  },
  "devDependencies": {
    "eslint": "^7.32.0",
    "nodemon": "^2.0.12"
  }, 
  "scripts": {
    "start": "node src",
    "start:dev": "nodemon --watch src/src/index.js"
  }
}

router 만들기

  1. koa-router 사용하기
  • koa에는 기능 내장되어있지 않으므로 별도 설치해야 함
  • 콘솔 설치
    yarn add koa-router
  • 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');
})
  1. 라우트 파라미터와 쿼리
  • ctx.params
    /about/:name? 형식으로 설정한 경우
    const {name} = ctx.params 로 찾기 가능
  • ctx.query
    /posts/?id=10 형식으로 설정한 경우
    const {id} = ctx.query 로 찾기 가능
  • 예제
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;
    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');
})
  1. 라우터 쪼개기
  • src/api/index.js
const Router = require('koa-router');
const api = new Router ();
api.get('/test', ctx=>{
    ctx.body='test 성공 '
});

//라우터를 내보낸다. 
module.exports=api;

  • index.js
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());

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

app.listen(4000, ()=>{
    console.log('Listening to port 4000');
})
  1. rest api 요청 테스트하기

controller 만들기

  1. bodyparser 설치하기
  • 목저: request Body에 json 형식으로 데이터를 넣어주면 이를 파싱하여 서버에서 사용 가능하게 함

  • 콘솔
    yarn add koa-bodyparser

  1. 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());

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

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

app.listen(4000, ()=>{
    console.log('Listening to port 4000');
})
  1. src/api/posts.ctrl.js 생성
let postId = 1;
//posts 배열 초기 데이터 
const posts = [
    { 
        id: 1, 
        title: '제목', 
        body: '내용'
    }
]

/* 포스트 작성 
POST /api/posts
{title, body}
*/

exports.write = ctx=>{
    const {title, body}=ctx.request.body;
    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; 
    }
    posts.splice(index, 1);
    ctx.status=204;
}

/* 포스트 수정 (교체 ) 
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]
}
  • 다음과 같이 사용할 수 있다.
    const 모듈이름 = require('파일이름');
    모듈이름.이름();

  • src/api/posts/index.js

const Router = require('koa-router');
const postsCtrl = require('./posts.ctrl')
const post = 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;
profile
개발자지망생

0개의 댓글