Javascript

[JS] Express 기초

kyoulho 2024. 8. 2. 18:32

Express 설치 및 초기 설정


Express란?

Express는 Node.js를 위한 빠르고 간결한 웹 프레임워크이다. 미들웨어와 라우팅 기능을 제공하여 서버와 API를 쉽게 구축할 수 있게 도와준다.

프로젝트 초기 설정

mkdir express-api
cd express-api
npm init -y
npm install express mongoose cors
npm install --save-dev typescript ts-node @types/node @types/express @types/cors
npx tsc --init

TypeScript 설정

tsconfig.json 파일을 생성하고 다음과 같이 설정한다.

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src"]
}


엔드포인트 만들기


엔트리 포인트 설정

프로젝트 구조는 아래와 같다.

express-api
│
├── src
│   ├── routes
│   ├── middleware
│   ├── controllers
│   ├── models
│   ├── app.ts
│   └── index.ts
└── tsconfig.json

src/app.ts

import express, { Application } from 'express';
import cors from 'cors';
import { json, urlencoded } from 'body-parser';
import userRouter from './routes/user';

const app: Application = express();

// 미들웨어 설정
app.use(cors());
app.use(json());
app.use(urlencoded({ extended: true }));

// 정적 파일 제공
app.use(express.static('public'));

// 라우터 설정
app.use('/api/users', userRouter);

export default app;

src/index.ts

import app from './app';
import mongoose from 'mongoose';

const PORT = process.env.PORT || 3000;
const MONGO_URI = process.env.MONGO_URI || 'your_mongodb_connection_string_here';

mongoose.connect(MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
  .then(() => {
    console.log('MongoDB connected successfully');
    app.listen(PORT, () => {
      console.log(`Server is running on port ${PORT}`);
    });
  })
  .catch((err) => {
    console.error('Failed to connect to MongoDB', err);
  });

 

미들웨어와 use()


미들웨어는 요청(Request)과 응답(Response) 사이에 실행되는 콜백 함수로, 요청을 처리하거나 응답을 수정하는 등의 작업을 수행할 수 있다. 미들웨어는 app.use()를 통해 설정한다.

const middleware = (req, res, next) => {}

여기서 next는 함수인데 이 함수를 호출하면 모든 것이 정상으로 동작한다. 그러나 next를 호출하지 않으면 이 미들웨어 다음에 메서드 체인으로 연결된 메서드들이 호출되지 않는다.

로깅 미들웨어 추가

import { Request, Response, NextFunction } from 'express';

const logger = (req: Request, res: Response, next: NextFunction) => {
  console.log(`url=${req.url}', method=${req.method}`);
  next();
};

export default logger;

src/app.ts에 로깅 미들웨어 추가

import logger from './middleware/logger';

app.use(logger);

 

정적 파일 제공: express.static


express.static이란 이름의 미들웨어를 사용하여 익스프레스 객체가 정적 파일을 제공할 수 있다. 하

src/app.ts에 정적 파일 미들웨어 추가

/public 디렉터리 밑에 파일들을 정적 파일로 제공한다.

app.use(express.static('public'));

 

JSON 파싱 미들웨어: express.json


클라이언트가 서버로 보내는 JSON 형식의 요청 본문을 파싱 하여 사용할 수 있도록 하는 미들웨어이다.

src/app.ts에 JSON 파싱 미들웨어 추가

app.use(express.json());

 

CORS 미들웨어


cors 패키지는 서버 응답에 cors 헤더를 설정하거나, 클라이언트가 보내는 프리플라이트 요청에 자동으로 응답하고, 허용할 정책을 관리할 수 있는 기능을 제공한다.

 

CORS 미들웨어 추가

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

// CORS 옵션 설정
const corsOptions = {
  origin: 'http://example.com', // 허용할 출처
  methods: 'GET,POST,PUT,DELETE', // 허용할 메서드
  allowedHeaders: 'Content-Type,Authorization', // 허용할 헤더
  credentials: true, // 쿠키 등 자격 증명 허용
};

app.use(cors(corsOptions));

 

라우터 설정


app 객체의 use 메서드에서 사용하는 경로는 절대 경로이지만, 라우터 객체 내부에서 사용하는 경로는 상대 경로이다.

import userRoutes from './routes/user')

app.use('/users', userRoutes);

src/routes/user.ts

import { Router } from 'express';
import { getUser, createUser, updateUser, deleteUser } from '../controllers/userController';

const router: Router = Router();

router.get('/:id', getUser);
router.post('/', createUser);
router.put('/:id', updateUser);
router.delete('/:id', deleteUser);

export default router;

src/controllers/userControllers.ts

import { Request, Response } from 'express';
import User from '../models/user';

export const getUser = async (req: Request, res: Response) => {
  try {
    const user = await User.findById(req.params.id);
    if (!user) return res.status(404).json({ message: 'User not found' });
    res.json(user);
  } catch (error) {
    res.status(500).json({ message: error.message });
  }
};

export const createUser = async (req: Request, res: Response) => {
  try {
    const user = new User(req.body);
    await user.save();
    res.status(201).json(user);
  } catch (error) {
    res.status(400).json({ message: error.message });
  }
};

export const updateUser = async (req: Request, res: Response) => {
  try {
    const user = await User.findByIdAndUpdate(req.params.id, req.body, { new: true });
    if (!user) return res.status(404).json({ message: 'User not found' });
    res.json(user);
  } catch (error) {
    res.status(400).json({ message: error.message });
  }
};

export const deleteUser = async (req: Request, res: Response) => {
  try {
    const user = await User.findByIdAndDelete(req.params.id);
    if (!user) return res.status(404).json({ message: 'User not found' });
    res.json({ message: 'User deleted successfully' });
  } catch (error) {
    res.status(500).json({ message: error.message });
  }
};

 

 

728x90