icon
12장 : 백엔드 기초와 API

Node.js와 Express.js 입문


지난 장에서는 웹의 근본적인 작동 원리인 클라이언트-서버 모델과 HTTP 통신 방식에 대해 학습했습니다. 프론트엔드가 사용자에게 보여지는 부분을 담당한다면, 백엔드는 보이지 않는 곳에서 데이터를 처리하고 비즈니스 로직을 수행하며, 클라이언트에게 필요한 정보를 제공하는 역할을 합니다.

이번 장부터는 이러한 백엔드 서버를 직접 구축하는 방법을 배웁니다. 특히, 프론트엔드 개발에 사용했던 JavaScript 언어를 백엔드에서도 사용할 수 있게 해주는 Node.js와, Node.js 기반의 웹 애플리케이션 프레임워크인 Express.js를 중심으로 서버 개발의 기초를 다질 것입니다. JavaScript 하나로 프론트엔드와 백엔드를 모두 개발할 수 있는 Full-Stack 개발의 첫걸음을 내딛는 시간입니다.


Node.js: 서버 사이드 JavaScript 런타임

우리는 지금까지 JavaScript를 웹 브라우저에서 실행되는 클라이언트 사이드 스크립트 언어로 사용했습니다. 하지만 Node.js는 Google Chrome의 V8 JavaScript 엔진을 기반으로 구축된 JavaScript 런타임으로, 브라우저 환경이 아닌 서버 환경에서도 JavaScript 코드를 실행할 수 있게 해줍니다.

Node.js의 특징 및 장점

  • 비동기 논블로킹 I/O: Node.js는 단일 스레드(Single-Thread) 기반이지만, 비동기 논블로킹 I/O 모델을 사용하여 동시에 많은 요청을 효율적으로 처리할 수 있습니다. 이는 웹 서버, 실시간 채팅 애플리케이션 등 I/O 작업이 많은 애플리케이션에 특히 유리합니다.
  • JavaScript 언어 사용: 프론트엔드와 백엔드 모두 JavaScript로 개발할 수 있어, 풀스택(Full-Stack) 개발이 용이하고 개발자들이 언어 전환에 대한 부담 없이 개발할 수 있습니다.
  • 방대한 생태계 (NPM): Node.js는 NPM(Node Package Manager)이라는 거대한 패키지 생태계를 가지고 있습니다. 수많은 오픈소스 라이브러리와 모듈을 쉽게 설치하고 사용할 수 있어 개발 생산성을 극대화합니다.
  • 빠른 개발 속도: 경량 프레임워크와 빠른 시작 속도 덕분에 프로토타이핑 및 MVP(Minimum Viable Product) 개발에 유리합니다.

Node.js 설치 확인

Node.js를 사용하려면 먼저 시스템에 Node.js가 설치되어 있어야 합니다.

node -v   # Node.js 버전 확인
npm -v    # npm 버전 확인

만약 설치되어 있지 않다면, Node.js 공식 웹사이트에서 LTS(Long Term Support) 버전을 다운로드하여 설치할 수 있습니다.


Express.js: Node.js 프레임워크

Node.js만으로도 웹 서버를 만들 수 있지만, HTTP 요청 처리, 라우팅, 미들웨어 관리 등 웹 애플리케이션 개발에 필요한 복잡한 작업을 직접 구현하는 것은 비효율적입니다. Express.js는 Node.js를 위한 빠르고 개방적이며 최소한의(minimalist) 웹 애플리케이션 프레임워크입니다.

Express.js는 웹 개발에 필요한 기능들을 미리 구현해 놓은 모듈 집합을 제공하여, 개발자가 더 쉽고 빠르게 백엔드 서버를 구축할 수 있도록 돕습니다.

Express.js의 주요 기능 및 특징

  • 라우팅 (Routing): URL 경로와 HTTP 메서드(GET, POST 등)에 따라 적절한 함수를 실행하여 요청을 처리하는 기능을 제공합니다.
  • 미들웨어 (Middleware): 요청-응답 주기 동안 다양한 작업을 수행하는 함수들을 연결할 수 있는 구조를 제공합니다. (예: 요청 로깅, 인증, 데이터 파싱 등)
  • 템플릿 엔진 지원: 동적으로 HTML 페이지를 생성할 수 있도록 Pug(구 Jade), EJS, Handlebars 등 다양한 템플릿 엔진과의 통합을 지원합니다.
  • HTTP 유틸리티 메서드: 요청 및 응답 객체(req, res)에 편리한 HTTP 유틸리티 메서드를 추가하여 개발을 용이하게 합니다.
  • 뛰어난 확장성: 필요한 기능만 추가하여 사용할 수 있는 '최소한의' 프레임워크이므로, 프로젝트의 필요에 따라 유연하게 기능을 확장할 수 있습니다.

첫 번째 Express.js 서버 구축하기

이제 직접 Node.js와 Express.js를 사용하여 간단한 웹 서버를 만들어 보겠습니다.

1. 새로운 프로젝트 디렉토리 생성 및 초기화

mkdir my-express-server
cd my-express-server
npm init -y

npm init -y 명령은 package.json 파일을 기본값으로 생성합니다.

2. Express.js 설치

npm install express

3. 서버 파일 생성 (app.js 또는 server.js)

프로젝트 루트 디렉토리에 app.js 파일을 생성하고 다음 코드를 작성합니다.

// app.js

// 1. Express 모듈을 임포트합니다.
const express = require('express');

// 2. Express 애플리케이션 인스턴스를 생성합니다.
const app = express();

// 3. 서버가 들을 포트 번호를 정의합니다.
// process.env.PORT는 환경 변수가 설정되어 있을 경우 해당 포트를 사용하고,
// 그렇지 않으면 3000번 포트를 기본값으로 사용합니다.
const port = process.env.PORT || 3000;

// 4. 미들웨어 설정: JSON 요청 본문 파싱 (클라이언트가 JSON 데이터를 보낼 때 필요)
app.use(express.json());

// 5. 라우트(Route) 정의: GET 요청 처리
// '/' 경로는 웹사이트의 루트(홈)를 의미합니다.
app.get('/', (req, res) => {
  // 클라이언트에게 "Hello, World! Welcome to my Express server!" 메시지를 응답합니다.
  res.send('Hello, World! Welcome to my Express server!');
});

// 6. 새로운 라우트 정의: /api/greeting 경로로 GET 요청 처리
// 쿼리 파라미터 'name'을 받아 사용합니다.
app.get('/api/greeting', (req, res) => {
    const name = req.query.name || '방문자'; // req.query로 쿼리 파라미터 접근
    res.send(`안녕하세요, ${name}님! Express API에 오신 것을 환영합니다.`);
});

// 7. 새로운 라우트 정의: POST 요청 처리 (데이터 받기)
app.post('/api/data', (req, res) => {
    const receivedData = req.body; // req.body로 요청 본문 (JSON) 접근
    console.log('클라이언트로부터 받은 데이터:', receivedData);
    res.status(200).json({
        message: '데이터가 성공적으로 수신되었습니다!',
        yourData: receivedData
    });
});


// 8. 서버 시작: 정의된 포트에서 요청을 대기합니다.
app.listen(port, () => {
  console.log(`서버가 http://localhost:${port} 에서 실행 중입니다.`);
  console.log(`http://localhost:${port}/api/greeting?name=김철수 로 접속해보세요.`);
  console.log(`POST 요청 테스트: http://localhost:${port}/api/data`);
});

4. 서버 실행

터미널에서 다음 명령어를 실행합니다.

node app.js

서버가 성공적으로 실행되면 터미널에 서버가 http://localhost:3000 에서 실행 중입니다.와 같은 메시지가 출력됩니다.

5. 브라우저에서 확인

  • 웹 브라우저를 열고 http://localhost:3000으로 접속합니다. "Hello, World! Welcome to my Express server!" 메시지가 보일 것입니다.
  • http://localhost:3000/api/greeting?name=김철수 로 접속하면 "안녕하세요, 김철수님! Express API에 오신 것을 환영합니다." 메시지를 확인할 수 있습니다.
  • POST 요청 테스트: Postman, Insomnia 또는 Fetch API를 사용하는 프론트엔드 코드(다음 장에서 다룰 예정)를 통해 http://localhost:3000/api/data로 JSON 데이터를 포함한 POST 요청을 보내보면 서버 터미널에 데이터가 로깅되고, 클라이언트에게 응답이 돌아올 것입니다.

Nodemon으로 개발 생산성 높이기 (선택)

Node.js 서버 코드를 수정할 때마다 서버를 껐다가 다시 켜야 하는 것은 매우 번거롭습니다. Nodemon은 코드 변경을 감지하여 자동으로 Node.js 서버를 재시작해주는 유틸리티입니다.

1. Nodemon 설치

npm install --save-dev nodemon

2. package.json 스크립트 추가

package.json 파일의 scripts 섹션에 start:dev 스크립트를 추가합니다.

{
  "name": "my-express-server",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "start": "node app.js",
    "start:dev": "nodemon app.js", // 이 부분 추가
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.19.2"
  },
  "devDependencies": {
    "nodemon": "^3.1.4"
  }
}

3. Nodemon으로 서버 실행

npm run start:dev

이제 app.js 파일을 수정하고 저장하면, Nodemon이 자동으로 서버를 재시작하여 변경 사항을 즉시 반영합니다.


마무리하며

이번 장에서는 JavaScript 기반의 백엔드 개발을 위한 핵심 기술 스택인 Node.jsExpress.js의 기초를 탄탄하게 다졌습니다.

여러분은 Node.js가 브라우저 외부에서 JavaScript를 실행할 수 있는 런타임이며, 비동기 논블로킹 I/O와 방대한 NPM 생태계를 통해 효율적인 서버 개발이 가능하다는 것을 알았습니다. 또한, Express.js가 Node.js 기반의 경량 웹 프레임워크로서 라우팅, 미들웨어, HTTP 유틸리티 등 웹 서버 구축에 필요한 다양한 기능을 제공한다는 것을 배웠습니다.

직접 app.js 파일을 작성하여 기본적인 GET/POST 요청을 처리하는 Express 서버를 구축하고 실행해보았으며, Nodemon을 사용하여 개발 생산성을 높이는 방법도 익혔습니다. 이제 여러분은 프론트엔드 개발에서 사용했던 JavaScript 언어로 백엔드 서버까지 구축할 수 있는 풀스택 개발의 기반을 마련했습니다.