Express 개발 강좌, 업로드한 파일의 메타데이터 처리

현대 웹 애플리케이션에서 파일 업로드는 매우 일반적인 기능입니다. 사용자는 종종 문서, 이미지, 비디오와 같은 파일을 서버에 업로드해야 합니다. Express.js는 Node.js 기반의 웹 애플리케이션 프레임워크로, 이러한 작업을 구현하는 데 적합한 도구입니다. 이번 강좌에서는 Express.js를 통해 업로드한 파일의 메타데이터를 처리하는 방법을 심도 있게 설명하겠습니다.

1. Express.js 소개

Express.js는 간결하고 유연한 Node.js 웹 애플리케이션 프레임워크로, 서버 사이드 애플리케이션 구축을 위해 필요한 기본 기능을 제공합니다. RESTful API를 쉽게 구현할 수 있는 기능과 미들웨어 기반의 아키텍처로 인해 많은 개발자들이 애용하고 있습니다.

2. 필요한 패키지 설치하기

파일 업로드 기능을 구현하기 위해 필요한 패키지를 설치하겠습니다. 가장 인기 있는 파일 업로드 Middleware인 multer를 사용하겠습니다. multer는 multipart/form-data를 처리하여, 파일을 쉽게 업로드할 수 있도록 도와줍니다.

npm install express multer

3. 기본적인 Express 서버 설정

기본적인 Express 서버를 설정하겠습니다. 다음 코드를 사용하여 app.js라는 파일을 생성하고, Express 서버를 설정합니다.


const express = require('express');
const multer = require('multer');
const app = express();
const port = 3000;

// multer 설정
const storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, 'uploads/');
    },
    filename: function (req, file, cb) {
        cb(null, Date.now() + '-' + file.originalname);
    }
});

const upload = multer({ storage: storage });

// 기본 라우트
app.get('/', (req, res) => {
    res.send('Hello, Express!');
});

// 파일 업로드 라우트
app.post('/upload', upload.single('file'), (req, res) => {
    if (!req.file) {
        return res.status(400).send('파일이 업로드되지 않았습니다.');
    }
    res.send({
        message: '파일이 성공적으로 업로드되었습니다.',
        file: req.file,
    });
});

// 서버 시작
app.listen(port, () => {
    console.log(`서버가 http://localhost:${port}에서 실행 중입니다.`);
});
        

4. 파일 업로드 라우트 설명

위의 코드는 파일 업로드를 위한 라우트를 설정합니다. upload.single('file')은 클라이언트로부터 file이라는 이름의 파일을 업로드 받을 것을 기대하며, 업로드된 파일의 정보를 req.file에서 사용할 수 있습니다.업로드된 파일의 메타데이터는 req.file 객체에 포함됩니다. 이 객체에는 파일의 이름, 경로, 크기와 같은 정보가 포함되어 있습니다.

4.1. 메타데이터 처리

업로드한 파일에 대한 메타데이터를 처리하는 방법에 대해 더 깊이 살펴보겠습니다. 다음 코드를 통해 파일의 메타데이터를 JSON 형식으로 반환하도록 수정할 수 있습니다.


app.post('/upload', upload.single('file'), (req, res) => {
    if (!req.file) {
        return res.status(400).send('파일이 업로드되지 않았습니다.');
    }

    const metadata = {
        originalName: req.file.originalname,
        mimeType: req.file.mimetype,
        size: req.file.size,
        uploadDate: new Date(req.file.uploadDate || Date.now()),
        path: req.file.path,
    };

    res.send({
        message: '파일이 성공적으로 업로드되었습니다.',
        metadata: metadata,
    });
});
        

5. 클라이언트 측 파일 업로드 구현

이제 클라이언트 측에서 파일을 업로드하는 HTML 양식을 구현하겠습니다. 다음 코드를 사용하여 index.html 파일을 생성합니다.






    
    
    파일 업로드


    

파일 업로드

6. 업로드한 파일의 메타데이터 구조

위 코드에서 업로드된 파일의 메타데이터는 다음과 같은 구조를 가집니다:


{
    message: "파일이 성공적으로 업로드되었습니다.",
    metadata: {
        originalName: "example.png",
        mimeType: "image/png",
        size: 102456,
        uploadDate: "2023-01-01T00:00:00.000Z",
        path: "uploads/1234567890-example.png"
    }
}
        

7. 에러 핸들링

파일 업로드 시 다양한 에러 상황이 발생할 수 있습니다. 예를 들어 파일 크기가 너무 크거나 허용되지 않는 파일 형식이 업로드되는 경우입니다. 이를 처리하기 위해 multer의 설정에서 제한 조건을 추가할 수 있습니다.


// 파일 크기 제한 (5MB 이하)
const upload = multer({
    storage: storage,
    limits: { fileSize: 5 * 1024 * 1024 },
    fileFilter: (req, file, cb) => {
        const fileTypes = /jpeg|jpg|png|gif/;
        const extname = fileTypes.test(file.mimetype);
        const mimetype = fileTypes.test(file.originalname.split('.').pop().toLowerCase());
        if (extname && mimetype) {
            return cb(null, true);
        }
        cb(new Error('허용되지 않는 파일 형식입니다.'));
    }
});
        

8. 실전 배포 및 최적화

이제 파일 업로드 기능이 완성되었습니다. 마지막 단계로는 이 기능을 실제 프로덕션 환경에 배포하고 최적화하는 것입니다. 이 과정에서는 다음과 같은 사항을 고려해야 합니다:

  • 파일 저장소: 클라우드 저장소 (예: AWS S3)를 사용할지, 로컬 파일 시스템에 저장할지를 결정합니다.
  • 보안: 업로드되는 파일의 유효성을 검사하여 악성 코드가 포함되지 않도록 합니다.
  • 성능: 여러 사용자가 동시에 업로드할 수 있도록 성능을 최적화합니다.

9. 결론

이번 강좌에서는 Express.js를 사용하여 파일 업로드 기능을 구현하고 업로드된 파일의 메타데이터를 처리하는 방법에 대해 설명했습니다. Express.js와 multer를 활용하면 간단하면서도 강력한 파일 업로드 기능을 구현할 수 있습니다. 완성된 애플리케이션을 바탕으로 추가적인 기능들을 고려하여 확장해보세요.

10. 추가 리소스

Express 개발 강좌, Express.js에서 CORS 설정하는 방법

현대 웹 애플리케이션은 여러 서버와 API가 상호작용하며 정보를 주고받는 형태로 설계되고 있습니다.
이 과정에서 CORS(Cross-Origin Resource Sharing)라는 개념이 굉장히 중요하게 작용합니다.
CORS는 외부 도메인에서 자원을 요청할 때 브라우저가 이를 허용할지 결정하는 메커니즘입니다.
이 글에서는 Express.js에서 CORS를 설정하는 방법을 단계별로 자세하게 알아보겠습니다.

1. CORS의 이해

CORS란 하나의 사이트에서 다른 사이트의 자원에 접근하는 것을 허용하는 보안 기능입니다.
웹 브라우저는 기본적으로 자바스크립트에서 다른 도메인으로의 요청을 차단합니다.
예를 들어, ‘https://example.com’에서 호스팅되는 웹 애플리케이션이 ‘https://api.example.com’로 API 요청을 하려고 하면,
브라우저는 이를 차단하고 CORS 오류를 발생시킵니다.
이는 웹 보안을 강화하기 위한 기능입니다.

2. Express.js에서 CORS를 설정하는 이유

Express.js는 서버와 API를 쉽게 구축할 수 있는 강력한 웹 프레임워크입니다.
하지만 외부 도메인에서의 요청을 허용하려면 CORS 설정이 필요합니다.
이를 통해 여러분의 API가 신뢰할 수 있는 도메인에서만 요청을 받을 수 있도록 제어할 수 있습니다.
CORS를 적절히 설정하지 않으면 보안 위협에 노출될 수 있습니다.

3. CORS 설정 방법

Express.js에서 CORS를 설정하는 방법은 여러 가지가 있지만, 가장 일반적으로 사용하는 방법은 cors 패키지를 활용하는 것입니다.
이 패키지는 CORS 관련 로직을 간단하게 처리할 수 있도록 도와줍니다. 이제 설치 및 설정 방법을 살펴보겠습니다.

3.1. CORS 패키지 설치하기

npm install cors

먼저, CORS 패키지를 프로젝트에 설치해야 합니다.
위의 명령어를 사용하여 CORS 패키지를 설치합니다.

3.2. 기본 CORS 설정

설치가 완료되면 Express 애플리케이션에서 사용할 수 있도록 설정합니다.
기본적인 설정은 다음과 같습니다.

javascript
const express = require('express');
const cors = require('cors');

const app = express();
app.use(cors()); // CORS 설정 추가

app.get('/api/data', (req, res) => {
    res.json({ message: 'CORS가 설정된 데이터입니다.' });
});

app.listen(3000, () => {
    console.log('서버가 http://localhost:3000 에서 실행 중입니다.');
});

위 코드에서 app.use(cors()); 구문이 CORS를 활성화시킵니다.
이제 이 서버는 모든 도메인에서의 요청을 수락하게 됩니다.

3.3. CORS 옵션 설정하기

모든 도메인에서 요청을 수락하는 것은 보안상 위험할 수 있습니다.
특정 도메인만 허용하고 싶다면 CORS 옵션을 설정해야 합니다.
아래 예제에서 특정 도메인에 대해 요청을 허용하는 방법을 보여드립니다.

javascript
const express = require('express');
const cors = require('cors');

const app = express();
const allowedOrigins = ['http://example.com', 'http://another-domain.com'];

app.use(cors({
    origin: allowedOrigins, // 허용된 도메인
    methods: ['GET', 'POST'], // 허용된 HTTP 메소드
    allowedHeaders: ['Content-Type', 'Authorization'], // 허용된 헤더
}));

app.get('/api/data', (req, res) => {
    res.json({ message: '특정 도메인에서 요청한 데이터입니다.' });
});

app.listen(3000, () => {
    console.log('서버가 http://localhost:3000 에서 실행 중입니다.');
});

위 코드는 allowedOrigins 배열에 지정된 도메인만 요청할 수 있도록 설정합니다.
methodsallowedHeaders 옵션으로 HTTP 메소드와 허용된 헤더도 추가적으로 지정할 수 있습니다.

3.4. 특수한 CORS 설정

가끔은 특정 요구 사항에 따라 CORS 정책을 세밀하게 설정해야 할 때가 있습니다.
예를 들어 인증된 요청에서 ‘Credential’을 허용하려면 아래와 같이 설정할 수 있습니다.

javascript
const express = require('express');
const cors = require('cors');

const app = express();
const allowedOrigins = ['http://example.com'];

app.use(cors({
    origin: allowedOrigins,
    credentials: true, // 인증된 요청 허용
}));

app.get('/api/data', (req, res) => {
    res.json({ message: '인증이 허용된 데이터입니다.' });
});

app.listen(3000, () => {
    console.log('서버가 http://localhost:3000 에서 실행 중입니다.');
});

위 예시에서 credentials: true 옵션을 추가함으로써, 인증된 요청이 허용됩니다.
클라이언트에서 인증 정보(예: 쿠키)를 포함하여 요청이 가능한 상태가 됩니다.

3.5. CORS 오류 처리하기

종종 클라이언트에서 CORS 오류가 발생할 수 있는데, 이는 브라우저가 요청을 차단하기 때문입니다.
서버가 올바르게 CORS를 설정했더라도 몇 가지 이유로 인해 오류가 발생할 수 있습니다.
오류를 해결하려면 다음과 같은 점을 먼저 확인해야 합니다.

  • 서버와 클라이언트의 도메인이 올바르게 설정되어 있는지 확인합니다.
  • HTTP 메소드와 헤더가 허용된 값인지 확인합니다.
  • If the server is configured correctly and still causes problems, check browser extensions or security settings that might block requests.

4. CORS를 사용한 실제 예제

이제 실제 애플리케이션에서 CORS를 사용하는 예제를 살펴보겠습니다.
아래 예제에서는 간단한 클라이언트와 Express.js 서버를 설정하여 CORS를 사용하는 방법을 보여줍니다.

4.1. Express.js 서버 설정

javascript
const express = require('express');
const cors = require('cors');

const app = express();
const allowedOrigins = ['http://example-client.com'];

app.use(cors({
    origin: allowedOrigins,
    methods: ['GET', 'POST'],
    credentials: true,
}));

app.get('/api/message', (req, res) => {
    res.json({ message: '안녕하세요, 클라이언트입니다!' });
});

app.listen(3000, () => {
    console.log('서버가 http://localhost:3000 에서 실행 중입니다.');
});

4.2. 클라이언트 코드

Express 서버에 요청하는 클라이언트 코드는 다음과 같이 작성할 수 있습니다.

javascript
fetch('http://localhost:3000/api/message', {
    method: 'GET',
    credentials: 'include', // 인증 정보 포함
})
.then(response => response.json())
.then(data => {
    console.log(data.message); // 안녕하세요, 클라이언트입니다!
})
.catch(error => {
    console.error('오류 발생:', error);
});

5. 결론

이번 글에서는 Express.js에서 CORS를 설정하는 방법에 대해 자세히 알아보았습니다.
CORS 설정은 보안의 일환으로 매우 중요한 과정입니다.
올바르게 설정하면, 외부 도메인에서 API를 안전하게 활용할 수 있습니다.
Express.js에서 CORS를 설정하는 것은 간단하지만,
보안상의 위험을 피하기 위해서는 적절한 정책을 계속 유지하고 관리해야 합니다.

더 많은 팁과 방법을 알고 싶다면, 공식 Express.js 문서와 CORS에 대한 리소스를 참고하시길 바랍니다.
앞으로 여러분의 웹 애플리케이션에서 CORS를 적절히 활용하여 안전하고 신뢰할 수 있는 서비스를 제공하시길 바랍니다!

Express 개발 강좌, PostgreSQL과 Sequelize를 이용한 관계형 데이터베이스 연동

1. 서론

Node.js는 비동기 프로그래밍을 지원하는 서버 사이드 플랫폼으로, 그 중 Express.js는 간결하고 강력한 웹 애플리케이션 프레임워크로 널리 사용됩니다. 본 강좌에서는 PostgreSQL 데이터베이스와 ORM(Object Relational Mapping) 라이브러리인 Sequelize를 활용하여 Express 애플리케이션에 관계형 데이터베이스를 연결하는 방법에 대해 자세히 알아보겠습니다.

2. 환경 설정

우선, 프로젝트를 위해 Node.js 및 PostgreSQL이 설치되어 있어야 합니다. PostgreSQL 설치 후 데이터베이스를 생성하고 다음 단계를 진행합니다.

2.1. Node.js 프로젝트 생성

mkdir express-postgresql-example
cd express-postgresql-example
npm init -y

2.2. 필요한 패키지 설치

Express, Sequelize, pg (PostgreSQL 드라이버), 관련 패키지를 설치합니다.

npm install express sequelize pg pg-hstore

3. PostgreSQL 데이터베이스 설정

PostgreSQL 데이터베이스에 접속하여 아래와 같이 데이터베이스를 생성합니다.
명령줄에서 psql을 실행한 후 다음 SQL 명령어를 입력합니다.

CREATE DATABASE example_db;

테이블 구조를 다음과 같이 설정하겠습니다.

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    email VARCHAR(100) UNIQUE
);

3.1. Sequelize 모델 생성

Sequelize를 통해 위의 users 테이블에 대한 모델을 생성합니다.

4. Express 서버 설정

이제 Express 서버를 설정해 보겠습니다. server.js 파일을 만들어 주십시오.

const express = require('express');
const { Sequelize, DataTypes } = require('sequelize');

// 서버 및 데이터베이스 설정
const app = express();
const sequelize = new Sequelize('example_db', 'username', 'password', {
    host: 'localhost',
    dialect: 'postgres'
});

// 모델 정의
const User = sequelize.define('User', {
    name: {
        type: DataTypes.STRING,
        allowNull: false
    },
    email: {
        type: DataTypes.STRING,
        allowNull: false,
        unique: true
    }
}, {
    tableName: 'users'
});

// 미들웨어
app.use(express.json());

// RESTful API 구현
app.get('/users', async (req, res) => {
    const users = await User.findAll();
    res.json(users);
});

app.post('/users', async (req, res) => {
    const { name, email } = req.body;
    const user = await User.create({ name, email });
    res.status(201).json(user);
});

// 서버 시작
const PORT = process.env.PORT || 3000;
app.listen(PORT, async () => {
    try {
        await sequelize.authenticate();
        console.log('Database connected');
        console.log(`Server is running on http://localhost:${PORT}`);
    } catch (error) {
        console.error('Unable to connect to the database:', error);
    }
});

5. 데이터 CRUD 작업

5.1. Create (생성)

POST /users 엔드포인트를 통해 사용자를 생성할 수 있습니다. 요청 본문에 사용자 이름과 이메일을 포함해야 합니다.

5.2. Read (조회)

GET /users 엔드포인트를 호출하면 데이터베이스에 있는 모든 사용자가 반환됩니다.

5.3. Update (수정)

app.put('/users/:id', async (req, res) => {
    const { id } = req.params;
    const { name, email } = req.body;
    const user = await User.findByPk(id);
    if (user) {
        user.name = name;
        user.email = email;
        await user.save();
        res.json(user);
    } else {
        res.status(404).json({ message: 'User not found' });
    }
});

5.4. Delete (삭제)

app.delete('/users/:id', async (req, res) => {
    const { id } = req.params;
    const user = await User.destroy({ where: { id } });
    if (user) {
        res.status(204).send();
    } else {
        res.status(404).json({ message: 'User not found' });
    }
});

6. Sequelize 응용: 관계 설정

Sequelize는 모델 간의 관계를 설정할 수 있습니다. 예를 들어, 사용자가 여러 게시글을 작성하는 구조로 만들기 위해 Post 모델을 추가해 보겠습니다.

const Post = sequelize.define('Post', {
    title: {
        type: DataTypes.STRING,
        allowNull: false
    },
    content: {
        type: DataTypes.TEXT,
        allowNull: false
    }
}, {
    tableName: 'posts'
});

// 관계 설정
User.hasMany(Post);
Post.belongsTo(User);

이제 사용자는 여러 게시글을 가질 수 있으며, 게시글은 하나의 사용자에게 속합니다.

7. 데이터베이스 마이그레이션

Sequelize CLI를 사용하여 데이터베이스를 마이그레이션할 수 있습니다. 먼저, sequelize-cli 패키지를 설치합니다.

npm install --save-dev sequelize-cli

그리고 다음 명령어로 마이그레이션을 생성합니다.

npx sequelize-cli migration:generate --name create-users

마이그레이션 파일 작성

생성된 파일에 다음 내용을 추가합니다.

module.exports = {
    up: async (queryInterface, Sequelize) => {
        await queryInterface.createTable('users', {
            id: {
                type: Sequelize.INTEGER,
                autoIncrement: true,
                primaryKey: true
            },
            name: {
                type: Sequelize.STRING,
                allowNull: false
            },
            email: {
                type: Sequelize.STRING,
                allowNull: false,
                unique: true
            },
            createdAt: {
                allowNull: false,
                type: Sequelize.DATE
            },
            updatedAt: {
                allowNull: false,
                type: Sequelize.DATE
            }
        });
    },
    down: async (queryInterface, Sequelize) => {
        await queryInterface.dropTable('users');
    }
};

마이그레이션을 실행하여 테이블을 생성합니다.

npx sequelize-cli db:migrate

8. 성능 최적화

데이터베이스와의 연결을 최적화하고, 필요한 경우 인덱스를 추가하여 쿼리 성능을 개선할 수 있습니다. Sequelize는 쿼리 최적화를 위한 다양한 옵션을 제공합니다.

User.findAll({
    where: { email: { [Op.like]: '%@gmail.com%' } },
    order: [['createdAt', 'DESC']],
    limit: 10
});

9. 결론

본 강좌를 통해 Express.js와 PostgreSQL, Sequelize를 이용한 웹 서버의 기본적인 구조와 데이터베이스 연동 방법을 익혔습니다. 이와 같은 구성을 통해 RESTful API를 효율적으로 구축할 수 있으며, 데이터베이스와 상호작용하는 강력한 기능을 활용할 수 있습니다.

Express 개발 강좌, 에러 핸들링 및 응답 구조 설계

웹 애플리케이션을 개발할 때는 에러 핸들링과 응답 구조 설계가 매우 중요합니다. 사용자가 불필요한 오류 메시지에 혼란을 느끼지 않도록 하고, 발생하는 모든 문제를 일관되게 처리할 수 있어야 합니다. 본 강좌에서는 Express.js를 이용한 에러 핸들링과 응답 구조 설계에 대하여 상세히 설명하겠습니다.

1. Express.js 소개

Express.js는 Node.js를 위한 웹 애플리케이션 프레임워크로, 빠르고 간단하게 웹 서버를 구축할 수 있도록 설계되었습니다. RESTful API, 웹 서버, 대규모 웹 애플리케이션 등을 개발할 때 널리 사용되며, ORM과 DB와의 통합, 미들웨어와의 결합 등 유연한 구조를 지원합니다.

2. 에러 핸들링의 중요성

에러 핸들링은 애플리케이션의 안정성과 사용자 경험에 큰 영향을 미칩니다. 예상치 못한 오류가 발생했을 때, 사용자에게 적절한 피드백을 제공하고 시스템의 안전한 동작을 보장해야 합니다. 적절한 에러 핸들링이 이루어지지 않으면, 사용자는 혼란을 느끼고 불만을 가질 수 있습니다.

2.1. 에러 종류

애플리케이션에서 발생할 수 있는 오류는 크게 다음과 같이 나눌 수 있습니다:

  • 사용자 입력 오류: 사용자가 잘못된 데이터를 입력했을 경우
  • 서버 오류: 서버에서 발생하는 예기치 못한 오류
  • 네트워크 오류: 외부 API 호출이나 데이터베이스 연결에서 발생하는 오류

3. Express에서의 에러 핸들링

Express에서는 미들웨어를 통해 에러를 처리할 수 있습니다. 에러 핸들링 미들웨어는 일반적인 미들웨어와 유사하지만, 추가적인 매개변수로 에러 객체를 받아들입니다. 기본적인 에러 핸들러의 구조는 다음과 같습니다.


    app.use((err, req, res, next) => {
        // 에러 처리 로직
        res.status(err.status || 500);
        res.json({ error: err.message });
    });
    

3.1. 기본 에러 핸들링

다음은 기본적인 에러 핸들링의 예시입니다. 사용자가 로그인할 때, 인증 정보가 유효하지 않으면 에러 메시지를 클라이언트에게 반환합니다.


    app.post('/login', (req, res, next) => {
        const { username, password } = req.body;
        if (!username || !password) {
            const error = new Error('사용자 이름과 비밀번호를 입력하세요.');
            error.status = 400;
            return next(error);
        }

        // ... 인증 로직 ...
        const isAuthenticated = false; // 예시로 잘못된 인증 결과
        if (!isAuthenticated) {
            const error = new Error('인증 정보가 올바르지 않습니다.');
            error.status = 401;
            return next(error);
        }

        res.send('로그인 성공');
    });
    

4. 사용자 정의 에러 객체

Express에서는 에러 객체를 커스터마이즈하여 발생하는 에러의 유형을 분류할 수 있습니다. 예를 들어, 네트워크 오류나 데이터베이스 오류를 표현하기 위해 다음과 같이 사용자 정의 에러 객체를 생성할 수 있습니다.


    class CustomError extends Error {
        constructor(message, status) {
            super(message);
            this.status = status;
        }
    }

    app.get('/data', (req, res, next) => {
        // 데이터베이스 연결 오류 발생
        const error = new CustomError('데이터베이스 연결 실패', 500);
        return next(error);
    });
    

4.1. 사용자 정의 에러 핸들러

사용자 정의 에러 객체를 활용하여 에러 핸들링 로직을 더욱 세분화할 수 있습니다.


    app.use((err, req, res, next) => {
        if (err instanceof CustomError) {
            res.status(err.status).json({ message: err.message });
        } else {
            res.status(500).json({ message: '서버 오류' });
        }
    });
    

5. 응답 구조 설계

클라이언트와 서버 간의 일관된 데이터 구조를 유지하는 것은 매우 중요합니다. 일반적으로 JSON 형식으로 데이터를 송신하며, 응답 구조는 다음과 같이 설계할 수 있습니다:


    {
        "status": "success",
        "data": { /* 관련 데이터 */ },
        "message": "성공적으로 처리되었습니다."
    }
    

5.1. 표준화된 응답 구조

모든 API 응답에 대해 표준화된 구조를 제공하는 것이 좋습니다. 예를 들어, 성공적인 결과와 에러 결과를 모두 동일한 형태로 반환하도록 설정할 수 있습니다.


    const sendResponse = (res, status, data, message) => {
        res.status(status).json({
            status: status >= 400 ? 'error' : 'success',
            data: data || null,
            message: message || ''
        });
    };

    app.get('/items', (req, res) => {
        // 데이터 조회
        const items = [{ id: 1, name: 'item1' }];
        sendResponse(res, 200, items, '아이템 목록 조회 성공');
    });
    

6. 에러 로그 기록

에러가 발생할 경우 이를 로그로 기록하는 것은 매우 중요합니다. 에러를 추적하고, 문제를 신속하게 해결할 수 있도록 돕습니다. Winston과 같은 로깅 라이브러리를 사용할 수 있습니다.


    const winston = require('winston');
    
    const logger = winston.createLogger({
        level: 'error',
        format: winston.format.json(),
        transports: [
            new winston.transports.File({ filename: 'error.log' })
        ],
    });

    app.use((err, req, res, next) => {
        logger.error(err.message);
        res.status(err.status || 500).json({ message: '서버 오류' });
    });
    

7. 결론

에러 핸들링과 응답 구조 설계는 안정적이고, 사용자 친화적인 웹 애플리케이션을 개발하는 데 필수적입니다. Express.js의 유연한 미들웨어 기능을 활용하여 다양한 유형의 에러를 효과적으로 처리하고, 일관된 데이터 구조를 적용하면 개발 효율성을 높일 수 있습니다.

본 강좌가 여러분의 Express 개발 실력을 한 단계 끌어올리는 데 도움이 되었기를 바랍니다. 다음 강좌에서는 더 심화된 내용을 다뤄보겠습니다.

Express 개발 강좌, 기본 라우팅 설정 및 GET, POST 요청 처리

Express.js는 Node.js에서 가장 널리 사용되는 웹 애플리케이션 프레임워크로서,
서버 사이드 웹 개발을 단순화하고, 엔드포인트를 구성하여 빠르고 쉽게 웹 애플리케이션을 구축할 수 있게 해줍니다.
이번 강좌에서는 Express의 기본적인 라우팅 설정 방법과 GET 및 POST 요청을 처리하는 방법에 대해 자세히 살펴보겠습니다.

1. Express.js란?

Express.js는 Node.js 기반의 어플리케이션 프레임워크로, RESTful API와 웹 애플리케이션을 구축하는 데 도움을 줍니다.
Express는 경량화된 구조를 가지고 있어 빠르게 웹 서버를 설정하고, 미들웨어 기능을 통해 HTTP 요청을 보다 손쉽게 처리할 수 있습니다.
또한, 다양한 플러그인과 미들웨어를 통한 확장성이 뛰어납니다.

2. Express 설치 및 기본 설정

Express를 사용하기 위해서는 Node.js가 필요합니다. Node.js가 설치된 후, Express를 설치하는 방법을 살펴보겠습니다.

npm install express

설치가 완료되면, 다음과 같이 Express 애플리케이션을 설정할 수 있습니다.

const express = require('express');
const app = express();
const PORT = 3000;

app.listen(PORT, () => {
    console.log(`서버가 포트 ${PORT}에서 실행되고 있습니다.`);
});

3. 기본 라우팅 설정

Express 애플리케이션에서 라우팅은 HTTP 요청을 특정 URL 경로와 연결하는 과정입니다.
기본적인 라우팅을 설정하는 방법을 살펴보겠습니다.

3.1 기본 GET 요청 처리

GET 요청은 서버에서 데이터를 요청할 때 사용됩니다. 다음과 같이 기본 경로(“/”)에 대한 GET 요청을 처리하는 라우트를 설정할 수 있습니다.

app.get('/', (req, res) => {
    res.send('안녕하세요, Express!');
});

위 코드를 실행한 후 브라우저에서 http://localhost:3000를 방문하면
“안녕하세요, Express!”라는 메시지를 확인할 수 있습니다.

3.2 GET 요청의 URL 매개변수 처리

URL 매개변수는 동적인 경로를 정의할 수 있게 해줍니다. 예를 들어, 사용자 ID를 URL로 전달받는 방법을 알아보겠습니다.

app.get('/user/:id', (req, res) => {
    const userId = req.params.id;
    res.send(`사용자 ID는 ${userId}입니다.`);
});

이를 통해 http://localhost:3000/user/123 라는 URL로 접속하면
“사용자 ID는 123입니다.”라는 메시지를 표시합니다.

3.3 기본 POST 요청 처리

POST 요청은 서버에 데이터를 전송할 때 사용됩니다. Express에서는 POST 요청을 다음과 같이 처리할 수 있습니다.

app.use(express.json()); // JSON 형식의 바디를 파싱하기 위한 미들웨어

app.post('/user', (req, res) => {
    const user = req.body; // JSON 바디에서 사용자 데이터 추출
    res.send(`사용자가 추가되었습니다: ${JSON.stringify(user)}`);
});

위 코드는 사용자의 정보를 JSON 형식으로 POST 요청을 통해 받을 준비를 하고 있습니다.
이 API 호출을 테스트하기 위해 Postman과 같은 도구를 사용할 수 있습니다.

4. GET 및 POST 요청 예제

아래는 GET 및 POST 요청을 처리하는 간단한 예제입니다. 여기에 사용자 정보를 저장하고 검색하는 기능을 추가해보겠습니다.

let users = []; // 사용자 정보를 저장할 배열

// GET 요청: 모든 사용자 정보 조회
app.get('/users', (req, res) => {
    res.json(users);
});

// POST 요청: 신규 사용자 추가
app.post('/users', (req, res) => {
    const newUser = req.body;
    users.push(newUser);
    res.status(201).send(`사용자 ${newUser.name} 추가 성공`);
});

이 API는 사용자의 추가와 조회 기능을 제공하며, 사용자는 JSON 형식으로 데이터를 전송할 수 있습니다. 예를 들어,
다음과 같이 요청을 보내면 새로운 사용자를 추가할 수 있습니다.

{ "name": "홍길동", "age": 30 }

5. 미들웨어 사용

Express의 강력한 기능 중 하나는 미들웨어를 사용하여 요청과 응답 객체를 수정하거나 요청을 처리하는 것입니다.
미들웨어는 요청이 라우터에 도달하기 전에 또는 응답이 클라이언트에 도달하기 전에 실행됩니다.

5.1 기본 미들웨어 설정

app.use(express.json()); // JSON 데이터 파싱 미들웨어
app.use(express.urlencoded({ extended: true })); // URL-encoded 데이터 파싱 미들웨어 

5.2 사용자 정의 미들웨어

사용자 정의 미들웨어를 만들어 요청의 로깅을 수행할 수 있습니다.

app.use((req, res, next) => {
    console.log(`${req.method} 요청에 대한 ${req.url}에 접근했습니다.`);
    next(); // 다음 미들웨어 또는 라우터로 제어를 전달
});

6. 오류 처리

오류 처리는 모든 서버 애플리케이션에서 매우 중요합니다. Express에서는 오류 처리를 위해 특별한 미들웨어를 사용할 수 있습니다.

app.use((err, req, res, next) => {
    console.error(err.stack);
    res.status(500).send('서버 내부 오류 발생');
});

위 미들웨어는 서버에서 발생한 오류를 청구하고, 클라이언트에게 오류 메시지를 전송합니다.

7. 마무리

이번 강좌에서는 Express를 사용하여 기본적인 라우팅을 설정하고, GET 및 POST 요청을 처리하는 방법에 대해 설명했습니다.
Express는 이처럼 간단한 설정으로 강력한 서버를 구성할 수 있도록 도와줍니다.
다음 강좌에서는 데이터베이스와의 연동 및 좀 더 복잡한 기능을 다룰 예정이니 많은 관심 부탁드립니다.

감사합니다!