프로젝트를 진행할 폴더를 만들고 해당 경로로 진입.
$ mkdir myapp
$ cd myapp
아래의 npm init -y
명령어를 사용하여 작업을 의도한 어플리케이션에 package.json
파일을 생성. 뒤에 붙는 -y
명령어를 통해 디폴트 값으로 제공하는 기본 설정 값을 남겨둔다.
$ npm init -y
만일 뒤에 붙는 -y
명령어를 생략하게되면 다양한 내용들을 입력하도록 요구하는데(예시; 이름, 어플리케이션 버젼 등), 우선 엔터를 치면서 디폴트 내용을 저장하면 위 내용과 같은 결과가 나온다. 기본적인 디폴트 내용의 최종 내용은 다음 package.json
상에 기록되며, 추후에 언제든지 원하는 내용을 추가 및 수정할 수 있다. 가장 메인이 되는 파일의 명칭은 어떠한 내용이 되어도 상관이 없다.
// package.json
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
다음으로 npm 명령어로 express를 설치한다. 배포용으로 쓰일 패키지임을 명시하는 package.json
파일 내 “dependency list”에 자동으로 Express항목과 version이 명시됨을 확인하자.
$ npm i express
Express를 일시적으로만 사용하고 배포용 dependency list에 저장하고 싶지 않는다면 아래의 명령어를 입력.
$ npm i express --no-save
dependencies가 아닌 로컬 개발환경에서 구동한다면(devDependencies) 아래의 명령어를 입력.
$ npm install express --save-dev
Node에서는 코드에서 수정이 일어났을 때 코드의 수정 사항이 서버에 자동으로 반영되지 않는다. 즉, 코드를 수정하고나면 서버를 계속해서 재가동 해주어야 한다. 이를 보완하기 위해 nodemon
패키지를 이용한다.
g
를 붙임으로써 global 변수로 nodemon을 설치할 수 있다. 아래 명령어를 통해 nodemon 패키지를 system path 전역으로 설치할 수 있습니다. g
를 붙이지 않고 설치하는 local 설치와의 차이점은, local 설치는 node_modules 하위 디렉토리에 한정되어 설치가 이루어진다는 점이다.$ npm install nodemon # local dependency install
$ npm install -g nodemon # global install
**package.json
내부의 npm script start 명령어 란에 아래와 같이 새롭게 nodemon을 경유하여 app.js를 실행한다는 의미의 명령어nodemon app.js
를 추가한다. 이제 간단히 npm start
** 명령어 만으로 언제든지 nodemon이 제공하는 도움을 받을 수 있다.$ "scripts": {
"start": "nodemon app.js"
}
package.json
내에서 해당 패키지가 dependency | devDependency 중 어디에 포함되어 적용되었는지를 확인.$ npm install --save-dev nodemon # local devDependency install
rs
를 입력하는 것이다.현재의 웹 브라우저는 보안상의 이유로 서로 다른 출처의 http 통신을 막도록 기본적으로 세팅되어 있다. 동일한 출처의 주체끼리만 서로 통신할 수 있도록 하는 이 SOP(Same Origin Policy) 정책은 보안성 향상을 위한 기본이다.
하지만 현실적으로 백엔드와 프론트 서버가 서로 다른 도메인에서 운용되는 현재의 3세대 웹 서비스 환경에서, 동일한 출처에서만 리소스를 주고 받을 수 없다. 따라서 이러한 SOP 정책을 올바르게 의도한 요청에 한해서 다소 완화시켜 서로간 통신을 가능케 해야 한다.
이는 별도의 CORS 설정을 통해 서로 다른 두개의 origin/domain 끼리의 데이터를 주고 받게 하기 위한 설정하여 이루어지며, 만일 해당 과정을 생략한다면 CORS 정책 위반을 이유로 웹 브라우저 차원에서 서버 통신을 막는다.
Cors 설정을 위한 npm 설치 CLI 명령어는 아래와 같습니다. 터미널에서 입력하여 설치를 진행한다.
$ npm install cors
const express = require('express')
const cors = require('cors')
const app = express()
app.use(cors())
app.get('/ping', function (req, res, next) {
res.json({message: 'pong'})
})
app.listen(3000, function () {
console.log('server listening on port 3000')
})
const express = require('express')
const cors = require('cors')
const app = express()
app.get('/ping', cors(), function (req, res, next) {
res.json({message: 'pong'})
})
app.listen(3000, function () {
console.log('server listening on port 3000')
})
{
"origin": "*",
"methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
"preflightContinue": false,
"optionsSuccessStatus": 204
}
npm 패키지 매니저를 이용하여 dotenv
라이브러리를 Node.js 프로젝트에 설치한다.
$ npm install dotenv
dotenv
라이브러리는 디폴트로 현재 디렉토리에 위치한 .env
파일로 부터 환경 변수를 읽어낸다. 따라서, .env
파일을 생성하고, 그 안에 필요한 환경 변수를 key-value
의 포멧으로 나열한다.
// .env
DB_HOST=localhost
DB_USER=root
DB_PASS=myPassword
이렇게 .env
파일에 저장해놓은 환경 변수들을 dotenv
라이브러리를 이용해서 process.env
에 설정할 수 있는데, 자신의 프로젝트가 CommonJS 기반인지 ES 모듈 기반인지에 따라 라이브러리 사용법이 상이하므로 나눠서 분석해야 한다.
먼저 Node.js에서 전통적으로 제공해왔던 모듈 시스템인 CommonJS에서 dotenv
라이브러리를 어떻게 사용하는지 알아보자. 애플리케이션을 구동할 때 제일 먼저 실행되는 자바스크립트 파일(ex. app.js
, index.js
)의 최상위에 다음과 같이 dotenv
라이브러리를 임포트한 후 config()
함수를 호출해주기만 하면 된다.
// app.js
require("dotenv").config();
console.log("DB_HOST:", process.env.DB_HOST);
console.log("DB_USER:", process.env.DB_USER);
console.log("DB_PASS:", process.env.DB_PASS);
예를 들어, 위 코드를 실행하면 process.env
로 부터 읽어진 환경 변수가 출력되는 것을 볼 수 있다.
DB_HOST: localhost
DB_USER: root
DB_PASS: s1mpl3
하지만, 같은 파일 내에서 dotenv
라이브러리의 config()
함수를 호출하기 전에 process.env
를 읽으면 안 되니 주의해야 한다. 그렇지 않다면 다음의 내용 처럼 ‘undefined’ 값이 반환된다.
// app.js
console.log("DB_HOST:", process.env.DB_HOST);
console.log("DB_USER:", process.env.DB_USER);
console.log("DB_PASS:", process.env.DB_PASS);
require("dotenv").config();
DB_HOST: undefined
DB_USER: undefined
DB_PASS: undefined
만약 .env
가 아닌 다른 경로에 있는 파일에 환경 변수를 저장해놨다면 config()
함수를 호출 시 path
옵션을 넘기는 방법도 있다. 하지만 현재 프로젝트에서는 발생 가능한 다양한 에러 변수를 최소화하기 위해 .env
에 모든 환경 변수를 관리하도록 했다.
require
대신에 import
키워드를 사용하는 ES 모듈에서는 dotenv
라이브러리를 어떤 방식으로 사용할까. ES 모듈을 사용할 때는 CommonJS를 사용할 때 보다 좀 더 주의가 필요가 있다. 아래 예시를 통해서 흔히 발생하는 문제를 확인할 수 있다.
아래 코드를 보면, dotenv
라이브러리를 제일 먼저 임포트하기 때문에 db.js
파일이 process.env
에 접근할 때 환경 변수가 설정이 되어 있을 것 같다는 생각이 든다.
// db.js
export const db_host = process.env.DB_HOST;
export const db_user = process.env.DB_USER;
export const db_pass = process.env.DB_PASS;
// app.js
import dotenv from "dotenv";
import { db_host, db_user, db_pass } from "./db.js";
dotenv.config();
console.log("DB_HOST:", process.env.DB_HOST);
console.log("DB_USER:", process.env.DB_USER);
console.log("DB_PASS:", process.env.DB_PASS);
console.log({ db_host, db_user, db_pass });
하지만 실제 실행을 해보면 db.js
파일이 process.env
에 접근했을 시점에는 환경 변수가 설정이 되어 있지 않았던 것을 알 수 있다.
DB_HOST: localhost
DB_USER: root
DB_PASS: s1mpl3
{ db_host: undefined, db_user: undefined, db_pass: undefined }
이러한 현상이 발생하는 이유는 dotenv.config()
함수가 db.js
파일이 임포트 된 이후 호출되었기 때문이다. 이 문제를 피하기 위해선 dotenv
라이브러리를 임포트하는 코드를 별도의 파일로 빼 그 속에 dotenv.config()
함수를 호출한다.
// env.js
import dotenv from "dotenv";
dotenv.config();
// app.js
import "./env.js";
import { db_host, db_user, db_pass } from "./db.js";
console.log("DB_HOST:", process.env.DB_HOST);
console.log("DB_USER:", process.env.DB_USER);
console.log("DB_PASS:", process.env.DB_PASS);
console.log({ db_host, db_user, db_pass });
DB_HOST: localhost
DB_USER: root
DB_PASS: s1mpl3
{ db_host: 'localhost', db_user: 'root', db_pass: 'myPassword' }
NodeJS 서버로 구성된 웹 환경에서는 기본적으로 제공되어지는 로깅(네트워크 통신기록) 기능이 없기에, 로그(log)를 관리하기 위해서 외부의 서드파티 모듈/라이브러리를 사용할 것을 권장한다. 그 중 Morgan은 npm 에서 사용되는 로그 관리를 위한 여러 패키지 중 하나이며 많은 개발자들이 사용하고 있다.
Morgan을 사용하면 http(s) 통신시 프론트-백엔드간 소통시 필요로 하는 ‘기본 정보’들을 자동으로 포매팅하여 편리하게 주고 받을 수 있게 된다. 여기서 말하는 ‘기본 정보’란, http 통신시 request, response 형태로 주고 받는 status code
, http version
등의 메타 정보들을 뜻하며, node.js-express 선에서 제공하지 않는 이 기능을 외부의 패키지의 힘을 빌려 사용하게 된 것이다. 참고사항으로, Morgan을 사용할 때 내가 원하는 요소대로 내부 속성을 커스터마이징 하여 설정 할 수도 있다.
morgan을 설치.
$ npm install morgan
express 환경의 앱에서 morgan을 사용하도록 설정.
const express = require('express');
const logger = require('morgan'); // morgan 모듈 추가하기
const app = express();
app.listen(3000, () => { console.log('Running on port 3000');});
로그의 포맷을 아래와 같이 선택하거나 지정할 수 있습니다.
app.use(morgan('combined')); // morgan 사용하기
combined
로그 포맷을 통해 제공되어지는 기본 적인 로그 내용은 다음과 같습니다.
:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"
combined
외에도 다음 4가지의 다양한 포맷 설정이 가능합니다.
// common
[:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length]]
// dev
[:method :url :status :response-time ms - :res[content-length]]
// short
[:remote-addr :remote-user :method :url HTTP/:http-version :status :res[content-length] - :response-time ms]
// tiny
[:method :url :status :res[content-length] - :response-time ms]
참고링크: Morgan 공식문서 페이지