Express?
์น ์ดํ๋ฆฌ์ผ์ด์ ์ ๋ง๋๋ ๋น ๋ฅด๊ณ ๊ฐ๋ฒผ์ด ํ๋ ์์ํฌ
Client : Front-end part
Server : Back-end part (๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ฑฐ๋ ์ ์ฅ)
RESTful Services
REST: Representational State Transfer
CRUD Operations
HTTP Methods
- GET: getting data
- POST: creating data
- PUT: updating data
- DELETE: deleting data
API example
GET /api/customers
GET /api/customers/1
PUT /api/customers/1
DELETE /api/customers/1
POST /api/customers
- RESTful convention(ํ์ฝ) (customer -> ๊ฐ๋จํ๊ณ ์๋ฏธ์๋ ์ฃผ์ ์ฌ์ฉ)
- Create, update ํ๋๋ฐ ํ์ค http ๋ฉ์๋๋ฅผ ์ฌ์ฉํจ
Introducing Express
- ์ ๋ฒ๊ฐ์ ์ฝ๋(Before)
// app.js
const http = require('http');
const server = http.createServer(function(req, res){
if(req.url === '/'){
res.write('Hello World');
res.end();
}
if(req.url === '/api/courses'){
res.write(JSON.stringify([1,2,3])); // convert this array->JSON syntex
res.end();
}
}); //create web server
server.listen(3000);
console.log('Listening on port 3000...');
ํ์ง๋ง, ์ด๋ ๊ฒํ๋ฉด ์ฌ๋ฌ ๊ฐ์ ๋ผ์ฐํฐ๋ฅผ ๊ฐ์ก์ ๋ if๋ฌธ์ด ๋ง์์ง๋ฉด์ ์ฝ๋๊ฐ ๋ณต์กํด์ง
-> express๋ฅผ ์ฌ์ฉํ์ฌ ๊น๋ํ ๊ตฌ์กฐ๋ก ๋ง๋ค ์ ์๋ค.
Your First Web Server
Handling GET Requests
- ์์ค์ฝ๋
// index.js
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello World');
}) //arg: url(path), callback
app.get('/api/courses', (req, res)=>{
res.send([1, 2, 3]);
});
app.listen(3000, () => console.log('Listening on port 3000'));
* express documentation (http://expressjs.com/en/4x/api.html#req)
- ์คํ๊ฒฐ๊ณผ
+ Tip
Nodemon
- ์ง๊ธ๊น์ง๋ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ ๋๋ง๋ค ์๋ฒ๋ฅผ ์ข ๋ฃ(ctrl+c) ์์ผฐ๋ค๊ฐ ๋ค์ ์คํํ๋ค.
- nodemon์ ์ค์นํ๋ฉด ์๋ฒ๋ฅผ ๊ป๋ค ์ผ์ง ์์๋ ์ ์ ๋ก ๋ณ๋๋ ํ์ผ์ด ์ ์ฉ๋๋ค.
์ค์น
npm i -g nodemon
global๋ก nodemon์ค์น
์คํ
nodemon index.js
node๋ก ์คํํ๋ ๋์ ์ nodemon์ผ๋ก ์คํ
Environment Variables
- Before์ฝ๋์์ ๊ฐ์ ํ ์ : ํฌํธ ๋๋ฒ๊ฐ ํ๋์ฝ๋ฉ ๋์ด ์๋ค.
- ํฌํธ๋๋ฒ๋ ํธ์คํ ํ๊ฒฝ์ ๋ฐ๋ผ ๋์ ์ผ๋ก ํ ๋น๋๊ธฐ ๋๋ฌธ์ด๋ค
- Environment Variables์ ์ด์ฉํ์ฌ ์ด๋ฅผ ๊ฐ์
- Port: ๋๊ณ ์๋ ํ๋ก์ธ์ค์ ํ๊ฒฝ
[์ฝ๋]
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Listening on port ${port}`));
[์คํ๊ฒฐ๊ณผ]
๊ทธ๋ผ, environment port๋ฅผ ์ค์ ํ ํ ์คํํด ๋ณด์
Route Parameters
[์ฝ๋]
app.get('/api/courses/:id', (req, res) => {
res.send(req.params.id);
})
์ฌ๊ธฐ์์ :id๋ parameter์ด๋ค.
[์คํ๊ฒฐ๊ณผ]
- ๋๊ฐ์ ํ๋ผ๋ฏธํฐ๋ ๊ฐ๋ฅํ๋ค.
[์ฝ๋]
app.get('/api/posts/:year/:month', (req, res) => {
res.send(req.params);
})
ํ๋ผ๋ฏธํฐ year์ month
[์คํ๊ฒฐ๊ณผ]
Query string parameter
- ๋ฐฑ์ค๋ ์๋น์ค์ ์ถ๊ฐ์ ์ธ ๋ฐ์ดํฐ๋ฅผ ์ ๊ณตํ๋ค (optional)
- ๋ผ์ฐํฐ ํ๋ผ๋ฏธํฐ๋ก๋ ๊ธฐ๋ณธ์ ์ด๊ณ ํ์ํ ๊ฐ์ ์ ๊ณต
URL: http://localhost:3000/api/post/2020/3?sortBy=name
[์ฝ๋]
app.get('/api/posts/:year/:month', (req, res) => {
res.send(req.query);
})
[์คํ๊ฒฐ๊ณผ]
GET url ์ถ๊ฐ ๋ฐ ์์ธ์ฒ๋ฆฌ(404)
[์ฝ๋] : GET /api/courses/:id
// index.js
const express = require('express');
const app = express();
const courses = [
{ id: 1, name: 'course1'},
{ id: 2, name: 'course2'},
{ id: 3, name: 'course3'},
];
app.get('/', (req, res) => {
res.send('Hello World');
})
app.get('/api/courses', (req, res)=>{
res.send(courses);
});
app.get('/api/courses/:id', (req, res) => {
const course = courses.find(c => c.id === parseInt(req.params.id))
if(!course) res.status(404).send('The course with the given ID was not found');
res.send(course);
});
- find(): javascript์์ ์ด๋ค ๋ฐฐ์ด์์๋ ์ธ ์ ์๋ ํจ์
- object not found -> 404๋ก ์ฒ๋ฆฌ
- req.params.id: string์ ๋ฆฌํดํ๋ค. -> parseInt(์๋ฐ์คํฌ๋ฆฝํธ ํจ์) ์ฌ์ฉ
[์คํ๊ฒฐ๊ณผ]
- Course๊ฐ ๋ชฉ๋ก์ ์์ผ๋ฉด 404์ค๋ฅ, ๋ชฉ๋ก์ ์์ผ๋ฉด ๊ฐ์ข ์ ๋ณด ์ถ๋ ฅ
Handling POST Requests
[์ฝ๋]
// index.js
const express = require('express');
const app = express();
app.use(express.json()); //json parsing ํ๊ธฐ ์ํด ์ฌ์ฉ
const courses = [
{ id: 1, name: 'course1'},
{ id: 2, name: 'course2'},
{ id: 3, name: 'course3'},
];
app.post('/api/courses/', (req, res) => {
const course = {
id: courses.length + 1,
name: req.body.name
};
courses.push(course);
res.send(course);
});
// ๋์ค์๋ id๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํด ์๋์ผ๋ก ํ ๋น๋ ๊ฒ์
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Listening on port ${port}`));
body์ ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด์ผํ๋ค
์ด๋ป๊ฒ ํ ์คํธ?
-> Postman ์ค์น https://www.postman.com/downloads/
[๊ฒฐ๊ณผ]
Input Validation
- ๋ณด์์ ์ํด์๋ ์ ๋ client๊ฐ ๋ณด๋ด๋ ๋ฐ์ดํฐ๋ฅผ ๋ฏฟ์ด์๋ ์๋๋ค.
- ๋ฐ๋ผ์ ์๋ฅผ๋ค์ด ์ด์ ๊ฐ์ด (1) ์ด๋ฆ์ ์์ด์ผํ๊ณ , (2) ๊ธธ์ด๋ ๋ฐ๋์ 3์ด์์ด์ฌ์ผ ํ๋ค. ๋ผ๋ ์กฐ๊ฑด์ ๊ฑธ์ด ์ ํจ์ฑ์ ๊ฒ์ฌํ๋ค.
app.post('/api/courses/', (req, res) => {
if(!req.body.name || req.body.name.length < 3){
// 400 Bad Request
res.status(400).send('Name is required and should be minimum 3 characters.');
return;
}
const course = {
id: courses.length + 1,
name: req.body.name
};
courses.push(course);
res.send(course);
});
ํ์ง๋ง ์ค์ ๋ก๋ input๋ ๋ ๋ง์ ๊ฒ์ด๊ณ ๋ ๋ณต์กํ validation logic์ด ํ์ํ๋ค.
Joi ์ค์น
- Joi๋ ์ด๋ฐ validation ๊ฒ์ฌ๋ฅผ ๊ฐํธํ๊ฒ ํ ์์๋๋ก ์ ๊ณต๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค.
- ์ค์น(Termianl์์) : npm i joi
- ์ํ๋ ๋ฒ์ ์ค์น : npm i joi@13.1.0
[Joi๋ฅผ ์ด์ฉํ input validation]
//๋งจ์์ค์
const Joi = require('joi'); // ํด๋์ค๋ฅผ ๋ฐํํ๋ฏ๋ก ๋ณ์๋ฅผ ๋๋ฌธ์๋ก ํจ
///////////////////////
app.post('/api/courses/', (req, res) => {
const schema = {
name: Joi.string().min(3).required()
};
const result = Joi.validate(req.body, schema);
console.log(result);
if(!req.body.name || req.body.name.length < 3){
// 400 Bad Request
res.status(400).send('Name is required and should be minimum 3 characters.');
return;
}
const course = {
id: courses.length + 1,
name: req.body.name
};
courses.push(course);
res.send(course);
});
[๊ฒฐ๊ณผ]
์ด๋ ๊ฒ ์ฝ๋๋ฅผ ๋ฐ๊ฟ ์ ์๋ค.
const schema = {
name: Joi.string().min(3).required()
};
const result = Joi.validate(req.body, schema);
if(result.error){
res.status(400).send(result.error);
return;
}
[ํฌ์คํธ๋งจ ๊ฒฐ๊ณผ]
์๋ฌ๋ฉ์ธ์ง๋ง ์ถ๋ ฅํ๋๋ก ์ฝ๋ ๋ณ๊ฒฝ
if(result.error){
res.status(400).send(result.error.details[0].message);
return;
}
[๊ฒฐ๊ณผ]
- Joi๋ input์ validateํ๊ณ ํด๋ผ์ด์ธํธ์ ์ ์ ํ ์๋ฌ๋ฉ์ธ์ง๋ฅผ returnํ๋ ๊ฒ์ ๋งค์ฐ ์ฝ๊ฒํ ์ ์๊ฒ ํด์ค
Handling PUT Requests
[PUT Logic]
app.put('/api/courses/:id', (req, res) => {
// Look up the course
// If not existing, return 404
// Validate
// If invalid, return 400 - Bad request
// Update course
// Return the updated course
});
[์์ค์ฝ๋]
// PUT
app.put('/api/courses/:id', (req, res) => {
const course = courses.find(c => c.id === parseInt(req.params.id))
if(!course) res.status(404).send('The course with the given ID was not found');
const { error } = validateCourse(req.body); //result.error
if(error){
res.status(400).send(error.details[0].message);
return;
}
course.name = req.body.name;
res.send(course);
});
function validateCourse(course){
const schema = {
name: Joi.string().min(3).required()
};
return Joi.validate(course, schema);
}
validate ๋ถ๋ถ์ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๋๋ก validateCourseํจ์๋ก ๋ง๋ฆ
[๊ฒฐ๊ณผ]
Handling DELTE Requests
[DELETE Logic]
// DELETE
app.delete('/api/courses/:is', (req, res) => {
// Look up the course
// Not existing, return 404
// Delete
// Return the same course
});
[์ฝ๋]
// DELETE
app.delete('/api/courses/:id', (req, res) => {
const course = courses.find(c => c.id === parseInt(req.params.id))
if(!course) return res.status(404).send('The course with the given ID was not found');
const index = courses.indexOf(course);
courses.splice(index, 1);
res.send(course);
});
[๊ฒฐ๊ณผ]
Fixing a Bug ๋ฐ ์ต์ข ์ฝ๋
// index.js
const Joi = require('joi'); // ํด๋์ค๋ฅผ ๋ฐํํ๋ฏ๋ก ๋ณ์๋ฅผ ๋๋ฌธ์๋ก ํจ
const express = require('express');
const app = express();
app.use(express.json()); //json parsing ํ๊ธฐ ์ํด ์ฌ์ฉ?
const courses = [
{ id: 1, name: 'course1'},
{ id: 2, name: 'course2'},
{ id: 3, name: 'course3'},
];
// GET
app.get('/', (req, res) => {
res.send('Hello World');
})
app.get('/api/courses', (req, res)=>{
res.send(courses);
});
app.get('/api/courses/:id', (req, res) => {
const course = courses.find(c => c.id === parseInt(req.params.id))
if(!course) return res.status(404).send('The course with the given ID was not found');
res.send(course);
});
// POST
app.post('/api/courses/', (req, res) => {
const { error } = validateCourse(req.body); //result.error
if(error) return res.status(400).send(error.details[0].message);
const course = {
id: courses.length + 1,
name: req.body.name
};
courses.push(course);
res.send(course);
});
// PUT
app.put('/api/courses/:id', (req, res) => {
const course = courses.find(c => c.id === parseInt(req.params.id))
if(!course) return res.status(404).send('The course with the given ID was not found');
const { error } = validateCourse(req.body); //result.error
if(error) return res.status(400).send(error.details[0].message);
course.name = req.body.name;
res.send(course);
});
function validateCourse(course){
const schema = {
name: Joi.string().min(3).required()
};
return Joi.validate(course, schema);
}
// DELETE
app.delete('/api/courses/:id', (req, res) => {
const course = courses.find(c => c.id === parseInt(req.params.id))
if(!course) return res.status(404).send('The course with the given ID was not found');
const index = courses.indexOf(course);
courses.splice(index, 1);
res.send(course);
});
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Listening on port ${port}`));
'๐ Archive > Node.js' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Node.js ์์ํ๊ธฐ! [์ ํ๋ธ Node.js beginner ํํ ๋ฆฌ์ผ ์ ๋ฆฌ] (0) | 2020.03.03 |
---|