리팩토링
- 소프트웨어 개발 과정에서 코드를 재구성하여 가독성을 높이고 유지보수를 쉽게 만드는 과정
- 코드의 구조를 개선하고 중복을 제거하여 더 나은 설계 패턴을 도입함으로 코드의 품질을 향상
- 코드의 기능을 변경하지 않으면서 코드를 개선하는 방법
// data/tweet.js
let tweets = [
{
id: '1',
text: '안녕하세요!',
createdAt: Date.now().toString(),
name: '김사과',
username: 'apple',
url: 'https://www.logoyogo.com/web/wp-content/uploads/edd/2021/02/logoyogo-1-45.jpg'
},
{
id: '2',
text: '반갑습니다!',
createdAt: Date.now().toString(),
name: '반하나',
username: 'banana',
url: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTJSRyel4MCk8BAbI6gT_j4DBTEIcY0WW4WWfoklymsWA&s'
}
];
// 모든 트윗을 리턴
export async function getAll() {
return tweets;
}
// 해당 아이디에 대한 트윗을 리턴
export async function getAllByUsername(username){
return tweets.filter((tweet) => tweet.username === username)
}
// 글번호에 대한 트윗을 리턴
export async function getById(id){
return tweets.find((tweet) => tweet.id === id);
}
// 트윗을 작성
export async function create(text, name, username){
const tweet = {
id: '10',
text,
createdAt: Date.now().toString(),
name, // name: name
username // username: username
};
tweets = [tweet, ...tweets];
return tweets;
}
// 트윗을 변경
export async function update(id, text){
const tweet = tweets.find((tweet) => tweet.id === id);
if(tweet) {
tweet.text = text;
}
return tweet;
}
// 트윗을 삭제
export async function remove(id){
tweets = tweets.filter((tweet) => tweet.id !== id);
}
// router/tweets.js
import express from "express";
import * as tweetController from '../controller/tweet.js';
import { body } from 'express-validator';
import { validate } from "../middleware/validator.js";
const router = express.Router();
/*
Post,Put에 text에 대해 빈문자열을 없애고, 최소 3자 이상 입력해야 데이터를 저장하도록 API에 적용
*/
const validateTweet = [
body('text').trim().isLength({min: 3}).withMessage('최소 3자 이상 입력'), validate
]
// 해당 아이디에 대한 트윗 가져오기
// GET
// http://localhost:8080/tweets?username=:username
router.get('/', tweetController.getTweets);
// 글번호에 대한 트윗 가져오기
// GET
// http://localhost:8080/tweets/:id
router.get('/:id', tweetController.getTweet);
// 트윗하기
// POST
// http://localhost:8080/tweets
// name, username, text
// json 형태로 입력 후 추가된 데이터까지 모두 json으로 출력
router.post('/', validateTweet, tweetController.createTweet);
// 트윗 수정하기
// PUT
// http://localhost:8080/tweets/:id
// id, username, text
// json 형태로 입력 후 변경된 데이터까지 모두 json으로 출력
router.put('/:id', validateTweet, tweetController.updateTweet);
// 트윗 삭제하기
// DELETE
// http://localhost:8080/tweets/:id
router.delete('/:id', tweetController.deleteTweet);
export default router;
// controller/tweet.js
import * as tweetRepository from '../data/tweet.js';
// 모든 트윗을 가져오는 함수
export async function getTweets(req, res){
const username = req.query.username;
const data = await (username ? tweetRepository.getAllByUsername(username)
: tweetRepository.getAll());
res.status(200).json(data);
}
// 하나의 트윗을 가져오는 함수
export async function getTweet(req, res, next) {
const id = req.params.id;
const tweet = await tweetRepository.getById(id);
if(tweet) {
res.status(200).json(tweet);
}else {
res.stutus(400).json({message: `${id}의 트윗이 없습니다`})
}
}
// 트윗을 생성하는 함수
export async function createTweet(req, res, next){
const {text, name, username} = req.body;
const tweet = await tweetRepository.create(text, name, username);
res.status(201).json(tweet);
}
// 트윗을 변경하는 함수
export async function updateTweet(req, res, next){
const id = req.params.id;
const text = req.body.text;
const tweet = await tweetRepository.update(id, text);
if(tweet) {
res.status(201).json(tweet);
}else {
res.status(404).json({message: `${id}의 트윗이 없습니다`})
}
}
// 트윗을 삭제하는 함수
export async function deleteTweet(req, res, next){
const id = req.params.id;
await tweetRepository.remove(id);
res.sendStatus(204);
}
express-validator
Express.js를 사용하여 웹 애플리케이션을 개발할 때 입력 데이터의 유효성을 검사하기 위한 패키지
설치
npm i express-validator
isLength(): 문자열 길이 검증
app.get('/:email', [param('email').isLength({min:3}).withMessage('이메일을 입력하세요!'), validate], (req, res, next) => {
res.send('💌');
});
isEmail(): 이메일 주소의 유효성 검증
app.get('/:email', [param('email').isEmail().withMessage('이메일을 입력하세요!'), validate], (req, res, next) => {
res.send('💌');
});
isInt(): 숫자의 최소 또는 최대값 검증
app.get('/:num', [param('num').isInt({min:10, max: 100}).withMessage('숫자의 범위는 10이상 100이하로 입력하세요'), validate], (req, res, next) => {
res.send('❤');
})
matches(): 정규표현식을 사용하여 문자열의 패턴을 검증
app.get('/:name', [param('name').matches(/^[가-힣]+$/).withMessage('이름은 한글로 입력하세요!'), validate], (req, res, next) => {
res.send('❤');
})
//validation.js
import express from 'express';
import {body, param, validationResult} from 'express-validator';
const app = express();
app.use(express.json());
const validate = (req, res, next) => {
const errors = validationResult(req);
if(errors.isEmpty()){
return next();
}
console.log(errors.array());
return res.status(400).json({message: errors.array()[0].msg});
}
app.get('/:email', [param('email').isEmail().withMessage('이메일을 입력하세요!'), validate], (req, res, next) => {
res.send('💌');
});
app.post('/users', [
body('name').trim().isLength({min:2}).withMessage('이름은 두글자 이상을 입력!'),
body('age').isInt().withMessage('나이는 숫자로 입력!'),
body('height').isInt({min:100, max: 200}).withMessage('키는 100이상 200이하로 입력하세요!'),
body('job').notEmpty(),
validate
], (req, res, next) => {
console.log(req.body);
res.sendStatus(201);
})
app.listen(8080);



// middleware/validator.js
import { validationResult } from "express-validator";
export const validate = (req, res, next) => {
const errors = validationResult(req);
if(errors.isEmpty()){
return next();
}
return res.status(400).json({message: errors.array()[0].msg});
}
🤍
ChatGPT에게 물어본 오늘의 공부
✔ validationResult
validationResults는 Express.js와 함께 사용되는 express-validator 미들웨어에서 제공되는 유효성 검사 결과를 담고 있는 객체입니다. 이 객체를 사용하여 요청의 유효성을 확인하고, 필요에 따라 오류 메시지를 처리할 수 있습니다.
express-validator는 Express 애플리케이션에서 입력 데이터의 유효성을 검사하는 데 사용되며, 자주 사용되는 유효성 검사 규칙을 포함하고 있습니다. 이를 통해 사용자로부터 제공된 데이터를 검증하고 오류가 있는 경우 적절한 응답을 보낼 수 있습니다.
validationResults 객체는 express-validator 미들웨어가 수행한 유효성 검사 결과를 담고 있습니다. 주로 라우터 핸들러 함수에서 사용되며, 해당 요청의 유효성 검사 결과를 확인하고 필요한 작업을 수행할 수 있습니다.
일반적으로 사용하는 방법은 다음과 같습니다.
- 라우터 핸들러 함수에서 express-validator를 사용하여 요청 데이터를 유효성 검사합니다.
- req 객체의 validationResults() 메서드를 사용하여 유효성 검사 결과를 가져옵니다.
- 가져온 결과를 분석하여 오류가 있는 경우 적절한 응답을 보냅니다.
예를 들어, 다음은 express-validator를 사용하여 이메일 필드를 검증하고 오류가 있는 경우 적절한 응답을 보내는 코드입니다.

위 코드에서 validationResults 함수는 express-validator의 check() 함수에 의해 수행된 유효성 검사 결과를 반환합니다. 오류가 없는 경우 빈 배열이 반환되며, 오류가 있는 경우 해당 오류들을 담고 있는 배열이 반환됩니다. 이를 통해 요청의 유효성을 확인하고 오류가 있는 경우 적절한 응답을 보낼 수 있습니다.
✔ return next();
return next();는 Express.js 미들웨어에서 다음 미들웨어 함수를 호출하는 역할을 합니다. Express.js에서 요청을 처리하는 라우터 핸들러 함수나 미들웨어 함수는 일반적으로 req, res, next 세 개의 매개변수를 가집니다.
- req: 요청 객체(Request object)로, 클라이언트로부터의 HTTP 요청에 대한 정보를 담고 있습니다.
- res: 응답 객체(Response object)로, 클라이언트로 HTTP 응답을 보내는 데 사용됩니다.
- next: 다음 미들웨어 함수를 호출하는 함수로, 미들웨어 체인에서 제어를 다음 함수로 전달합니다.
미들웨어 함수가 요청을 처리한 후에 다음 미들웨어 함수로 제어를 넘기려면 next() 함수를 호출해야 합니다. 따라서 return next();는 현재 미들웨어 함수의 실행을 중지하고 다음 미들웨어 함수로 제어를 넘기는 역할을 합니다.
일반적으로 Express.js 애플리케이션에서는 미들웨어 함수 체인에서 모든 작업을 순차적으로 처리하기 위해 next() 함수를 호출합니다. 만약 현재 미들웨어 함수에서 오류가 발생하거나 특정 조건을 만족하면 next() 함수를 호출하지 않고 바로 응답을 보내는 경우도 있습니다.
✔ app.listen(8080)
app.listen(8080)은 Express 애플리케이션을 지정된 포트(여기서는 8080)에서 실행시키는 역할을 합니다.
Express 애플리케이션은 HTTP 요청을 받아들이고 처리하기 위해 웹 서버로 동작합니다. app.listen() 메서드를 사용하여 Express 애플리케이션을 웹 서버로 변환하고, 클라이언트의 요청을 대기하며 처리할 수 있게 됩니다.
이 메서드는 포트 번호를 매개변수로 받아들이며, 해당 포트에서 서버를 실행시킵니다. 클라이언트는 이 포트 번호를 사용하여 Express 애플리케이션에 HTTP 요청을 보내고, Express는 해당 요청을 처리하고 응답을 반환합니다.
따라서 app.listen(8080)은 Express 애플리케이션을 8080번 포트에서 실행시키는 것을 의미합니다. 클라이언트는 이 포트를 사용하여 Express 애플리케이션에 요청을 보내고, Express는 이를 처리하여 응답을 반환합니다.
🤍