icon안동민 개발노트

Node.js와 Express.js 입문


 Node.js는 Chrome V8 자바스크립트 엔진으로 빌드된 자바스크립트 런타임으로, 서버 사이드 애플리케이션 개발에 사용됩니다.

 Express.js는 Node.js 위에서 동작하는 가장 인기 있는 웹 애플리케이션 프레임워크 중 하나입니다.

Node.js의 특징과 장점

  1. 비동기 I/O : 논블로킹 작업으로 높은 처리량 제공
  2. 이벤트 기반 : 이벤트 루프를 통한 효율적인 리소스 관리
  3. 크로스 플랫폼 : 다양한 운영 체제에서 실행 가능
  4. 넓은 생태계 : npm을 통한 다양한 패키지 사용 가능

Node.js의 비동기, 이벤트 기반 특성

const fs = require('fs');
 
fs.readFile('example.txt', 'utf8', (err, data) => {
  if (err) throw err;
  console.log(data);
});
 
console.log('This comes first!');

 이 예제에서 파일 읽기는 비동기적으로 수행되며, 콜백 함수는 파일 읽기가 완료된 후 실행됩니다.

 이러한 특성은 I/O 집약적인 작업에서 높은 성능을 제공합니다.

npm (Node Package Manager)

 npm은 Node.js의 패키지 관리자로, 다음과 같이 사용합니다.

# 패키지 설치
npm install express
 
# package.json 생성
npm init
 
# 개발 의존성 설치
npm install --save-dev nodemon

Express.js 소개

 Express.js는 미니멀리스트 웹 프레임워크로, 다음과 같은 특징을 가집니다.

  1. 간결하고 유연한 웹 애플리케이션 구조
  2. 미들웨어를 통한 HTTP 요청 처리
  3. 강력한 라우팅 시스템
  4. 템플릿 엔진 지원

 다른 프레임워크(예 : Koa, Hapi)와 비교했을 때, Express는 더 직관적이고 광범위한 커뮤니티 지원을 받고 있습니다.

Express.js 기본 사용법

 서버 설정

const express = require('express');
const app = express();
const port = 3000;
 
app.get('/', (req, res) => {
  res.send('Hello World!');
});
 
app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});

 라우팅

app.get('/users', (req, res) => {
  res.json([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }]);
});
 
app.post('/users', (req, res) => {
  // 새 사용자 생성 로직
  res.status(201).json({ message: 'User created' });
});

 미들웨어 사용

app.use(express.json()); // JSON 파싱 미들웨어
 
app.use((req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  next();
});

RESTful API 설계 및 구현

 RESTful API 설계 원칙

  1. 리소스 기반 URL
  2. HTTP 메서드를 통한 작업 정의
  3. 적절한 HTTP 상태 코드 사용

 Express.js로 구현한 RESTful API 예시

app.get('/api/books', (req, res) => {
  // 모든 책 조회
});
 
app.get('/api/books/:id', (req, res) => {
  // 특정 책 조회
});
 
app.post('/api/books', (req, res) => {
  // 새 책 생성
});
 
app.put('/api/books/:id', (req, res) => {
  // 책 정보 업데이트
});
 
app.delete('/api/books/:id', (req, res) => {
  // 책 삭제
});

데이터베이스 연동

 Mongoose를 사용한 MongoDB 연결

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/myapp', { useNewUrlParser: true, useUnifiedTopology: true });
 
const Book = mongoose.model('Book', { title: String, author: String });
 
app.post('/api/books', async (req, res) => {
  const book = new Book(req.body);
  await book.save();
  res.status(201).json(book);
});

에러 처리와 로깅

 에러 처리 미들웨어

app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

 로깅 설정 (Winston 사용)

const winston = require('winston');
const logger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'combined.log' })
  ]
});
 
app.use((req, res, next) => {
  logger.info(`${req.method} ${req.url}`);
  next();
});

Best Practices와 주의사항

 1. 보안

  • Helmet 미들웨어 사용
  • 입력 검증
  • 적절한 인증 및 권한 부여

 2. 성능 최적화

  • 비동기 작업의 적절한 사용
  • 캐싱 전략 구현
  • 데이터베이스 쿼리 최적화

 3. 코드 구조화

  • 모듈화 및 관심사 분리
  • 환경 변수 사용
  • 테스트 작성

 4. 배포

  • PM2와 같은 프로세스 관리자 사용
  • 무중단 배포 전략 구현
  • 모니터링 및 로깅 설정

 Node.js와 Express.js는 현대 웹 개발에서 중요한 위치를 차지하고 있습니다. Node.js의 비동기, 이벤트 기반 특성은 I/O 집약적인 작업에서 높은 성능을 제공하며, 이는 실시간 애플리케이션이나 대규모 API 서버 구축에 특히 유용합니다.

 npm(Node Package Manager)은 Node.js 생태계의 핵심 요소로, 수많은 오픈 소스 패키지를 쉽게 사용할 수 있게 해줍니다. 이는 개발 생산성을 크게 향상시키고, 커뮤니티의 지식과 경험을 활용할 수 있게 합니다.

 Express.js는 Node.js 위에서 동작하는 경량 웹 프레임워크로, 간결하면서도 강력한 기능을 제공합니다. 라우팅, 미들웨어 시스템, 템플릿 엔진 지원 등의 기능을 통해 웹 애플리케이션 개발을 단순화합니다. 다른 Node.js 웹 프레임워크들과 비교했을 때, Express.js는 학습 곡선이 낮고 유연성이 높아 널리 사용되고 있습니다.

 Express.js를 사용한 서버 설정은 매우 간단합니다. 기본적인 라우팅 설정만으로도 API 서버를 구축할 수 있으며, 미들웨어를 통해 요청 처리 파이프라인을 쉽게 확장할 수 있습니다. RESTful API 설계 원칙을 따라 리소스 중심의 엔드포인트를 구성하고, HTTP 메서드를 통해 CRUD 작업을 구현할 수 있습니다.

 데이터베이스 연동에 있어 MongoDB와 Mongoose ORM의 조합은 Node.js 생태계에서 인기 있는 선택입니다. Mongoose를 통해 스키마 기반의 모델링과 편리한 쿼리 인터페이스를 사용할 수 있으며, 이는 NoSQL 데이터베이스인 MongoDB의 유연성과 잘 어울립니다.

 에러 처리와 로깅은 안정적인 애플리케이션 운영을 위해 중요합니다. Express.js의 에러 처리 미들웨어를 통해 중앙화된 에러 관리가 가능하며, Winston과 같은 로깅 라이브러리를 사용하여 구조화된 로그를 생성하고 관리할 수 있습니다.

 Node.js와 Express.js를 사용한 서버 개발에서는 몇 가지 Best Practices를 따르는 것이 중요합니다. 보안 측면에서는 Helmet 미들웨어 사용, 적절한 인증 및 권한 관리, 입력 검증 등이 필요합니다. 성능 최적화를 위해서는 비동기 작업의 적절한 사용, 캐싱 전략 구현, 데이터베이스 쿼리 최적화 등을 고려해야 합니다. 코드 구조화 측면에서는 모듈화, 환경 변수 사용, 테스트 작성 등이 중요합니다.

 배포 시에는 PM2와 같은 프로세스 관리자를 사용하여 애플리케이션의 안정성을 높이고, 무중단 배포 전략을 구현하여 서비스의 연속성을 보장해야 합니다. 또한, 적절한 모니터링 및 로깅 설정을 통해 운영 중 발생할 수 있는 문제를 신속하게 파악하고 대응할 수 있어야 합니다.

 결론적으로, Node.js와 Express.js는 현대적이고 효율적인 웹 서버 개발을 위한 강력한 도구입니다. 이들의 특성과 장점을 잘 이해하고 적절히 활용한다면, 확장성 있고 유지보수가 용이한 웹 애플리케이션을 개발할 수 있습니다. 하지만 동시에 비동기 프로그래밍 모델의 복잡성, 단일 스레드 환경에서의 CPU 집약적 작업 처리 등의 특성을 고려하여 적절한 아키텍처 설계와 최적화가 필요합니다.