'Node.js를 위한 빠르고 개방적인 간결한 웹 프레임워크'
🗣️ Express 널리, 오래 쓰임 -> 사용자가 많고 새로운 기술 많이 올라온다. 가장 기본적인 프레임워크
yarn add express
express는 개발환경에서만 사용되는 것이 아니라 실제로 코드를 올릴 때도 포함되어야 함. -D 없이 add
서버가 작동하는 방식에 대해 먼저 알아보자

서버와 클라이언트 서로 소통하면서 요청/응답 주고 받음 -> 요청과 응답은 어떤 방식에 의한 것인가?
➡️ HTTP Protocol: 서버와 클라이언트를 이어주는 길!
서버와 클라이언트는 HTTP Protocol을 통해서 소통을 함


[HTTP 구조]

start line - 시작 문장
headers - 요청과 응답의 추가 정보
body - 중요한 정보
REST API - 서버와 클라이언트가 정보를 주고받는 방식에 대한 약속
REST = 자원 + 행위 + 표현
자원: HTTP URL, 즉 주소. 서버에 요청을 보내는 주소.

protocol: http라는 프로토콜 이용
host: 주인이 localhost, 컴퓨터가 주인 (naver.com인 경우 naver.com이 host)
port: 요청이 들어오는 입구 (8000 - 로컬에서 서버 테스트 할 때, 443 - https에 사용되는 포트 443은 생략 가능)
path: / 경로. 경로 안에 응답이나 데이터 존재한다고 볼 수 있음
path variable: 어떤 값이든 올 수 있음
query: 추가적인 정보 담음, 시작은 물음표로 구분은 & 표시로. key와 value를 ?, =, & 이용해서 구분지음
행위: 요청을 하는 방법
HTTP Method- GET, POST, PATCH, PUT, DELETE
같은 end point 가지더라도 메서드가 다르면 다른 요청이 됨, 하나의 end point당 다섯가지의 요청 존재
CRUD - Create(POST 통해서 데이터 생성), Read(GET으로 어떤 정보 불러옴), Update(PATCH, PUT PUT은 데이터의 전체, PATCH는 데이터의 일부 수정), Delete(DELETE)
표현: 요청과 응답의 형식, 요청과 응답을 어떻게 할 것인가?
JSON, XML, TEXT
🗣️ 앞으로 다룰 대부분의 자료는 JSON
💡 간단한 규칙들!
📖 REST API 및 HTTP에 대한 추가 조사하기

client가 요청 보낼 때 항상 middleware 거쳐 오도록 장치 설치해놓은 것
공통적인 처리 과정 필요할 때 사용
ex. middleware를 통해 디도스 공격시 서버 다운되는 것 피하기 위해 정해진 ip의 클라이언트만 접근 가능하도록 함
middleware 어디에서 중간 다리 역할을 하느냐에 따라 두 가지로 구분

어플리케이션 레벨 미들웨어 - 클라이언트의 모든 요청이 거쳐감

라우터 레벨 미들웨어 - 모든 요청에 대해 검사하지는 않음 어떤 한 요청에 대해서만. 메서드(라우터)마다 middleware 다르게 적용
📌 가장 많이 사용되는 라이브러리
cors - 접근 가능한 도메인을 제한
helmet - http 헤더 설정을 통해 보안 강화
dayjs - 날짜 관련 작업을 할 때 사용
nodemon - 수정된 코드에 따라 다시 서버를 실행
axios - 다른 서버(ex. 카카오, 네이버 지도 등등)에 요청을 보낼 때 사용
bcrypt - 비밀번호 암호화에 사용(단방향 암호화. 복호화가 불가능)
jsonwebtoken - 로그인한 유저 정보를 토큰으로 만들기 위해 사용
yarn add cors helmet dayjs
yarn add -D nodemon
cors와 helmet 사용
cors와 helmet은 middleware에 넣음
import cors from "cors";
import helmet from "helmet";
app.use(cors({
origin : "https://www.naver.com"
}));
// https://www.naver.com 에서 요청이 와야만 서버가 응답 보내주도록 도메인 제한
app.use(cors()); // 모든 도메인 접근 허용
app.use(helmet());
dayjs 사용
import dayjs from "dayjs";
const today = new Date(); // 날짜 객체 생성
const todayTodayjs = dayjs(today).format("YYYY-MM-DD"); // dayjs로 변환한 날짜 출력, 출력 형태 지정
➕
터미널에 yarn dev 입력하니 "listen EADDRINUSE: address already in use :::8000" 에러가 발생했다ㅠ.ㅠ
8000번 포트 사용하는 프로세스 찾아서 강제종료를 해야 했다

lsof 명령어로 프로세스 확인, -i 옵션 사용하면 특정 포트 사용중인 프로세스만을 볼 수 있다.
프로세스 확인 후 $ kill -9 (해당 포트를 사용하는 PID값)으로 프로세스 강제종료!
[8000번 포트를 정상적으로 이용할 수 있게 된 모습]

➕
nodemon 사용
script로 사용

--exec: 실행

코드 수정하고 저장 하면 자동으로 서버가 재실행 됨
bcrypt jsonwebtoken 사용
yarn add bcrypt jsonwebtoken
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
const password = "1234";
const hashedPassword = bcrypt.hashSync(password, 10);
// 암호화된 패스워드 만듦
console.log({hashedPassword});
const token = jwt.sign("1234", "a123afjafoawndcwafeo");
console.log({token});

📖 강의에서 다룬 라이브러리 설치 및 cors, helmet, nodemon 적용하고 github에 업로드하기
express 앱 생성하기
// yarn add express
import express from "express";
const app = express();
Application Level 미들웨어 작성하기
// 요청을 json 형태로 받는데 특화된 middleware
app.use(express.urlencoded({ extended: true, limit: "700mb" }));
app.use(express.json());
app.use(cors({ origin: "*"}));
app.use(helmet());
app.use

미들웨어 - app.use에 바로 middleware 함수 넣어주면 미들웨어로 동작
라우터 - 경로를 입력해 준 후 라우터를 넣어줘야 함
app.-HTTP 메서드

app.get 함수 사용하면 GET 메서드로 들어온 요청 받을 수 있는 것
express 앱 실행하기
app.listen(8000, () => {
console.log("Server is running on port 8000");
});
app.use(express.json());
app.use(express.urlencoded({extended: true, limit:"700mb"}));
🗣️ app.use는 미들웨어, 라우터를 위한 함수이기 때문에 미들웨어와 라우터에만 사용. use에서 사용하는 endpoint들은 다 get으로 통일되기 때문에 어울리지 않음.
HTTP Method 통해서 작성하는 REST API
// GET Method 통해서 작성하는 REST API
// 유저 정보 가져오기
// query or Path로 요청 받음(body는 손실되는 경우가 있다)
// status는 응답의 성공 상태를 의미
// get의 경우에는 성공하면 status 보통 200 가져옴
app.get("/users", (req, res) => {
res.status(200).json({users});
});
// POST Method
// 유저 생성
// 요청 body로 많이 받음
// 성공 status: 201
app.post("/users", (req, res) => {
const {name, age} = req.body;
users.push({
id: new Date().getTime(),
name,
age
});
res.status(201).json({users});
});
// PATCH Method
// 유저 수정
// 성공 status: 204
// req.params.id
app.patch("/users/:id", (req, res) => {
const{id} = req.params;
const{ name, age} = req.body;
console.log("param", req.params);
const targetUserIdx = users.findIndex((user) => user.id === Number(id));
users(targetUserIdx) = {
id : users[targetUserIdx].id,
name : name ? name : users[targetUserIdx].name,
age: age ?? users[targetUserIdx].age
}
});
// DELETE Method
// 유저 삭제
// 성공 status: 204
// 경로에 path variable 추가
app.delete("/users/:id", (req, res) => {
const {id} = req.params;
const deletedUsers = users.filter((user) => user.id != Number(id));
users = deletedUsers
res.status(204).json();
});
"/users": endpoint. 각각 들어온 메서드에 따라 가는 곳이 달라짐
📖 app.use를 통해 간단한 미들웨어 구현 후 app.get, app.post, app.patch, app.delete 통해 REST API 만들기

라우터는 클라이언트에게 받은 요청의 경로 지정해줄 수 있음
라우터 생성하기
import { Router } from "express";
const router = Router();
라우팅 경로와 함수 등록
const router = Router();
router.get("/", (req, res) => {});
router.get("/detail", (req, res) => {});
router.post("/", (req, res) => {});
router.patch("/", (req, res) => {});
router.delete("/", (req, res) => {});
export default router;
라우터 등록하기
import express from "express";
import UserRouter from "./users"; // 라우팅 경로와 함수 등록한 파일명이 users일 때
const app = express();
/**
* application middleware
*/
const UserRouter = Router();
// UserRouter endpoint들 등록
UserRouter.get("/", (req, res) => {}); // 슬래시 뒤에 아무것도 없으면 기본적으로 설정한 경로
UserRouter.get("/detail", (req, res) => {});
UserRouter.post("/", (req, res) => {});
UserRouter.patch("/", (req, res) => {});
UserRouter.delete("/", (req, res) => {});
app.use("/users", UserRouter); // users에 해당하는 경로 등록

let users = [
{
id: 1,
name: "sngmin",
age: 12,
},
];
...
const UserRouter = Router();
// GET /users
// 전체 유저 조회
UserRouter.get("/", (req, res)=> {
res.status(200).json({users});
});
// GET /users/detail/:id
// 유저 한 명을 불러오는 API
UserRouter.get("/detail/:id", (req, res)=> {
const { id } = req.params;
users.find((user) => user.id === Number(id));
res.status(200).json({users});
});
// POST /users/
// 유저를 생성하는 API
UserRouter.post("/", (req, res)=> {
const {name, age} = req.body;
user.push({
id: new Date().getTime(),
name,
age,
});
res.status(201).json({users});
});
// 유저 라우터 등록
app.use("/users", UserRouter);
서버 실행

Postman으로 확인하기

🚨 새로운 body를 작성하고 요청을 보내도 업데이트가 되질 않음... ㅠㅠ 뭐가 문제일까
라우터 사용하는 이유
=> 위처럼 사용하면 라우터 사용하는 이유의 장점을 살릴 수가 없음
💡 src>users>index.js
유저 선언 부분 옮겨졌고 모든 라우터가 분리됨.(적용하는 부분과 내용을 적는 부분 분리, 오류 났을 때 수정이 더 쉽다)
import { Router } from "express";
// Router
class UserController{
router;
users = [
{
id: 1,
name: "sngmin",
age: 12,
},
];
constructor(){
this.router = Router();
this.init();
}
init(){
this.router.get("/", this.getUsers.bind(this));
this.router.get("/detail/:id", this.getUser.bind(this));
this.router.post("/", this.createUser.bind(this));
}
getUsers(req, res){
res.status(200).json({users: this.users});
}
getUser(req, res){
const {id} = req.params;
const user = this.user.find((user) => user.id === Number(id));
res.status(200).json({user});
}
createUser(req, res) {
const { name, age } = req.body;
this.users.push({
id: new Date().getTime(),
name,
age,
});
res.status(201).json({users: this.users});
}
}
const userController = new UserController();
export default userController;
src>index.js
import express, { Router } from "express";
import cors from "cors";
import helmet from "helmet";
import dayjs from "dayjs";
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import UserController from "./users";
const app = express();
// 미들웨어
app.use(cors());
app.use(helmet());
app.use(express.json());
app.use(express.urlencoded({extended: true, limit:"700mb"}));
app.use("/users", UserController.router);
// req: 요청
// res: 응답
app.get("/", (req, res) => {
res.send("Nodejs 강의 재밌어요!");
});
app.listen(8000, () => {
console.log("서버가 시작되었습니다.");
});
🚨 서버 실행하면
Error [ERR_UNSUPPORTED_DIR_IMPORT]: Directory import '/Users/sngmin/Desktop/LECTURE/express-practice/src/users' is not supported resolving ES modules imported from /Users/sngmin/Desktop/LECTURE/express-practice/src/index.js 오류 뜸
왜지.............