배꼽파지 않도록 잘 개발해요

[코드잇] Express 기본기 - ① Express 기본 익히기 본문

코드잇 Codeit/Back-End

[코드잇] Express 기본기 - ① Express 기본 익히기

꼽파 2024. 1. 23. 17:26


◆ Express 기본 익히기

◆ ORM으로 하는 데이터베이스 작업

◆ 배포하기


Express 기본 익히기

Express

· Node.js 환경의 서버 프로그램을 만들 때 사용하는 프레임워크
· fast, unopinionated(고집이 세지 않은), minimalist
- express는 서버프로그램에 필요한 최소한의 기능만 제공함.
- 자유도가 높음

 

폴더 안에 app.js 파일 만들기

npm init

 

익스프레스 설치

npm install express

 

외부 클라이언트가 보낸 리퀘스트의 URL 패스 부분이 /hello라면 여기 있는 함수가 실행됨.

const express = require('express');

const app = express();  // 함수가 리턴하는 객체 = app

app.get('/hello', (req, res) => {
    res.send('<h1>Hello Express</h1>');
});

app.listen(3000);

 

라우터 핸들러(router handler) : 특정 path에 대응하는 콜백

- route : 서버가 각 리퀘스트의 path부분을 보고 알맞은 작업을 수행
- handler : 작업을 담당하는 존재

(req, res) => {
    res.send('<h1>Hello Express</h1>');
});

 

listen : 외부 리퀘스트를 기다림

포트번호 : 서버 안에서 실행되는 여러 프로그램들 중 특정 프로그램을 식별할 수 있게 해주는 번호

app.listen(3000);

 

해당 주소로 접속

http://localhost:3000/hello

 

서버가 정상적으로 동작하는지 확인하기 위해 화면 출력함.

app.listen(3000, () => {
    console.log('Server is listening...');
});


API 서버

Sever 

  • 웹 서버 : 웹 페이지를 Reponse의 Body에 담아서 보내주는 서버
  • API 서버 : 클라이언트의 요청을 처리하고 처리한 결과를 Response의 Body에 담아서 보내주는 서버

하나의 컴퓨터가 두 가지 역할을 동시에 할 수 있음.
실무에서는 개발의 편리함, 트래픽 분산을 위해 따로 만드는 경우가 많음.

Cowork라는 직원 정보 관리 서비스를 위한 API 서버


직원 정보 조회하기

전체 직원 정보 조회

const express = require('express');

const app = express();  // 함수가 리턴하는 객체 = app

const members = require('./members')

app.get('/api/members', (req, res) => {
    res.send(members);
});

app.listen(3000, () => {
    console.log('Server is listening...');
});

send(members) : send 메소드가 배열을 json 문자열로 변환한 결과를 response의 body에 담아서 보내줌

 

API 서버에 관한 URL은 path부분에 api를 포함시켜줌
도메인 자체에 api를 넣어서 API 서버에 관한 URL임을 나타내기도 함.

 

특정 직원 정보 조회

const express = require('express');

const app = express();  // 함수가 리턴하는 객체 = app

const members = require('./members')

app.get('/api/members', (req, res) => {
    res.send(members);
});

app.get('/api/members/:id', (req, res) => {
    const { id } = req.params;
    const member = members.find((m) => m.id === Number(id));
    if (member) res.send(member);
    else res.status(404)  // 요청한 정보가 없다
            .send({ message: 'There is no such member' });  // 이런 문장도 JSON 객체 안에 넣어주는게 좋음.
});


app.listen(3000, () => {
    console.log('Server is listening...');
});

 

:id의 의미

· 'members/' 뒤에 오는 값들을 id에 담으라는 의미
· 라우트 파라미터(Route Parameter) : 변하는 값을 담는 부분, string 타입
· 라우트 파라미터 값은 req 객체의 params라고 하는 객체의 프로퍼티로 설정됨.

 

구조분해 할당

    const { id } = req.params;

params 객체에서 id라는 프로퍼티 값만 id 변수에 담음.

 

 


리소스

Resource : 서버에 저장돼 있는 수많은 정보
ex. 쇼핑몰 : 회원이나 상품들의 정보, 주문 내역 등 


특정 팀만 조회하기

http://localhost:3000/api/members?team=engineering
http://localhost:3000/api/members?team=marketing
http://localhost:3000/api/members?team=sales

 

· ? 이후의 부분 : 쿼리(Query)

서버에 있는 데이터를 조회할 때 기준을 정하기 위해 사용

 

· app 객체의 get 함수는 특정 path로 오는 Get 메소드를 가진 request를 처리하는 라우터 핸들러를 등록함.

app.get('/api/members', (req, res) => {
    const { team } = req.query;  // 물음표 뒷부분(쿼리) team으로 받음
    if (team) {  // 해당하는 team을 보내기
        const teamMembers = members.filter((m) => m.team === team);
        res.send(teamMembers);
    } else {  // 아니면 전체 직원 정보를 보내기
        res.send(members);
    }
});

 

req 객체의 query라고 하는 객체에는 URL의 쿼리에 표시한 여러 파라미터들의 값이 담겨 있음.

const team = req.query.team;
const { team } = req.query

 

별도로 처리하지 않은 파라미터에 대해서는 전체 직원 정보가 출력됨.


POST 리퀘스트를 보내는 방법

app 객체의 post 함수 사용
- body의 내용을 서버에서 별도로 처리해줘야 함.
- 일반 브라우저에서는 POST 리퀘스트를 보낼 수 없음.

 

VSCode에서 바로 POST 리퀘스트로 보내는 법
- REST Client 프로그램 설치
- test.http 파일 생성 후 안에 보낼 리퀘스트 내용을 작성하면  VSCode에서 서버로 내용을 보낼 수 있음.

 

· GET 리퀘스트는 body가 필요없어서 head부분만 적어주면 됨.
· POST 리퀘스트는 GET 리퀘스트와 달리 body도 있음.
· 'application/json' : body에 있는 데이터타입이 JSON이라는 뜻임.
· body는 head로 부터 한 줄 띄어씀.

GET http://localhost:3000/api/members

###
POST http://localhost:3000/api/members
Content-Type: application/json

{
    "id": 11,
    "name": "Zake",
    "team": "Engineering",
    "position": "Android Developer",
    "emailAddress": "zake@google.com",
    "phoneNumber": "010-xxxx-xxxx",
    "admissionDate": "2021/06/12",
    "birthday": "1995/09/27",
    "profileImage": "profile11.png"
}

서버에서 body를 읽지 못하고 undefined가 출력됨.


새 직원 정보 추가하기

Express 사용할 때 body가 있는 request를 처리하려면 특정 코드를 추가해줘야 함.

app.use(express.json());

express 객체의 json 메서드가 함수를 리턴함.
그 함수는 서버로 온 request의 body에 JSON 데이터가 존재할 경우 그것을 추출해서 request body의 프로퍼티 값으로 설정해줌.

 

미들웨어(middleware) : request가 라우터 핸들러에 의해 처리되기 에 추가적으로 필요한 전처리를 수행하는 함수

express.json()

request가 들어오면 방금 설정한 middleware에 의해서 body에 있는 json 데이터가 req객체의 프로퍼티에 설정됨.
그 다음 req, res를 보고 알맞은 라우터 핸들러가 호출되는 것임.

request를 보내면 body에 담은 내용이 잘 출력됨.

 

app.post('/api/members', (req, res) => {
    const newMember = req.body;
    members.push(newMember);  // 기존의 직원 정보 배열에 newMember 추가
    res.send(newMember);  // 추가한 객체를 다시 response에 담아서 보내줌.
});

 

미들웨어는 하나의 함수이다

function jsonParser (req, res, next) {
..
  next();
}

마지막 next 파라미터로 넘어오는 함수를 마지막에 호출하면, 리퀘스트를 다음 들웨어나 라우트 핸들러로 넘길 수 있음.


nodemon과 npm start

nodemon 패키지를 개발용으로 설치

npm install nodemon --save--dev

 

패키지 실행

npx nodemon app.js

 

 

package.json 파일

  "scripts": {
    "start": "node app.js"
  },

npm start로 프로젝트를 실행하는 것이 보편적인 관행임.

 

npm start는 원래 있는 명령어라서 그냥 써도 됨.
npm dev는 만든 명령어라서 npm run dev라고 써야됨.

 

  • 원래 있는 명령어 : npm 명령어
  • 기존에 없는데 새로 만든 명령어 : npm run 명령어

--save-dev 옵션의 의미

개발 용도로만 필요한 패키지를 설치할 때 --save-dev 옵션을 사용

하나의 프로젝트에서

  • 배포 용도로 필요한 패키지들은 dependencies 필드에,
  • 개발 용도로만 필요한 패키지들은 devDependencies 필드에

그 정보가 기재되어야 한다

 

dependencies에 있는 패키지들만 node_modules 디렉토리에 설치

- devDependencies에 있는 패키지들(개발 용도로만 필요하고 배포 용도로는 필요하지 않은 패키지들)은 제외

NODE_ENV=production npm install
npm install --production

 

패키지를 설치하고 그 패키지의 정보를 dependencies 필드에 저장

npm install
npm install --save-prod

 

실제 배포 진행 순서

  1. 실제 개발 중이던 프로젝트 디렉토리를 하나 더 복사
  2. 새 디렉토리에서 node_modules 디렉토리 삭제
  3. npm install --production를 실행해서 devDependencies 필드에 있던 패키지들은 제외하고, dependencies 필드에 있던 패키지들만 node_modules 디렉토리에 재설치
  4. 실제 서비스를 위해 코드 실행(npm start 등 실행)

기존 직원 정보 수정하기

newInfo 객체의 모든 프로퍼티 값을 순회하면서 각각의 프로퍼티값을 member 객체의 같은 이름을 가진 프로퍼티 값으로 대입하는 코드

if (member) {
        Object.keys(newInfo).forEach((prop) => {
            member[prop] = newInfo[prop];
        });

 

해당 id의 직원 정보를 수정하는 코드

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!' });
    }
});

 

POST 리퀘스트와 비슷한 구조임.

###
PUT http://localhost:3000/api/members/1
Content-Type: application/json

{
    "id": 1,
    "name": "Alex",
    "team": "engineering",
    "position": "IOS Developer",
    "emailAddress": "alex@google.com",
    "phoneNumber": "010-xxxx-xxxx",
    "admissionDate": "2018/12/10",
    "birthday": "1994/11/08",
    "profileImage": "profile1.png"
}

잘 수정된 것을 확인할 수 있음.


객체의 프로퍼티 순회하기

특정 객체가 갖고 있는 모든 프로퍼티 확인 방법

  • Object.keys(객체) 
  • Object.values(객체)
  • for ... in 구문

Object.keys(객체) → 해당 객체의 프로퍼티 네임이 담긴 배열을 리턴함.

const car = {
    brand: 'Toyota',
    model: 'Camry',
    year: 2022,
    color: 'Blue'
};

const propertyNames = Object.keys(car);

console.log(propertyNames);
// Output: ['brand', 'model', 'year', 'color']

 


Object.entries(객체) → 각 프로퍼티의 key-value 쌍을 담은 배열을 리턴함.

const person = {
    name: 'Alice',
    age: 28,
    city: 'New York'
};

const keyValuePairs = Object.entries(person);

console.log(keyValuePairs);
// Output: [['name', 'Alice'], ['age', 28], ['city', 'New York']]

 

for in과 for of의 차이점

for in

for (let key in object) {
	//
}
const person = {
    name: 'John',
    age: 30,
    job: 'Developer'
};

for (let key in person) {
    console.log(key + ': ' + person[key]);
}

일반적으로 객체의 프로퍼티를 순회, 배열도 사용 가능함.

 

for of

for (let element of iterable) {
    //
}
const numbers = [1, 2, 3, 4, 5];

for (let number of numbers) {
    console.log(number);
}

배열, 문자열, 맵, 세트 등과 같은 반복 가능한 객체를 반복


기존 직원 정보 삭제하기

기존의 직원 정보 배열에서 삭제할 직원 정보 id값과 일치하지 않는 요소들만 추려내서 새로운 배열을 만들고, 그 배열을 새로운 직원 정보 배열로 설정함.

app.delete('/api/members/:id', (req, res) => {
    const { id } = req.params;
    const membersCount = members.length;
    members = members.filter((member) => member.id !== Number(id));
    if (members.length < membersCount) {
        res.send({ message: 'Deleted' });
    } else {
        res.status(404).send({ message: 'There is no member with the id'})
    }
});

 

###
DELETE http://localhost::3000/api/members/3

body 필요없고 지울 것만 요청 보내면 됨.

 

728x90