티스토리 뷰
목차
Node.js 서버 개발의 핵심은 비동기 프로그래밍입니다. 비동기 처리를 통해 고성능 서버를 구현할 수 있으며, Express 프레임워크를 사용하여 효율적인 서버를 구축할 수 있습니다. 또한, 데이터베이스 연동을 통해 데이터 처리를 통합함으로써 더욱 강력한 서버를 만들 수 있습니다. 이 글에서는 Node.js의 비동기 프로그래밍 원리부터 Express 프레임워크 사용법, 데이터베이스 연동 방법까지 자세히 살펴보겠습니다.
1. 이벤트 루프와 비동기 처리
Node.js는 자바스크립트 런타임 환경으로, 서버 개발에서 특히 효율적인 이유는 비동기 I/O 처리를 지원하기 때문입니다. 비동기 프로그래밍의 핵심은 이벤트 루프입니다. 이벤트 루프는 Node.js가 비동기적으로 작업을 처리할 수 있게 해주며, 이는 서버의 성능을 극대화하는 데 기여합니다. 이벤트 루프는 실행 스택과 작업 큐 두 가지 주요 구성을 가집니다. 실행 스택은 현재 실행 중인 코드를 담고 있으며, 작업 큐는 나중에 실행할 작업들을 대기시킵니다. 비동기 작업이 호출되면, 이는 실행 스택에서 빠져나와 작업 큐에 추가됩니다. 실행 스택이 비워질 때마다 이벤트 루프는 작업 큐에서 대기 중인 작업을 하나씩 꺼내어 실행합니다. 이로 인해 단일 스레드 환경에서도 비동기 작업이 원활하게 처리될 수 있습니다. 이벤트 루프의 작동 원리를 이해하는 것은 비동기 프로그래밍의 기초를 다지는 데 매우 중요합니다. 비동기 프로그래밍에서는 콜백, 프로미스, async/await와 같은 패턴을 사용하여 작업을 처리합니다. 콜백은 비동기 작업이 완료되었을 때 호출되는 함수로, 비동기 프로그래밍의 기본 요소입니다. 그러나 콜백 지옥(callback hell) 문제를 겪을 수 있기 때문에 이를 개선하기 위해 프로미스와 async/await가 도입되었습니다. 프로미스는 비동기 작업의 결과를 처리하는 방식을 개선하였고, 체이닝을 통해 여러 비동기 작업을 순차적으로 처리할 수 있게 되었습니다. 프로미스는 new Promise() 생성자로 생성되며, 성공 또는 실패를 나타내는 resolve와 reject 함수를 인수로 받습니다. 프로미스로 반환된 작업은 then()과 catch() 메서드를 통해 이어서 처리할 수 있습니다. async/await는 프로미스 기반의 비동기 코드를 더욱 직관적으로 작성할 수 있게 도와줍니다. async 키워드로 선언된 함수 내에서 await 키워드를 사용하면, 프로미스가 반환될 때까지 코드 실행을 일시 정지합니다. 이는 동기적 코드 작성 방식과 유사하여 가독성을 높이고 디버깅을 쉽게 만듭니다. 이벤트 루프와 비동기 처리의 효과를 강조하기 위해 간단한 예제를 살펴보겠습니다. 예를 들어, 파일 읽기 작업을 비동기적으로 처리할 수 있는 fs 모듈의 readFile 메서드를 사용하여, 파일을 읽는 동안 차단되지 않고 다른 작업을 계속 수행할 수 있습니다. const fs = require('fs'); fs.readFile('example.txt', 'utf8', (err, data) => { if (err) { console.error(err); return; } console.log(data); }); 이 예제에서 readFile 메서드는 비동기적으로 파일을 읽으며, 작업이 완료되면 콜백 함수를 호출합니다. 이로 인해 다른 작업들이 차단되지 않고 계속 실행될 수 있습니다. 이벤트 루프와 비동기 처리를 통해 Node.js는 높은 성능과 확장성을 제공하는 서버를 구축할 수 있습니다. 이는 특히 대량의 I/O 작업을 처리하는 서버에서 큰 이점을 제공합니다. 개인적으로 Node.js의 비동기 프로그래밍은 초기 학습 곡선이 있으나, 이를 극복하면 매우 강력한 도구가 되며, 고성능의 확장 가능한 서버를 구축하는 데 큰 도움이 됩니다. 이는 서버의 효율성을 높이고 사용자의 요청을 신속하게 처리하는 데 중요한 역할을 합니다.
2. Express 프레임워크 사용법
Express는 Node.js에서 가장 널리 사용되는 웹 프레임워크 중 하나로, 빠르고 간결하게 웹 및 API 서버를 구축할 수 있게 해줍니다. Express는 경량의 유연한 프레임워크로, 다양한 미들웨어와 함께 사용하여 확장성과 유지보수성을 높일 수 있습니다. Express를 사용하면 HTTP 요청을 처리하고, 라우팅을 관리하며, 다양한 미들웨어를 통해 기능을 확장할 수 있습니다. 먼저 Express를 설치하고, 기본적인 서버를 설정해보겠습니다. npm을 사용하여 Express를 설치할 수 있습니다. npm init -y npm install express 그런 다음, 서버를 설정하여 간단한 "Hello World" 응답을 반환하는 예제를 작성해보겠습니다. const express = require('express'); const app = express(); const port = 3000; app.get('/', (req, res) => { res.send('Hello World!'); }); app.listen(port, () => { console.log(`Server is running on port ${port}`); }); 이 예제에서는 Express를 사용하여 기본적인 서버를 설정하고, 루트 경로('/')에 대한 GET 요청을 처리하여 "Hello World"를 반환합니다. 이제 라우팅을 좀 더 세부적으로 다루어보겠습니다. 라우팅은 특정 URL 경로에 요청을 매핑하는 것으로, 다양한 엔드포인트를 처리할 수 있게 해줍니다. Express에서는 app.get(), app.post(), app.put(), app.delete()와 같은 메서드를 사용하여 다양한 HTTP 메서드에 대한 요청을 처리할 수 있습니다. app.get('/user/:id', (req, res) => { const userId = req.params.id; res.send(`User ID: ${userId}`); }); app.post('/user', (req, res) => { const newUser = req.body; // 새로운 사용자 생성 로직 res.send('User created'); }); 이 예제에서는 GET 요청으로 사용자의 ID를 받아 처리하고, POST 요청으로 새로운 사용자를 생성합니다. 요청 매개변수와 본문 데이터를 처리하는 방법을 예로 보여줍니다. Express에서는 미들웨어를 사용하여 기능을 확장할 수 있습니다. 미들웨어는 요청과 응답 객체를 조작하거나, 요청 흐름을 제어할 수 있는 함수입니다. 예를 들어, body-parser 미들웨어를 사용하여 요청 본문을 파싱할 수 있습니다. npm install body-parser 그런 다음, 서버 설정에 body-parser 미들웨어를 추가합니다. const bodyParser = require('body-parser'); app.use(bodyParser.json()); 이 설정을 통해 모든 요청 본문을 JSON 형태로 파싱하여 사용할 수 있습니다. 이외에도 인증, 로깅, 에러 처리 등을 위한 다양한 미들웨어가 존재하며, 이를 통해 서버의 기능을 확장할 수 있습니다. Express를 사용하면 템플릿 엔진과 결합하여 동적 웹 페이지를 생성할 수도 있습니다. Pug, EJS, Handlebars와 같은 템플릿 엔진을 사용하여 서버에서 렌더링된 HTML을 생성할 수 있습니다. 예를 들어, Pug 템플릿 엔진을 사용하여 간단한 HTML 페이지를 렌더링하는 코드를 작성해보겠습니다. npm install pug app.set('view engine', 'pug'); app.get('/pug', (req, res) => { res.render('index', { title: 'Hey', message: 'Hello there!' }); }); 이 예제에서는 Pug 템플릿 엔진을 설정하고, "/pug" 경로에 대한 요청을 처리하여 템플릿을 렌더링합니다. 개인적으로 Express는 간단하면서도 강력한 프레임워크로, 다양한 웹 애플리케이션 및 API 서버를 구축하는 데 매우 유용하다고 생각합니다. 이는 개발 생산성을 높이고, 코드의 가독성과 유지보수성을 향상시키는 데 큰 도움이 됩니다.
3. 데이터베이스 연동
Node.js 서버 개발에서 데이터베이스 연동은 필수적인 요소 중 하나입니다. 다양한 데이터베이스와 연동하여 데이터를 저장하고 조회하는 방법을 익히는 것은 매우 중요합니다. Node.js는 MySQL, PostgreSQL, MongoDB 등 다양한 데이터베이스와 쉽게 연동할 수 있는 여러 모듈을 제공합니다. 먼저 MySQL 데이터베이스와의 연동을 살펴보겠습니다. MySQL은 가장 널리 사용되는 관계형 데이터베이스 중 하나로, 다양한 Node.js 모듈을 통해 연동할 수 있습니다. mysql2 모듈을 사용하여 MySQL 데이터베이스에 연결하고, 데이터를 조회하는 예제를 작성해보겠습니다. npm install mysql2 그런 다음, 데이터베이스 연결을 설정하고, 간단한 쿼리를 실행해보겠습니다. const mysql = require('mysql2'); const connection = mysql.createConnection({ host: 'localhost', user: 'root', password: 'password', database: 'test' }); connection.connect((err) => { if (err) { console.error('Error connecting to the database:', err); return; } console.log('Connected to the database'); }); connection.query('SELECT * FROM users', (err, results) => { if (err) { console.error('Error executing query:', err); return; } console.log('Query results:', results); connection.end(); }); 이 예제에서는 MySQL 데이터베이스에 연결하고, "users" 테이블에서 데이터를 조회하는 간단한 쿼리를 실행합니다. 조회된 결과는 콘솔에 출력됩니다. 다음으로는 MongoDB와의 연동을 살펴보겠습니다. MongoDB는 문서 지향 데이터베이스로, NoSQL 데이터베이스 중 가장 널리 사용되는 제품 중 하나입니다. MongoDB와 연동하기 위해 mongoose 모듈을 사용할 수 있습니다. mongoose는 MongoDB 객체 데이터 모델링(ODM) 라이브러리로, 데이터베이스 스키마를 정의하고 데이터를 쉽게 조작할 수 있게 도와줍니다. npm install mongoose 그런 다음, MongoDB 연결을 설정하고, 간단한 데이터 모델을 정의해보겠습니다. const mongoose = require('mongoose'); mongoose.connect('mongodb://localhost:27017/test', { useNewUrlParser: true, useUnifiedTopology: true }); const db = mongoose.connection; db.on('error', (err) => { console.error('MongoDB connection error:', err); }); db.once('open', () => { console.log('Connected to MongoDB'); }); const userSchema = new mongoose.Schema({ name: String, age: Number, email: String }); const User = mongoose.model('User', userSchema); const newUser = new User({ name: 'John Doe', age: 30, email: 'john.doe@example.com' }); newUser.save((err) => { if (err) { console.error('Error saving user:', err); return; } console.log('User saved successfully'); }); 이 예제에서는 MongoDB에 연결하고, "User" 모델을 정의하여 새로운 사용자를 데이터베이스에 저장합니다. Mongoose를 사용하면 데이터베이스 스키마를 정의하고, 데이터 조작을 간단하게 할 수 있습니다. 마지막으로 PostgreSQL 데이터베이스와의 연동을 살펴보겠습니다. PostgreSQL은 오픈 소스 관계형 데이터베이스로, 고급 기능과 확장성을 자랑합니다. Node.js에서는 pg 모듈을 사용하여 PostgreSQL 데이터베이스에 연결할 수 있습니다. npm install pg 그런 다음, PostgreSQL 연결을 설정하고, 간단한 쿼리를 실행해보겠습니다. const { Client } = require('pg'); const client = new Client({ host: 'localhost', user: 'postgres', password: 'password', database: 'test' }); client.connect((err) => { if (err) { console.error('Error connecting to PostgreSQL:', err); return; } console.log('Connected to PostgreSQL'); }); client.query('SELECT * FROM users', (err, res) => { if (err) { console.error('Error executing query:', err); return; } console.log('Query results:', res.rows); client.end(); }); 이 예제에서는 PostgreSQL 데이터베이스에 연결하고, "users" 테이블에서 데이터를 조회하는 간단한 쿼리를 실행합니다. 조회된 결과는 콘솔에 출력됩니다. Node.js를 사용하면 다양한 데이터베이스와 쉽게 연동할 수 있으며, 이를 통해 강력한 데이터 중심 애플리케이션을 개발할 수 있습니다. 개인적으로 데이터베이스 연동은 서버 개발에서 매우 중요한 요소로, 이를 통해 데이터 저장과 조회를 효율적으로 처리할 수 있음을 경험했습니다. 앞으로 더 많은 개발자들이 Node.js를 활용하여 다양한 데이터베이스와 연동된 강력한 서버를 구축할 수 있기를 바랍니다. Node.js 서버 개발에서 비동기 프로그래밍의 중요성을 다뤘습니다. 이벤트 루프와 비동기 처리의 작동 원리를 통해 Node.js의 성능을 극대화할 수 있음을 확인했으며, Express 프레임워크 사용법을 통해 웹 서버와 API를 구축하는 방법을 살펴보았습니다. 또한 데이터베이스 연동을 통해 데이터를 저장하고 조회하는 방법을 이해했습니다. Node.js는 비동기 프로그래밍을 통해 높은 성능과 확장성을 제공하며, 다양한 도구와 프레임워크를 활용하여 강력한 서버를 개발할 수 있습니다. 개인적으로 Node.js를 사용한 서버 개발은 흥미롭고 유익한 경험이었으며, 많은 개발자들이 이를 통해 고성능의 확장 가능한 서버를 구축할 수 있기를 기대합니다. Node.js의 비동기 프로그래밍 기술을 통해 더 많은 웹 애플리케이션이 효율적으로 구현될 수 있기를 바랍니다.