본문 바로가기
C++ 200제/코딩 IT 정보

Node.js Express 로컬 서버 구축(3) JSON 반환 stub API

by vicddory 2020. 3. 5.

시리즈 목록

  1. Node.js Express 로컬 서버 구축(1): npm 도입
  2. Node.js Express 로컬 서버 구축(2): Express 라우팅
  3. Node.js Express 로컬 서버 구축(3): JSON 반환 stub API
  4. Node.js Express 로컬 서버 구축(4) Request 다른 서버 이미지 얻기


요즘은 Json 데이터 송수신이 일반적입니다. 이전 포스트에선 API가 완성되지 않았었는데, 이번엔 로컬 서버에서 JSON을 반환하는 스텁 API 기능을 구현합니다.


sub - IT 용어 사전

글 순서

  • 목적
    • Node.js Express를 이용해 PC 로컬 서버를 시작
  • 포스트 결과
    • GET으로 요청을 보내면, JSON 데이터가 돌아옴
    • POST에서 JSON 데이터를 보내면, 200 OK 응답 코드가 돌아옴
  • 대상자
    • WEB 프런트 담당자
    • HTML, CSS, JavaScript(es2015 포함)의 기본 문법을 이해하는 사람
    • HTTP 통신 GET, POST 등을 어느 정도 이해하는 사람 (대충 알아도 됨)
    • 검은 화면에 명령어 입력하는 게 싫지 않은 사람
  • 환경 버전
    • Windows10
    • Node.js (권장 버전) 10.15.01
    • npm 6.4.1
    • Express 4.16.4
    • Advanced REST client 10.0.12


Chrome 확장 도구 : Advanced REST client

GET과 POST 동작 확인을 위해, Chrome 확장 도구인 "Advanced REST client"를 이용합니다.


Advanced REST client 크롬 다운로드


사용 방법은 아래 사이트를 참고하세요. UI가 단순해 이 포스트에서도 필요할 때마다 설명합니다.


Advanced REST client 다운로드 공식 홈페이지 github


express에서 라우팅 구현

지난번 복습

Node.js Express를 사용한 서버에서 정적 컨텐츠 라우팅을 위해 use 메소드와 express.static 메소드를 이용했습니다.


const express = require('express');
const app = express();

app.listen(8080);

app.use(express.static(path.join(__dirname, 'public')));


use는 모든 유형의 요청(리퀘스트)에서 실행됩니다.


라우팅 기본

GET 요청받음

GET 요청을 받고 싶다면 get 메소드를 이용합니다.


// 사이트 루트에 GET 요청할 경우 app.get('/', (req, res, next)=>{ res.send('루트'); }); // /test/sub에서 GET 요청받으려면 app.get('/hoge/sub', (req, res, next)=>{ res.send('하하하하); });

POST 요청받음

POST 요청을 받고 싶다면 post 메소드를 이용합니다.


// 사이트 루트에 POST 요청할 경우 app.post('/', (req, res, next)=>{ res.send('루트!전원집합!'); }); // /test/sub에서 POST 요청받으려면 app.post('/hoge/fuga', (req, res, next)=>{ res.send('하하하하'); });


경로 (패스 path) 지정

get과 post 두 경우 모두, 첫 번째 인수는 선택하고 싶은 사이트의 경로입니다. 이때, 와일드카드, 정규표현식 등을 결합할 수도 있습니다.


app.get(/^book/, ()=>{});


위의 예에서는 /book, /books에는 매칭되지만 /boo, /ibook과는 매칭하지 않습니다.


공식 가이드 : Express에서의 라우팅


미들웨어 기본

get과 post 두 경우 모두, 두 번째 인수는 요청받을 때 동작할 콜백 함수입니다. 이 콜백 함수는 미들웨어(중간 처리 함수)라고도 합니다.


미들웨어는 리퀘스트(요청) req, 리스폰스(응답) res를 나타내는 객체와 후속 미들웨어로 버튼의 역할을 담당하는 함수 next를 받습니다.


이 미들웨어 안에서 클라이언트에 응답하거나, 명시적으로 프로세스를 종료하거나, next()를 실행하고 다른 곳으로 제어를 넘기지 않으면 응답 없음 상태에 빠집니다.


app.get(/^book/, (req, res, next)=>{

  if(req.query.id){
    res.send('OK.');
  }else{
    next();
  }
});


res.send

클라이언트에 HTTP 응답을 반환하는 메소드입니다.

문자열뿐만 아니라 배열이나 객체도 보낼 수 있습니다. 미리 정의하지 않은 경우, 헤더의 ContentType은 전송 데이터에 따라 자동으로 할당됩니다.


res.end

데이터를 송신하지 않고 응답 프로세스를 종료하기 위한 메서드입니다.

실제론 Node.js의 핵심 모듈인 httpresponse.end입니다. 인수에 데이터를 전달하면 송신되지만, res.send 등의 전용 메서드를 이용하는 것이 바람직합니다.


공식 가이드 : 크롬 응용 프로그램에서 사용하는 미들웨어 만들기


송신 데이터 수신


- GET에서 송신한 URL 매개 변수

GET으로 전송힌 URL 매개 변수를 수신하려면, 미들웨어에 전달된 req 객체의 query 속성에 액세스합니다.


/** * /search?color=red&size=small에 리퀘스크 */ app.get('/search', (req, res, next)=>{ console.log(req.query.color); // "red" console.log(req.query.size); // "small" });



참조 : req.query (영문)

- POST로 전송된 JSON 데이터

POST에서 JSON 데이터를 받으려면 미리 파싱하는 미들웨어를 설정해야 합니다. 이 미들웨어는 Node.js Express에 준비되어 있습니다.


const express = require('express'); const app = express(); app.use(express.json()); // 파서용 미들웨어 설정 app.post((req, res)=>{ console.log(req.body); // 파싱한 데이터 참조 });


Express 정적 메서드로 json 실행 결과를 use 메소드에 전달합니다. 전달은 어디까지나 json 실행 결과로 반환되며, 미들웨어에는 json 메소드 자체가 없습니다. 파싱된 데이터는 request 객체의 body 속성에 저장됩니다.


참조 : express.json (영문)


JSON 데이터 쓰기

- 객체 분석 후 쓰기

객체를 JSON으로 파싱한 후 전송하려면 res.json 메소드를 사용합니다.


app.get('/', (req, res, next)=>{
  res.json({ message: `This is a pen.`});
});


참조 : res.json (영문)



- JSON 파일 쓰기

미리 준비한 JSON 파일을 보낼 때는, res.sendFile 메소드가 편리합니다. 이 함수는 Express 버전 4.8.0 이상에서 지원됩니다.


app.get('/', (req, res, next)=>{
  res.sendFile(__dirname + '/data.json', (err) => {
    if (err) {
      res.sendStatus(400);
    } else {
      console.log('sending completed');
    }
  });
});


첫 번째 인수엔 송신할 파일의 절대 경로를 지정합니다.

두 번째 인수엔 전송 완료 또는 오류가 발생할 때 호출되는 콜백 함수를 지정합니다.

에러 발생 시 오류 정보를 인수로 받습니다. 성공 시 undefined입니다.


참조 : res.sendFile (영문)



route()에서 미들웨어 정리

route 메소드를 이용하면 동일한 경로에 대한 유형별 리퀘스트 정리가 됩니다.


app.route('/moimoi')
  .get((req, res)=>{
    // GET
  })
  .post((req, res)=>{
    // POST
  })
  .put((req, res)=>{
    // PUT
  })
  .delete((req, res)=>{
    // DELETE
  });


참조 : app.route (영문)

Router에서 루팅 처리, 외부 모듈화

라우팅 처리를 다른 파일에 정의하면, 기본 메인 프로세스에서 처리하는 미들웨어로 통합할 수 있습니다.


미들웨어를 정의하고 공개

Node.js Express 정적 메소드 express.Router를 실행하여 라우팅을 위한 미들웨어의 골격을 생성합니다.

이 골격은 "이 경로에 대한 요청 응답 값은 이거다"라는 라우팅 처리 기반이기도 합니다. 내용을 보충할 땐 일반적으로 use, get, post 등을 이용합니다.

완성된 미들웨어를 export 합니다.


/**
 *  /api/index.js
 */
const express = require('express');
const router = express.Router(); // 미들웨어 준비

router.get('/items', (req, res) => {
  res.json({ items: [] });
});

router.post('/registration', (req, res) => {
  res.end('Completed');
});

module.exports = router; // export 공개


공개된 미들웨어 사용

공개된 미들웨어를 가져와 라우팅에 적용합니다.


/**
 * /app.js
 */
const express = require('express');
const app = express();
const api = require('./api/'); // 미들웨어 읽고 넣기

app.use('/api', api);


/api에 대한 요청 대응을 /api/index.js에 정의된 미들웨어에 전달합니다.

이때 미들웨어 내부의 루트 경로는 /api입니다. 미들웨어에서 지정한 /items 실제로 /app/items에 대한 요청(리퀘스트)입니다. 미들웨어에서 /app/items 해버리면 실제로 /app/app/items로 지정한 것이 되어 버립니다.


가이드 : express.Router (한국어)

참조 : express.Router (영문)


API 기능의 구현

위 내용을 고려하여 API 기능을 구현합니다.


파일과 폴더의 준비

API 관련 파일을 저장하는 폴더 api를 추가합니다.

이 폴더 아래에 클라이언트로 보내는 json 데이터와 라우팅 프로세스를 설명하는 js 파일을 만듭니다.


sample/
  ├ public/
  │    ├ css/
  │    │   └ sample.css 
  │    ├ js/
  │    │   └ sample.js 
  │    ├ img/
  │    │   └ sample.png 
  │    └ index.html
  ├ api/
  │    ├ index.js
  │    └ data.json
  └ app.js

/** * /app.js */ const express = require('express'); const app = express(); const path = require('path'); // /api/index.js에서 정의된 미들웨어 const api = require('./api/'); app.listen(8080, () => { console.log('Running at Port 8080...'); }); // API 루팅용 미들웨어를 /api로 설정 app.use('/api', api); app.use(express.static(path.join(__dirname, 'public'))); app.use((req, res) => { res.sendStatus(404); }); /** * /api/index.js */ const express = require('express'); const router = express.Router(); // JSON 파서 router.use(express.json()); // /api/foo 에 GET 리퀘스트 router.get('/foo', (req, res) => { // 파일을 전달 res.sendFile(__dirname + '/data.json', (err) => { if (err) { res.sendStatus(400); } else { console.log('sending completed'); } }); }); // /api/bar 에 GET・POST 리퀘스트 router.route('/bar') .get((req, res) => { // 받은 파라미터 그대로 JSON으로 변환하여 반환함 res.json(req.query); }) .post((req, res) => { // 필수 데이터 항목인 id, name, address를 체크하고 있음 const nameAry = ['id', 'name', 'address'], failed = nameAry.some(v => !req.body[v]); if (failed) { res.sendStatus(400); } else { res.sendStatus(200); } }); module.exports = router;


/api/data.json에 알맞은 내용을 입력합니다.


{
  "id": "W0001",
  "title": "I Love Cats and Dogs",
  "price": 3000000000000
}

준비가 되면 서버를 시작합니다.


$ node app.js



"Advanced REST client (ARC)" 사용해 송수신 테스트

송수신 테스트를 크롬(Chrome) 확장 도구인 "Advanced REST client"에서 실시하면 편리합니다.


여기에서 설치할 수 있습니다.

홈> 애플리케이션> Advanced REST client 다운로드


ARC를 시작하고, 우선 TOP 페이지에 접속해 봅니다.


  1. Method "GET"
  2. RequestURL에 "http://localhost:8080/"
  3. "SEND" 클릭



"200 OK"와 HTML 데이터를 취득했습니다.


그럼, 이어서 API 데이터를 가져옵니다.

GET으로 "http://localhost:8080/api/foo"에 요청을 보내면, /api/data.json을 얻을 수 있습니다.


다음은 GET으로 "http://localhost:8080/api/bar?name=pee&address=poo&age=17"에 요청을 보냅니다.

URL 매개 변수의 값을 JSON으로 얻을 수 있습니다.


다음은 POST로 "http://localhost:8080/api/bar"에 요청을 보냅니다.


  • "Parameters> Body> Body content type"을 "application/json"
  • "Parameters> Body> Editor view"를 "JSON visual editer"
  • id, name, address의 세 속성을 포함한 JSON 데이터 정의



크롬에서 "200 OK"가 돌아오는 걸 확인했습니다.

다음에 항목을 하나 줄여 전송해 보면, "400 Bad Request"가 돌아옵니다.


이제 Node.js Express API 개발이 어느 정도 됐으니, 어떻게든 될 것 같네요!


JSON Server

이 글을 쓰는 도중에, JSON 반환 API를 쉽게 구현하는 "JSON Server"라는 존재를 알았습니다 ...


공식 : GitHub - typicode / json-server



댓글