1. Express란?
- Node.js 환경에서 실행되는 서버 프로그램을 만들 때 사용하는 프레임워크
- 서버 프로그램에 필요한 최소한의 기능만 제공하고 프로그램의 전체적인 구조는 개발자가 자유롭게 구현할 수 있음
- 자유도가 높은 프레임워크
2. API 서버란?
- Server의 두가지 종류
1) 웹페이지를 Response의 Body에 담아서 보내주는 서버 = Web Server
- 화면을 그리는데 필요한 재료를 Response의 Body에 담아서 줌
2) 요청을 처리하고 처리한 결과를 Response의 Body에 담아서 보내주는 서버 = API Server
- 요청한 작업을 처리하고 처리한 결과를 Response의 Body에 JSON 등의 형식으로 담아서 줌
3. Express 사용해보기
- 현재 디렉토리를 패키지로 만드는 방법 - npm init
- Express 패키지 설치 - npm install express
- 특정 Path에 대응하는 콜백 = 라우트 핸들러 (route handler)
- route는 서버가 각 리퀘스트의 path 부분을 보고 알맞은 작업을 수행하는것
- handler는 그 작업을 담당하는 존재를 의미
- 첫번째 파라미터 req => request 객체로, 이 객체를 통해서 클라이언트가 보낸 리퀘스트를 다룰 수 있음
- 두번째 파라미터 res => response 객체로, 이 객체를 통해서 적절한 리스폰스를 보낼 수 있음
- 포트 번호 (Port Number)
- 서버 안에서 실행되는 여러 프로그램들 중 특정 프로그램을 식별할 수 있게 해주는 번호
//Express 패키지에서 공개하는 것을 가져와야 함
const express = require('express');
//Express 패키지는 함수 하나를 외부에 공개해야함
const app = express();
//외부의 클라이언트가 보낸 리퀘스트의 URL Path 부분이
// /hello라면 함수가 실행
// 콜백 = 특정 조건이 만족되었을 때 실행되는 함수
app.get('/hello', (req,res)=> {
res.send('<h1>Hello Express</h1>');
});
//외부에서 리퀘스트가 오는것을 기다리도록 하는 메소드
//이것까지 써줘야 프로그램이 외부의 리퀘스트를 받을 수 있음
//포트번호 3000
app.listen(3000);
- 터미널 창에서 node app.js를 입력하면 서버 프로그램 실행
- 서버 프로그램이 지금 브라우저가 실행 중인 컴퓨터와 같은 컴퓨터에서 실행되고 있기 때문에 localhost라고
- 서버가 외부의 리퀘스트를 들을 준비를 마치고 나면 자동으로 실행
- 서버가 정상적으로 실행되었는지를 확인하기 위해서 listen 메소드에 이런 식의 콜백을 넣어주는 것이 좋
app.listen(3000, () => {
console.log('Server is listening...');
});
4. 직원 정보 조회하기
- Cowork의 직원 정보 관리 웹 서비스에서 사용할 API 서버 제작
- 실제 서비스에서는 직원 정보 같은 데이터를 저장하기 위해서 데이터베이스를 사용
- 여기에서는 직원정보를 배열로 관리
- send 메소드에 배열을 넣으면 배열을 JSON 문자열로 변환한 결과를 response의 Body에 담아서 보내주게
members.js
module.exports = [
{
id: 1,
name: 'Alex',
team: 'engineering',
position: 'Server Developer',
emailAddress: 'alex@google.com',
phoneNumber: '010-xxxx-xxxx',
admissionDate: '2018/12/10',
birthday: '1994/11/08',
profileImage: 'profile1.png',
......
},
app.js
const express = require('express');
const app = express();
let members = require('./members');
app.get('/api/members', (req,res)=> {
res.send(members);
});
app.listen(3000, () => {
console.log('Server is listening...');
});
Route Parameter
- path 부분에서 가변적인 값이 전달되는 부분에 사용
- Route Parameter의 값은 req 객체의 params라고 하는 객체의 프로퍼티로 설정
- req.params.id로 id 값을 가져올 수 있음
- 직원 정보 배열에 있는 여러 객체들 중에서 해당 id 값을 가진 객체를 찾기 위해 배열의 find 메소드를 사용
- find는 그 인자로 들어온 콜백 함수가 true를 리턴하게 하는 배열의 여러 요소들 중에서 첫 번째 요소를 리턴
- 만약 해당 id를 가진 직원 정보가 있다면 그 직원 정보를 그대로 response에 담아서 보내주도록 함
app.js
...
//members/뒤에 오는 값을 id변수에 대입
//라우트 파라미터(Route Parameter)
app.get('/api/members/:id', (req,res)=> {
//const id = req.params.id;
const {id} = req.params;
const member = members.find((m)=>m.id === Number(id));
if(member) {
res.send(member);
}else {
//404 : 요청한 정보가 없다는 걸 나타냄
res.status(404).send({message:"There is no such member"});
}
});
...
5. 리소스란?
리소스(Resource)
- 서버에 저장돼 있는 수많은 정보
6. 특정 팀만 조회하기
- URL 끝에 ? 이후의 부분을 쿼리(Query)라고 함
- 쿼리는 서버에 있는 데이터를 조회할 때 기준을 정하기 위해 사용
- URL에 team이라는 파라미터 값이 있는 경우에는 전체 직원 정보들 중에서 해당 팀에 속한 직원들만 추리면 됨
- filter 메소드는 배열의 각 요소를 순회하면서 인자로 들어온 콜백이 true를 리턴하는 요소들만 모아서 새로운 배열을 만듬
app.js
app.get('/api/members', (req,res)=> {
const { team } = req.query;
if(team) {
const teamMembers = members.filiter((m)=> m.team === team);
res.send(teamMembers);
}else {
res.send(members);
}
});
7. POST 리퀘스트를 보내는 방법
- app 객체의 get 함수가 실행되려면 request의 메소드가 GET이어야 한다는 조건이 필요
- app 객체의 get 함수는 특정 path로 오는, GET 메소드를 가진 리퀘스트를 처리하는 라우트 핸들러를 등록함
- 기존 리소스를 수정하려는 PUT 리퀘스트, 기존 리소스를 삭제하려는 DELETE 리퀘스트도 있음
POST 리퀘스트 보내기
- app 객체의 POST 함수 사용
-새로 추가하려고 하는 리소스의 내용이 해당 리퀘스트의 바디에 담겨있어서 서버에서 바디의 내용을 별도로 처리해줘야 함
app.js
app.post('/api/members', (req,res) => {
console.log(req.body);
});
rest client 플러그인 설치
-> VS Code에서 바로 리퀘스트를 보내고 리스폰스를 볼 수 있음
- 헤드 뿐만 아니라 바디도 있음
- 헤드에는 POST 메소드, 리퀘스트를 보낼 URL
- 바디에는 데이터의 타입을 나타내는 Content-Type헤더가 들어 있음
(applicaiton/json 값은 바디에 있는 데이터 타입이 JSON이라는 뜻)
8. 새 직원 정보 추가하기
- express를 사용할 때 바디가 있는 리퀘스트를 처리하려면 특정 코드를 추가해줘야함
app.js
app.use(express.json());
- express.json() 메소드는 함수를 리턴
-> 그 함수는 서버로 온 리퀘스트의 바디에 JSON 데이터가 존재할 경우에 그것을 추출해서 리퀘스트 바디의 body 프로퍼티의 값으로 설정
-> 리퀘스트가 라우트 핸들러에 의해 처리되기 전에 추가적으로 필요한 전처리를 수행하는 함수를 미들웨어(middleware)라고
- 리퀘스트가 들어오게 되면 middleware에 의해서 바디에 있는 JSON 데이터가 res 객체의 body 프로퍼티에 설정되고
리퀘스트의 path와 메소드를 보고 알맞은 라우트 핸들러가 호출
app.use(express.json());
app.use((req, res, next) => {
console.log(req.query);
next();
});
- 미들웨어는 형식적으로 req, res, next 이렇게 3개의 파라미터를 가진 함수이고, 기능적으로는 라우트 핸들러 이전에 리퀘스트에 관한 처리를 해주는 함수
- 미들웨어는 app 객체의 use 메소드로 설정할 수 있음
- 미들웨어 안에서 원하는 처리를 모두 수행한 후에는 마지막에 next를 호출하여 리퀘스트를 그 다음 미들웨어 또는 라우트 핸들러로 넘겨줘야 함
9. nodemon과 npm start
- 코드가 실행되면 자동으로 프로그램도 재실행되도록 nodemon 패키지 사용
- nodejs.18 버전부터는 nodemon 패키지를 설치하지 않아도 node --watch server.js 로 사용 가능
package.json
"scripts": {
"start" : "node app.js"
},
- npm start라고만 써도 서버를 실행할 수 있음
10. --save-dev 옵션의 의미
1) --save-dev 옵션없이 설치했을 떄
- dependencies 필드에 nodemon 패키지가 보임
2) --save-dev 옵션을 주고 설치했을 때
- dependencies 필드가 아니라 devDependencies 필드에 nodemon 패키지의 정보가 있다는 것을 알 수 있음
- 프로젝트의 코드를 실행하는 경우
1. 개발/테스트 목적의 코드 실행
- 첫 개발부터 시작해서 중간중간 코드를 제대로 작성해가고 있는 건지를 테스트하기 위한 목적에서의 코드 실행
2. 실제 서비스 제공을 위한 코드 실행
- 충분한 검증을 거진 코드를 서비스 제공 목적으로 배포해서 실행하기 위한 목적에서의 코드 실행
- 배포 용도로는 필요하지 않고 개발 용도로만 필요한 패키지를 설치할 때 --save-dev 옵션을 사용
- 하나의 프로젝트에서
- 배포 용도로 필요한 패키지들은 dependencies 필드에,
- 개발 용도로만 필요한 패키지들은 devDependencies 필드에, 그 정보가 기재되어야 함
- 프로젝트의 코드를 배포 용도로 실행하기 전 과정
1. 실제 개발 중이던 프로젝트 디렉토리를 하나 더 복사
2. 새 디렉토리에서 node_modules 디렉토리 삭제
3. npm install --production를 실행해서 devDepencencies 필드에 있던 패키지들은 제외하고, dependencies 필드에 있던 패키지들만 node_modules 디렉토리에 재설치
4. 실제 서비스를 위해 코드 실행 (npm start 등 실행)
11. 기존 직원 정보 수정하기
- 서버에 있는 기존의 직원 정보를 수정하는 PUT 리퀘스트를 처리
- 해당 id를 가진 객체가 있으면 새 정보의 내용대로 해당 객체의 모든 프로퍼티의 값을 수
app.js
app.put('/api/members:id', (req,res) => {
const { id } = req.params;
const newInfo = req.body;
const member = members.find((m)=> m.id === Number(id));
if(member) {
Object.keys(newInfo).forEach((prop) => {
member[prop] = newInfo[prop];
});
res.send(member);
}else {
res.status(404).send({message: 'There is no member with the id:'});
}
});
12. 객체의 프로퍼티 순회하기
- 자바스크립트에서 특정 객체가 갖고 있는 모든 프로퍼티를 확인할 수 있는 방법
1) Object.keys
- 특정 객체의 모든 프로퍼티를 조회
if (member) {
Object.keys(newInfo).forEach((prop) => {
member[prop] = newInfo[prop];
});
res.send(member);
2) Object.entries
- 각 프로퍼티의 이름(key) - 값(value) 쌍을 담은 배열을 리턴하는 메소드
const newInfo = {
id: 11,
name: 'William',
team: 'Engineering',
position: 'Android Developer',
emailAddress: 'zake@google.com',
phoneNumber: '010-xxxx-xxxx',
admissionDate: '2021/06/12',
birthday: '1995/09/27',
profileImage: 'profile11.png',
};
console.log(Object.entries(newInfo)); // !
- [프로퍼티 이름, 프로퍼티 값] 배열들이 담긴 하나의 배열이 리턴
- 프로퍼티의 이름 뿐만 아니라 프로퍼티의 값도 바로 동시에 가져오는 것이 가능
const newInfo = {
id: 11,
name: 'William',
team: 'Engineering',
position: 'Android Developer',
emailAddress: 'zake@google.com',
phoneNumber: '010-xxxx-xxxx',
admissionDate: '2021/06/12',
birthday: '1995/09/27',
profileImage: 'profile11.png',
};
Object.entries(newInfo).forEach((pair) => {
console.log(`Key: ${pair[0]} => Value: ${pair[1]}`);
});
3) for...in 구문
- for ...in 구문을 써서 한 객체의 프로퍼티를 순회하는 것도 가능
const newInfo = {
id: 11,
name: 'William',
team: 'Engineering',
position: 'Android Developer',
emailAddress: 'zake@google.com',
phoneNumber: '010-xxxx-xxxx',
admissionDate: '2021/06/12',
birthday: '1995/09/27',
profileImage: 'profile11.png',
};
for (const property in newInfo) {
console.log(property);
}
- 프로퍼티의 값도 출력하려면
const newInfo = {
id: 11,
name: 'William',
team: 'Engineering',
position: 'Android Developer',
emailAddress: 'zake@google.com',
phoneNumber: '010-xxxx-xxxx',
admissionDate: '2021/06/12',
birthday: '1995/09/27',
profileImage: 'profile11.png',
};
for (const property in newInfo) {
console.log(`Key: ${property} => Value: ${newInfo[property]}`);
}
13. 기존 직원 정보 삭제하기
- 기존 직원 정보를 삭제하는 DELETE 리퀘스트 처리
- DELETE 리퀘스트를 처리하는 라우트 핸들러는 app 객체의 delete 메소드로 등록
- 직원 정보를 삭제하려면 직원 정보 배열에서 해당 직원의 정보 객체만 삭제해주면 됨
- 배열의 filter 메소드를 사용해 기존의 직원 정보 배열에서 삭제할 직원 정보 id값과 일치하지 않는 요소들만 추려내서
새로운 배열을 만들고 그 배열을 새로운 직원 정보 배열로 설정
- 삭제되었다는 문장을 메시지로 돌려 보내줌
app.js
app.delete('/api/members/:id',(req,res) => {
const { id } = req.params;
const memberCount = members.length;
members = members.filter((member) => member.id != Number(id));
if(members.length < membersCount) {
res.send({message: 'Deleted'});
} else {
res.status(404).send({messge: 'There is no member with the id!'});
}
});
'Node.js' 카테고리의 다른 글
[코드잇] ORM으로 하는 데이터베이스 작업 (0) | 2023.10.26 |
---|---|
[코드잇] 서드파티 모듈과 npm 제대로 배우기 (1) | 2023.10.24 |
[코드잇] 초간단 웹서버 만들기 (0) | 2023.10.07 |
[코드잇] Node.js 기본 개념 (1) | 2023.10.04 |