무언가를 배우는 가장 좋은 방법은 직접 해보는 겁니다. Node.js도 마찬가지겠죠? Node.js를 배우기 위해서는 Node.js를 직접 설치해 보고, 관련된 서비스를 직접 만들어보는 것이 가장 좋은 방법일겁니다.
우선 Node.js에 대해서는 이전의 ‘Node.js 설치 및 NPM 사용 가이드‘란 제목의 포스팅에서 비교적 자세히 설명해 두었습니다. 이번 글에서는 바로 Node.js를 이용한 API 서버를 만들어보도록 하겠습니다.
Node.js API 프로젝트 준비하기
express-generator 설치하기
express-generator는 프로젝트를 사용자가 손쉽게 생성할 수 있게 도와주는 웹 애플리케이션 프레임워크인데, 다음의 명령어로 설치할 수 있습니다.
npm install -g express-generator
프로젝트 생성하기
express-generator를 설치했다면 API 서버를 만들기 위한 프로젝트를 생성해줘야 합니다. 새로운 프로젝트는 다음과 같이 express {프로젝트 명}
의 명령어로 생성할 수 있습니다.
express node-api
프로젝트 모듈 설치하기
프로젝트를 생성한 후에는 프로젝트에 필요한 모듈을 설치해야 합니다. 프로젝트 모듈을 설치하려면 우선 생성된 프로젝트 폴더로 이동한 후 npm install 명령어를 입력해 주면 됩니다.
cd node-api
npm install
만약 모듈을 설치하는 과정에서 ‘npm WARN deprecated’와 같은 경고 메세지가 나온다면 다음의 명령어를 입력해주면 됩니다.
npm audit fix
서버 구동하기
프로젝트의 모듈을 모두 설치하고 나면 서버를 구동할 수 있는 환경이 구성되는데, npm start 명령어로 서버를 구동하고 테스트 웹페이지를 브라우저에 띄울 수 있습니다.
npm start
서버가 구동된 후에는 http://localhost:3000
과 같이 3000번 포트를 통해 웹페이지에 접근할 수 있습니다.
Express 프로젝트의 구조
express를 통해 프로젝트를 생성하면 위와 같은 구조로 프로젝트의 폴더가 생성되는데, 각각의 폴더와 파일의 역할은 다음과 같습니다.
- bin/www
- 포트 번호 등 웹 서버 구축에 관한 설정 정보가 정의되어 있는 파일
- node_modules
- Node.js의 모듈이 설치되는 폴더
- public
- 자바스크립트, 이미지, css 등 정적 파일을 위한 폴더
- routes
- 라우팅 리소스 별로 모듈을 만들어 라우팅 로직을 구현할 수 있으며, 클라이언트에서 요청 별로 어떤 로직을 수행할지의 기능을 정해놓은 파일로 자바에서의 controller와 같은 역할을 함
- views
request
요청에 대한 로직을 처리한 후 클라이언트에 응답을 보낼 때html
코드로 변환해서 반환하는 파일을 정의한 폴더- app.js
- express의 설정 정보가 담겨있는 파일
- package.json
- 프로그램의 이름, 버전, 모듈 등에 대한 정보를 기술해 둔 파일로
install
시 package.json을 참조하여 모듈을 설치
라우터
routes/index.js 파일을 열어보면 다음과 같이 /로 접근하는 경우에 보여주는 화면을 res.render
에서 정의하고 있는 것을 확인할 수 있는데, index
란 바로 /views/index.jade 파일을 가리킵니다.
var express = require('express'); var router = express.Router(); /* GET home page. */ router.get('/', function(req, res, next) { res.render('index', { title: 'Express' }); }); module.exports = router;
라우터 페이지 추가하기
라우터에 새로운 페이지를 추가하는 경우에는 get 방식이나 post 방식으로 설정할 수 있는데, get 방식의 경우에는 router.get
메서드를, post 방식의 경우에는 router.post
메서드를 사용합니다.
두 방식은 모두 status()
와 json()
메서드를 사용하는데, status()
의 괄호 안에는 응답하고자 하는 HTTP 상태 코드를 입력하고, json()
의 괄호 안에는 응답하고자 하는 json 형식의 데이터를 입력합니다.
router.get('/api/get/demo', function(req, res) { res.status(200).json({ "message": "call get api demo" }) });
router.post('/api/post/demo', function(req, res) { res.status(200).json({ "message": "call post api demo" }); });
라우터를 추가하면 구동 중인 서버를 종료하고 재시작을 해야 하는데, 화면단의 파일들은 수정이 바로 적용되어 확인이 가능하지만, 서버단의 소스는 구동 중인 시스템을 재시작해야 추가한 설정 내용이 반영됩니다
서버를 재시작하고 http://localhost:3000/api/get/demo
로 접속해 보면 다음과 같은 json 메세지를 확인할 수 있습니다.
{"message":"call get api demo"}
post 방식의 경우에는 Postman이라는 서비스를 통해 간단하게 확인해 볼 수 있습니다.
Mysql 연동하기
Node.js은 MySQL과 연동할 수 있는 모듈을 제공해주는데, MySQL 모듈을 사용하기 위해서는 MariaDB를 설치해야 합니다.
MariaDB란 오픈 소스인 관계형 데이터베이스 관리 시스템으로, MySQL과 동일한 소스 코드를 기반으로 하고 있고, GPL v2 라이센스를 따르고 있습니다.
여담이지만 현재 MySQL은 오라클의 소유로 라이센스의 상태가 불확실한 것이 가장 큰 단점으로 꼽히고 있기 때문에, 여기에 반발해 만든 것이 MariaDB이고 기본적으로 MySQL과 소스코드를 공유하고 있는 만큼 사용방법과 구조가 동일합니다.
MariaDB는 공식 홈페이지에 접속하면 다운로드할 수 있는데, 버전과 OS, 시스템 종류, 패키지 등을 설정한 다음 다운로드 받은 msi 파일을 실행하면 자동으로 설치가 되고, MariaDB를 설치한 후에는 다음의 명령어로 mysql 모듈을 설치해 주면 됩니다.
npm install mysql --save
mysql 모듈을 설치한 후에는 package.json 파일에 다음과 같이 mysql 모듈이 추가되어 있는 것을 확인할 수 있습니다.
{ "name": "node-api", "version": "0.0.0", "private": true, "scripts": { "start": "node ./bin/www" }, "dependencies": { "cookie-parser": "~1.4.4", "debug": "~2.6.9", "express": "~4.16.1", "http-errors": "~1.6.3", "jade": "~1.11.0", "morgan": "~1.9.1", "mysql": "^2.18.1" } }
MySQL 연동하기
우선 Node.js와 MySQL 연동을 위해 /database/란 폴더를 만들고 이 폴더에 db_connect.js란 파일을 생성 한 후 다음과 같이 접속 정보를 추가해 주세요.
const db = require('mysql'); const conn = db.createConnection({ host: 'localhost', port: 3306, user: 'user', password: 'password', database: 'db_name' }); module.exports = conn;
다음으로 app.js 파일에 다음과 같이 var app = express();
코드의 아래에 connect를 위한 코드를 추가해주면 됩니다.
const db = require('./database/db_connect'); db.connect();
CRUD 테스트
MySQL 연동 작업을 완료했다면 CRUD 테스트를 위해 router.get
으로 URL을 맵핑해 주면 되는데, CRUD란 대부분의 컴퓨터 소프트웨어가 가지는 기본적인 데이터 처리 기능인 생성, 읽기, 갱신, 삭제를 일컫는 말입니다.
CRUD 테스트를 위해서는 create, drop, insert, select, update, delete의 총 6개의 URL을 맵핑하는데 각각의 맵핑 URL은 데이터베이스 쿼리를 통해 작업을 수행하고, 작업의 수행 결과를 json 형태의 데이터로 반환해 주는 간단한 API 서버의 역할을 수행 할 수 있습니다.
우선 데이터베이스 쿼리를 처리할 수 있도록 다음과 같이 데이터베이스와 연결을 해주고, 각각의 URL에 대한 DB 쿼리를 만들어 주면 됩니다.
const db = require('../database/db_connect');
// create router.get('/create', function(req, res) { db.query('CREATE TABLE DEPARTMENT (DEPART_CODE INT(11) NOT NULL, NAME VARCHAR(200) NULL DEFAULT NULL COLLATE utf8mb4_general_ci, PRIMARY KEY (DEPART_CODE) USING BTREE)', function(err, rows, fields) { if(!err) { res.send(rows); // response send rows } else { console.log('err : ' + err); res.send(err); // response send err } }); });
// drop router.get('/drop', function(req, res) { db.query('DROP TABLE DEPARTMENT', function(err, rows, fields) { if(!err) { res.send(rows); // response send rows } else { console.log('err : ' + err); res.send(err); // response send err } }); });
// insert router.get('/insert', function(req, res) { db.query('INSERT INTO DEPARTMENT(DEPART_CODE, NAME) VALUES(5001, "ENGLISH")', function(err, rows, fields) { if(!err) { res.send(rows); // response send rows } else { console.log('err : ' + err); res.send(err); // response send err } }); });
// select router.get('/select', function(req, res) { db.query('SELECT * FROM DEPARTMENT', function(err, rows, fields) { if(!err) { res.send(rows); // response send rows } else { console.log('err : ' + err); res.send(err); // response send err } }); });
// update router.get('/update', function(req, res) { db.query('UPDATE DEPARTMENT SET NAME="UPD ENG" WHERE DEPART_CODE=5001', function(err, rows, fields) { if(!err) { res.send(rows); // response send rows } else { console.log('err : ' + err); res.send(err); // response send err } }); });
// delete router.get('/delete', function(req, res) { db.query('DELETE FROM DEPARTMENT WHERE DEPART_CODE=5001', function(err, rows, fields) { if(!err) { res.send(rows); // response send rows } else { console.log('err : ' + err); res.send(err); // response send err } }); });
위와 같이 각각의 URL에 데이터베이스 쿼리를 추가하고 결과를 반환해주는 코드를 입력하면 기본적인 API 서버로 동작시킬 수 있는데, /routes/index.js의 전체 코드는 다음과 같습니다.
var express = require('express'); var router = express.Router(); /* GET home page. */ router.get('/', function(req, res, next) { res.render('index', { title: 'Express' }); }); // require db_connect.js const db = require('../database/db_connect'); // create router.get('/create', function(req, res) { db.query('CREATE TABLE DEPARTMENT (DEPART_CODE INT(11) NOT NULL, NAME VARCHAR(200) NULL DEFAULT NULL COLLATE utf8mb4_general_ci, PRIMARY KEY (DEPART_CODE) USING BTREE)', function(err, rows, fields) { if(!err) { res.send(rows); // response send rows } else { console.log('err : ' + err); res.send(err); // response send err } }); }); // drop router.get('/drop', function(req, res) { db.query('DROP TABLE DEPARTMENT', function(err, rows, fields) { if(!err) { res.send(rows); // response send rows } else { console.log('err : ' + err); res.send(err); // response send err } }); }); // insert router.get('/insert', function(req, res) { db.query('INSERT INTO DEPARTMENT(DEPART_CODE, NAME) VALUES(5001, "ENGLISH")', function(err, rows, fields) { if(!err) { res.send(rows); // response send rows } else { console.log('err : ' + err); res.send(err); // response send err } }); }); // select router.get('/select', function(req, res) { db.query('SELECT * FROM DEPARTMENT', function(err, rows, fields) { if(!err) { res.send(rows); // response send rows } else { console.log('err : ' + err); res.send(err); // response send err } }); }); // update router.get('/update', function(req, res) { db.query('UPDATE DEPARTMENT SET NAME="UPD ENG" WHERE DEPART_CODE=5001', function(err, rows, fields) { if(!err) { res.send(rows); // response send rows } else { console.log('err : ' + err); res.send(err); // response send err } }); }); // delete router.get('/delete', function(req, res) { db.query('DELETE FROM DEPARTMENT WHERE DEPART_CODE=5001', function(err, rows, fields) { if(!err) { res.send(rows); // response send rows } else { console.log('err : ' + err); res.send(err); // response send err } }); }); module.exports = router;
결과 확인하기
URL 맵핑 작업이 끝났다면 서버측 코드를 수정한 만큼, Node.js 서버를 재시작해주어야 새로 맵핑한 주소로 접속할 수 있습니다.
npm start
서버를 재시작 한 후에는 다음과 같이 각각의 URL로 접속하여 그 결과를 확인할 수 있습니다.