BE_[Node] 2. Express 초기 환경세팅 가이드_11.1

송철진·2022년 10월 31일
0
post-thumbnail
post-custom-banner

요약

  • Node Express를 사용 시 필요한 npm 패키지(모듈)들을 설치 및 관리할 수 있다
  • npm 패키지(모듈)들의 목적과 기능.
  • 네트워크 통신시 개발자의 수고를 덜어주는 5가지의 기본 패키지:
    [npm] express | nodemon | cors | dotenv | morgan.

1. Express

폴더 생성: mkdir myapp
폴더 진입: cd myapp
package.json파일 생성: npm init -y
package.json파일에서 "main" 파일을 app.js로 수정

설치

$ npm install express

일시적으로만 사용하고 배포용 dependency list에 저장하고 싶지않다면

$ npm install express --no-save

로컬 개발환경에서 쓰고 싶은 패키지들을 관리하고 싶다면

$ npm install express --save-dev

2. nodemon

디렉토리(또는 디렉토리)를 계속 모니터링하고 변경 사항이 있으면 스크립트를 다시 시작하는 패키지

  • Node는 서버에 코드의 수정 사항이 자동으로 반영되지 않음.

설치
: node_modules 하위 디렉토리에 한정되어 설치
-g : system path 전역에 설치 (권장)

$ npm install nodemon     # local dependency install
$ npm install -g nodemon  # global install

package.json 내부의 npm script start 명령어 란에 아래와 같이 새롭게 nodemon을 경유하여 app.js를 실행한다는 의미의 명령어(nodemon app.js)를 추가:

필요 시, devDependency 로 설치한다면

$ npm install --save-dev nodemon

수동으로 서버 종료 없이 재시작: rs
서버 종료: Ctrl + c

3. CORS 설정

서로 다른 도메인에서 운용되는 백엔드/프론트 서버가 현재의 3세대 웹 서비스 환경에서 리소스를 주고 받을 수 있도록 SOP정책을 완화시켜주는 설정

SOP(Same Origin Policy) 정책
동일한 출처의 주체끼리만 서로 통신할 수 있도록 하는 정책

  • 현재의 3세대 웹브라우저에서는 SOP정책에 따라 서로 다른 출처의 http 통신이 막혀있다
  • 보안성 향상의 기본

CORS 설정을 생략하면?
CORS 정책 위반으로 웹 브라우저 차원에서 서버 통신을 막는다!

나중에 읽어보기

설치

$ npm install cors

CORS 요청 설정하기
1. 모든 request에 대해

  1. 단 하나의 route에서만

참고) 기본값

{
  "origin": "*",
  "methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
  "preflightContinue": false,
  "optionsSuccessStatus": 204
}

4. Dotenv 환경변수 관리

1. 설치
npm 패키지 매니저로 dotenv라이브러리를 Node.js 프로젝트에 설치

$ npm install dotenv

2. env 파일 작성
dotenv라이브러리는 기본값으로 현재 디렉토리에 위치한 .env파일로부터 환경 변수를 읽어낸다
👉 .env파일을 생성하고, 필요한 환경 변수를 key-value 형태로 나열한다.

.env 파일에 저장해놓은 환경 변수들을 dotenv 라이브러리를 이용해서 process.env에 설정할 수 있다.

사용법 1. CommonJS에서 환경 변수 불러오기 (require)
애플리케이션을 구동 시, 제일 먼저 실행되는 자바스크립트 파일(ex. app.js, index.js)의 최상위에 dotenv 라이브러리를 임포트한 후 config() 함수를 호출한다

app.js 실행 결과:

ㄴ process.env로 부터 읽어들인 환경 변수가 출력되는 것

dotenv 라이브러리의 config() 함수 호출 전에 process.env를 읽으면?

사용법 2. ES 모듈에서 환경 변수 불러오기 (import)

require 대신에 import 키워드를 사용

왜 undefined 일까?

  • 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_HOST: localhost
DB_USER: root
DB_PASS: s1mpl3
{ db_host: undefined, db_user: undefined, db_pass: undefined }

Solution

  • 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;
  • env.js 👉 dotenv를 별도 파일에서 import, config()함수 호출
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' }

5. Morgan

npm에서 사용되는 로그(log) 관리용 외부 서드파티 모듈/라이브러리

  • 필요성: NodeJS 서버 기반 웹 환경에서는 로깅(네트워크 통신기록) 기능이 기본 제공되지 않으므로.

  • http(s) 통신시 프론트-백엔드간 소통시 필요로 하는 기본 정보들을 자동으로 포매팅하여 편리하게 주고 받을 수 있다.

    • 기본 정보: http 통신시 request, response 형태로 주고 받는
      status code, http version 등의 메타 정보.
  • 내부 속성을 커스터마이징 할 수 있다.

설치

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

로그의 포맷을 선택하거나 지정할 수 있다
ex)

app.use(morgan('combined')); // morgan 사용하기

로그 포맷 5가지

combined
[:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"]

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]

6. 실행 예제

6-1. ping-pong

// app.js
const http = require("http");
const express = require("express");
const cors = require("cors");
const morgan = require("morgan");
const dotenv = require("dotenv");
const {appendFile} =  require("fs")

// 핑퐁을 적극적으로 활용하기 위해 app의 express()메소드를 발동시킬 것이다
app = express();

//app.use는 수많은 패키지를 사용할 수 있게 하는 미들웨어이다
app.use(express.json());
app.use(cors());
app.use(morgan('combined')); // 로깅 패키지 | 옵션: dev, tiny, combined

// dotenv.config(): 환경변수를 활용할 수 있게 하는 메서드
dotenv.config()

// /ping 이라는 타겟 리소스에 요청이 들어오면 pong을 보낸다는 메시지
// health check
app.get("/ping", (req,res) => {
    res.json({ message : "pong" });
})

// 위에 선언한 http로 서버를 열어주어야 한다
const server = http.createServer(app);
//dotenv의 환경변수로 저장된 포트번호를 불러올 것이다
const PORT = process.env.PORT;

const start = async () => {
    // 포트번호에 맞게 서버를 잘 동작시켜 모든 것들을 서버로서 계속 듣고 있겠다
    server.listen(PORT, () => console.log(`Server is listening on ${PORT}`));
}
// start를 실행하겠다
start();

👉 실행 결과
package.json에 "start": "nodemon app.js" 가 잘 입력되어 있기 때문에

npm start 명령어 실행 시 다음과 같이 [nodemon]에 대해 잘 실행된다

하지만 서버에서 PORT번호가 undefined로 process.env.PORT에서 못가져오는 것을 알 수 있음! 이것을 해결하려면 숨김파일 3개를 생성해야 한다.

  • .gitignore : 깃허브 상에 내가 만든 파일이 올라가지 않도록 숨김처리
    ex) 환경변수
  • .env.sample : 환경변수를 누구에게나 보여줄 수 있는 파일
    깃허브에 올라가~ 다른 개발자가 확인해서 환경변수를 어떻게 넣어야 되는구나 알 수 있게 모조값 입력
  • .env : 실제 환경변수를 저장할 파일

ls -al 명령어로 숨김파일도 다 잘 생성됐는지 확인:

데이터 입력하기:

  • .gitignore : 실제환경변수 파일(.env), 불필요한 대량의 파일들(node_modules/)
  • .env.sample : 깃허브에 올려서 다른 개발자가 보고 이해할 수 있는 모조값
  • .env : 내가 실제 적용할 포트 번호

nodemon 기능 활용: cmd 누르고 rs 입력. 서버를 끄지 않고 재실행한다
👉 .env에 입력한 포트 번호 3000을 잘 읽어와 서버에 반영된 것을 확인!

get요청 👉 pong 확인!

morgan() 로깅 옵션에 따른 결과 확인: tiny와 dev는 형태가 유사함

app.use(express.json());
  • json() : 외부에서 요청으로 들어온 내용값에 대해서 그 body데이터를 parsing한다

"난해하게 들어올 수 있었던 데이터구조를 개발자들이 가독성 좋게 구분지어서 깔끔하게 구조화하고 정리해서 터미널이나 코드 화면단에 보여질 수 있게 하는게 express.json()메소드가 가진 숨김기능 중 하나이다
옛날: app.use(bodyParser.json())이라는 별도의 메소드를 써야 했다
express.json이 들어서면서 deprecated됐음(더이상 서비스 제공하지 않음)"

  • cors() : 제 3세대 웹 이후 프론트 백엔드 간 통신이 잘 되도록 엄격한 통신을 완화시켜줌. 패키지 안에 설정된 부분에 한해 통신이 될 수 있다!
    👉 모든 통신 request가 app.use()의 cors()를 경유하여 들어오기 때문에 올바르게 동작되어 response를 쏴줄 수 있게 구조화됨!

특정 api endpoint에만 동작할 수 있도록 cors()를 설정한다면?
👉 app.use(cors())는 주석처리하고, 특정 app.get()의 매개변수로 cors()를 입력하여 다양하게 처리할 수 있다

끝으로..
공식문서를 찾아가며 자신만의 철학을 담아 딥하게 커스터마이징 하자


nodejs는 런타임 환경을 제공
expressjs는 직접적인 웹서비스 기능을 담당


profile
검색하고 기록하며 학습하는 백엔드 개발자
post-custom-banner

0개의 댓글