// app.js
import express from 'express'
const app = express();
app.get('/', (req, res) => {
res.json({ message: 'Hello express!' });
}); // 이 때, 이 arow function () => {}을 미들웨어라고 부름
// also 리퀘스트 핸들러라고도 불림
app.listen(3000, () => {
console.log('Server is listening on port 3000')
});
(err, req, res, next)err 파라미터는 throw로 에러를 발생시키거나, next(err) 등으로 사용할 경우에만 사용됨(req, res, next)next 파라미터는 다음 미들웨어 함수를 가리키는 함수로, next() 등으로 사용됨Request 보내서 테스트해보기:
1. npm run dev 명령어로 서버 실행
2. .http 파일에서 Send Request 버튼을 눌러서 요청 보내기
GET http://localhost:3000/hello
.get의 argument로 전달한 순서대로 실행됨import express from 'express'
const app = express();
function meeting(req, res, next) {
console.log('Hello,');
next();
}
function greeting(req, res, next) {
console.log('Express!');
res.json({ message: 'hey Codeit!' })
}
app.get('/hello', meeting, greeting);
app.listen(3000, () => {
console.log('Server is listening on port 3000')
});
.all 메소드를 사용해서 같은 미들웨어를 여러 http 메소드 (get, post, delete ... )에서 중복하여 사용하는 경우 코드를 간결히 작성하는 법// 코드의 변경, 추가, 삭제가 복잡해짐,,
app.get('/hello', greeting);
app.post('/hello', greeting);
app.delete('/hello', greeting);
// 개선된 코드: .all 메소드 사용
app.all('/hello', greeting);
.use 메소드를 활용하여 /hello 주소를 가진 모든 request 보내기// use
app.use('/hello', (req, res, next) => {
console.log('hello, use!');
next();
});
// get: '/hello/world' 주소
app.get('/hello/world', (req, res, next) => {
console.log('hello world');
res.json({ message: 'hey world' });
});
app.use() 메소드는 해당 경로로 시작하는 모든 리퀘스트에 대해 미들웨어를 실행app.all() 메소드는 모든 HTTP 메소드에 대해 해당 경로와 정확하게 일치하는 리퀘스트에 대해 미들웨어를 실행✨ .get()에서 실행 순서는 함수 호출 순서이나, use()와 all()로 불러와진 함수들이 가장 앞에 놓임
function authentication(req, res, next) {
req.user = 'Codeit';
next();
}
app.get('/me', authentication, (req, res, next) => {
console.log(req.user);
res.json({ user: req.user });
});
404 Not Found 상태 코드와 함께 경고메시지 출력function getProduct(req, res, next) {
req.product = products[req.params.id];
if (req.product) {
next();
} else {
res.status(404).json({ message: '존재하지 않는 상품입니다.' });
}
}
function error(req, res, next) {
throw new Error('에러 발생!');
// next(new Error('에러 발생!')) 를 사용해도 동일한 결과!
}
function ok(req, res, next) {
res.json({ message: 'OK!'})
}
app.get('/error', error, ok);
// 직접 ErrorHandler 정의해보기
app.use((error, req, res, next)=>{
console.log(err);
res.json({ message: "에러 핸들러!" });
});
GET http://localhost:3000/error로 request 보내서 확인하기app.use(미들웨어)의 형태로 app.use의 argument로 미들웨어를 넘겨주는 형식을 사용함미들웨어의 종류:
1. express.json()
import express from 'express';
const app = express();
app.use(express.json()); // express.json()
app.post('/products', (req, res) => {
console.log(req.body);
res.json({ message: 'Product 추가하기' });
});
POST http://localhost:3000/products
Content-Type: application/json
{
"name": "상품1",
"price": 100
}
express.urlencoded() // express.urlencoded()
app.use(express.urlencoded({ extended: true }));
app.post('/users', (req, res) => {
console.log(req.body);
res.json({ message: 'User 추가하기' });
})
app.listen(3000, () => {
console.log('Server is listening on port 3000');
});
POST http://localhost:3000/users
Content-Type: application/x-www-form-urlencoded
name=codeit&age=22
express.static()app.use(express.static('public'));
public 디렉토리에 속한 파일 명으로 리퀘스트를 보내서 해당 파일들에 접근할 수 있게 됨
GET http://localhost:3000/codeit.png
###
GET http://localhost:3000/index.html
codeit.png, index.html 파일은 public 폴더에 저장된 파일들임
https://www.codeit.kr/topics/express-core-features/lessons/8924
.route(중복된 경로) 메소드를 사용하면 중복되는 경로들을 묶어서 표현할 수 있음!import express from 'express';
const app = express();
app.route('/products')
.get((req, res) => {
res.json({ message: 'Product 목록 보기' });
})
.post((req, res) => {
res.json({ message: 'Product 추가하기' });
});
app.route('/products/:id')
.patch((req, res) => {
res.json({ message: 'Product 수정하기' });
})
.delete((req, res) => {
res.json({ message: 'Product 삭제하기' });
});
app.listen(3000, () => {
console.log('Server is listening on port 3000');
});
import express from 'express';
const app = express();
const productRouter = express.Router();
productRouter.route('/')
.get((req, res) => {
res.json({ message: 'Product 목록 보기' });
})
.post((req, res) => {
res.json({ message: 'Product 추가하기' });
});
productRouter.route('/:id')
.patch((req, res) => {
res.json({ message: 'Product 수정하기' });
})
.delete((req, res) => {
res.json({ message: 'Product 삭제하기' });
});
app.use('/products', productRouter);
app.listen(3000, () => {
console.log('Server is listening on port 3000');
});
import express from 'express';
const app = express();
const productRouter = express.Router();
productRouter.use((req, res, next) => {
console.log('productRouter에서 항상 실행!');
// product로 시작하는 모든 경로에서 항상 실행됨!
next();
});
productRouter.route('/')
.get((req, res) => {
res.json({ message: 'Product 목록 보기' });
})
.post((req, res) => {
res.json({ message: 'Product 추가하기' });
});
productRouter.route('/:id')
.patch((req, res) => {
res.json({ message: 'Product 수정하기' });
})
.delete((req, res) => {
res.json({ message: 'Product 삭제하기' });
});
app.use('/products', productRouter);
app.listen(3000, () => {
console.log('Server is listening on port 3000');
});
경로가 /products로 시작하는 라우트는 누구나 조회, 생성, 수정, 삭제가 가능하지만, 경로가 /users로 시작하는 라우트는 관리자만 조회, 생성, 수정, 삭제가 가능한 API 서버를 만드려고 합니다.
Authorization 헤더에 s3cret이라는 문자열 값으로 포함하여 리퀘스트를 보낸 경우 관리자로 인증되고, 키가 없거나 잘못된 값이 포함되어 있는 경우 401 Unauthorized 상태 코드와 함께 메시지 객체를 리스폰스로 반환해 주세요. 메시지 객체는 아래의 리스폰스 바디를 확인해 주세요.
import express from 'express';
const app = express();
// User Router
const userRouter = express.Router();
userRouter.route('/')
.get((req, res, next) => {
res.json({ message: '사용자 목록 보기' });
})
.post((req, res, next) => {
res.json({ message: '사용자 추가하기' });
});
userRouter.route('/:id')
.patch((req, res, next) => {
res.json({ message: '사용자 수정하기' });
})
.delete((req, res, next) => {
res.json({ message: '사용자 삭제하기' });
});
function adminOnly(req, res, next) {
const authorization = req.get('Authorization');
if (authorization === 's3cret') {
next();
} else {
res.status(401).json({ message: '권한이 없습니다.' });
}
}
app.use('/users', adminOnly, userRouter);
// Product Router
const productRouter = express.Router();
productRouter.route('/')
.get((req, res, next) => {
res.json({ message: '상품 목록 보기' });
})
.post((req, res, next) => {
res.json({ message: '상품 추가하기' });
});
productRouter.route('/:id')
.patch((req, res, next) => {
res.json({ message: '상품 수정하기' });
})
.delete((req, res, next) => {
res.json({ message: '상품 삭제하기' });
});
app.use('/products', productRouter);
app.listen(3000, () => {
console.log('Server is listening on port 3000');
});
// src > routes > product.js
import express from 'express';
const productRouter = express.Router();
productRouter.use((req, res, next) => {
console.log('Product Router에서 항상 실행!');
next();
})
productRouter.route('/')
.get((req, res) => {
res.json({ message: 'Product 목록 보기' });
})
.post((req, res) => {
res.json({ message: 'Product 추가하기' });
});
productRouter.route('/:id')
.patch((req, res) => {
res.json({ message: 'Product 수정하기' });
})
.delete((req, res) => {
res.json({ message: 'Product 삭제하기' });
});
export default productRouter;
// src > routes > user.js
import express from 'express';
const userRouter = express.Router();
userRouter.get('/', (req, res, next) => {
res.json({ message: 'User 목록 보기' });
});
export default userRouter;
// src > middlewares > always.js
export default function (req, res, next) => {
console.log('나는 항상 실행!');
next();
}
// app.js
import express from 'express';
import productRouter from './routes/product.js';
import userRouter from './routes/user.js';
import always from '.middlewares/always.js';
const app = express();
app.use(always);
app.use('/products', productRouter);
app.use('/users', userRouter);
app.listen(3000, () => {
console.log('Server is listening on port 3000');
});
// app.js
import express from 'express';
import productRouter from './routes/product.js'
import userRouter from './routes/user.js'
import always from './middlewares/always.js';
import multer from 'multer';
const app = express();
app.use(always);
app.use('/products', productRouter);
app.use('/users', userRouter);
const upload = multer({ dest: 'uploads/' });
app.post('/files', upload.single('attatchment'), (req, res) => {
res.json({ message: '파일 업로드 완료!' });
});
app.listen(3000, () => {
console.log('Server is listening on port 3000');
});
POST http://localhost:3000/files
Content-Type: multipart/form-data; boundary=Boundary01234567890123456789
--Boundary01234567890123456789
Content-Disposition: form-data; name="attachment"; filename="hello.txt"
Content-Type: text/plain
Hello!
--Boundary01234567890123456789--
// users.js
import express from 'express';
const userRouter = express.Router();
userRouter.get('/', (req, res, next) => {
res.json({ message: 'User 목록 보기' });
});
export default userRouter;
// app.js
import express from 'express';
import productRouter from './routes/product.js'
import userRouter from './routes/user.js'
import always from './middlewares/always.js';
import multer from 'multer';
const app = express();
app.use(always);
app.use('/products', productRouter);
app.use('/users', userRouter);
const upload = multer({ dest: './uploads/' });
app.post('/files', upload.single('attachment'), (req, res) => {
console.log(req.file);
res.json({ message: '파일 업로드 완료!'});
});
app.listen(3000, () => {
console.log('Server is listening on port 3000');
});