리팩토링
- 소프트웨어 개발 과정에서 코드를 재구성하여 가독성을 높이고 유지보수를 쉽게 만드는 과정
- 코드의 구조를 개선하고 중복을 제거하여 더 나은 설계 패턴을 도입함으로 코드의 품질을 향상
- 코드의 기능을 변경하지 않으면서 코드를 개선하는 방법
// app.js
import express from "express";
import morgan from "morgan";
import tweetsRouter from './router/tweets.js'
const app = express();
app.use(express.json()); // json로 연결
app.use(morgan("dev"));
app.use('/tweets', tweetsRouter); //tweetsRouter 미들웨어 등록
app.use((req, res, next) => {
res.sendStatus(404);
});
app.listen(8080);
// tweets.js
import express from "express";
import * as tweetController from '../controller/tweet.js';
const router = express.Router();
// 해당 아이디에 대한 트윗 가져오기
// GET
// http://localhost:8080/tweets?username=:username
// http://localhost:8080/tweets?username=banana
router.get('/', tweetController.getTweets);
// 글번호에 대한 트윗 가져오기
// GET
// http://localhost:8080/tweets/:id
// http://localhost:8080/tweets/1
router.get('/:id', tweetController.getTweet);
// 트윗하기
// POST
// http://localhost:8080/tweets
// name, username, text
// json 형태로 입력 후 추가된 데이터까지 모두 json으로 출력
// {
// "id":55,
// "text":"트윗을 추가했어요555",
// "name":"김사과",
// "username":"apple"
// }
router.post('/', tweetController.createTweet);
// 트윗 수정하기
// PUT
// http://localhost:8080/tweets/:id
// http://localhost:8080/tweets/1
// id, username, text
// json 형태로 입력 후 변경된 데이터까지 모두 json으로 출력
// {
// "text":"트윗을 변경했어요!"
// }
router.put('/:id', tweetController.createTweet);
// 트윗 삭제하기
// DELETE
// http://localhost:8080/tweets/:id:
router.delete('/:id', tweetController.deleteTweet);
export default router;
// data/tweet.js
let tweets = [
{
id: '1',
text: '안녕하세요!',
createdAt: Date.now().toString(),
name: '김사과',
username: 'apple',
},
{
id: '2',
text: '반갑습니다!',
createdAt: Date.now().toString(),
name: '반하나',
username: 'banana',
}
];
// 모든 트윗을 리턴
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, // 같은 이름이라면 text: text의 text 생략 가능
createdAt: Date.now().toString(),
name, // 같은 이름이라면 name: name의 name 생략 가능
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);
}
// controller/tweet.js
import * as tweetRepository from '../data/tweet.js';
// 여러 트윗을 가져오는 함수
// getTweets
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);
}
// 하나의 트윗을 가져오는 함수
// getTweet
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.status(404).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);
}
깃
이름 누르고 Commits
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(':하트2:');
})
matches(): 정규표현식을 사용하여 문자열의 패턴을 검증
app.get('/:name', [param('name').matches(/^[가-힣]+$/).withMessage('이름은 한글로 입력하세요!'), validate], (req, res, next) => {
res.send(':하트2:');
})
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.listen(8080);
// 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);
문제
Post, Put에 text에 대해 빈문자열을 없애고, 최소 3자 이상 입력해야 데이터를 저장하도록 API에 적용
// 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
// http://localhost:8080/tweets?username=banana
router.get('/', tweetController.getTweets);
// 글번호에 대한 트윗 가져오기
// GET
// http://localhost:8080/tweets/:id
// http://localhost:8080/tweets/1
router.get('/:id', tweetController.getTweet);
// 트윗하기
// POST
// http://localhost:8080/tweets
// name, username, text
// json 형태로 입력 후 추가된 데이터까지 모두 json으로 출력
// {
// "id":55,
// "text":"트윗을 추가했어요555",
// "name":"김사과",
// "username":"apple"
// }
router.post('/', validateTweet, tweetController.createTweet);
// 트윗 수정하기
// PUT
// http://localhost:8080/tweets/:id
// http://localhost:8080/tweets/1
// id, username, text
// json 형태로 입력 후 변경된 데이터까지 모두 json으로 출력
// {
// "text":"트윗을 변경했어요!"
// }
router.put('/:id', validateTweet, tweetController.createTweet);
// 트윗 삭제하기
// DELETE
// http://localhost:8080/tweets/:id:
router.delete('/:id', tweetController.deleteTweet);
export default router;
// 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});
}