글 작성자: 망고좋아
반응형

📖 오늘 배운 내용 - 2021.12.02

  • 시맨틱 버전 규칙
  • 라우터
  • 미들웨어
  • .env
  • REST API

 

📝 시맨틱 버전 규칙

  • 패치 버전 Z : 하위 호환을 하지만 버그 수정이 있을 때 올라간다. 버그 수정은 내부적으로 잘못 처리되고 있는 것을 고치는 것을 의미한다.
  • 작은 버전 Y : 새로운 기능이 추가되었지만 기존의 공개 API가 하위 호환되고 있을 때 올라간다. 이는 패치 수준의 변화를 포함할 수 있으나, 작은 버전이 올라가면 패치 버전은 꼭 0이 되어야 한다.
  • 주요 버전 X : 하위 호환되지 않는 변화가 추가될 때 반드시 올라가야 한다. 이는 패치 수준과 작은 수준의 변화를 포함할 수 있으나, 주요 버전이 올라가면 작은 버전과 패치 버전은 꼭 0이 되어야 한다.

 

📝 라우터란?

  • 하나의 페이지를 만들기 위해서 app.get()을 사용했다.
  • 만약에 배민을 웹 버전으로 출시한다면 필요한 페이지로는 회원가입, 가게 목록, 가게 정보, 이벤트 목록, 결제, 프로필, 리뷰 등 많다. 이 많은 페이지를 app.js에 app.get으로 한 파일에 넣기엔 무리다.
  • app.js에 라우터를 만들고 라우터 파일을 연결해 준다. ⇒ 구조적으로 짤 수 있다.
    • 예를 들면 가게 관련 따로, 프로필 따로 등등 나눠준다.
  • Route는 해석하면 이다. 즉, 라우터는 어느 페이지로 보낼지 결정해 준다.
const express = require("express");
const path = require("path");

// routes에 있는 index.js 가져오기
const index = require("./routes/index");

const app = express();
const port = 9999;

// http:localhost:9999/
app.get("/", (req, res) => {
  res.send("hello");
});

// http:localhost:9999/hello
app.get("/hello", (req, res) => {
  // 파일 보내기
  //path.join()는 2개 서로 다른 경로를 합쳐준다.
  res.sendFile(path.join(__dirname, "./static/index.html"));
});

app.listen(port, () => {
  console.log(`${port}번 포트에서 서버가 돌아가고 있어요!`);
});

 

📝 라우팅 해보기

🛠 app.js

const express = require("express");
const path = require("path");

// reoutes에 있는 index.js 가져오기
const index = require("./routes/index");

const app = express();
const port = 9999;

// routes의 index 연결
app.use("/routes", index);

app.listen(port, () => {
  console.log(`${port}번 포트에서 서버가 돌아가고 있어요!`);
});

 

🛠 /routes/index.js

const express = require("express");

// ** router로 생성
const router = express.Router();

// app이 아닌 router
router.get("/", (req, res) => {
  res.send("안녕!");
});

// 다른 파일에서 index.js을 사용하기 위해 exports로 빼주기
module.exports = router;

 

📕 값 넣어서 넘겨주기

const express = require("express");

// ** router로 생성
const router = express.Router();

// app이 아닌 router
router.get("/", (req, res) => {
  res.send("안녕!");
});

// 동적으로 값 넣어주기
router.get("/is_odd_1/:id", (req, res) => {
  const id = parseInt(req.params.id); // id 값 가져오기

  if (isNaN(id)) res.send("아 숫자만 넣으라고 --;;");
  else if (id % 2 === 0) res.send(`${id}는 짝수에요!`);
  else res.send(`${id}는 홀수에요!`);
});

// 다른 파일에서 index.js을 사용하기 위해 exports로 빼주기
module.exports = router;
  • /search/(:numver)/:(option1)/:(option2) ⇒ 이렇게 웹사이트를 설계하는 것은 너무 지저분하다!! ⇒ form태그의 method를 활용하자!

 

📕 값 넣어서 넘겨주기 리팩토링

const express = require("express");
const path = require("path");

// ** router로 생성
const router = express.Router();

// app이 아닌 router
router.get("/", (req, res) => {
  res.send("안녕!");
});

// 동적으로 값 넣어주기
router.get("/is_odd_1/:id", (req, res) => {
  const id = parseInt(req.params.id);

  if (isNaN(id)) res.send("아 숫자만 넣으라고 --;;");
  else if (id % 2 === 0) res.send(`${id}는 짝수에요!`);
  else res.send(`${id}는 홀수에요!`);
});

router.get("/is_odd_2_page", (req, res) => {
  res.sendFile(path.join(__dirname, "../static/get_test.html"));
});

router.get("/is_odd_2", (req, res) => {
  // params가 query로 바뀜
  // number는 form태그 안에 있는 name값이 number, query string는 form 태그로 보낸 데이터를 자동으로 받아옴
  const id = parseInt(req.query.number);

  // http://localhost:9999/routes/is_odd_2?number=23 이렇게 주소 전달 된다.
  if (isNaN(id)) res.send("아 숫자만 넣으라고 --;;");
  else if (id % 2 === 0) res.send(`${id}는 짝수에요!`);
  else res.send(`${id}는 홀수에요!`);
});

// 다른 파일에서 index.js을 사용하기 위해 exports로 빼주기
module.exports = router;
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>테스트</title>

<body>
    <form action="/routes/is_odd_2" method="get">
        숫자 : <input type="text" name="number" /><br />
        <input type="submit" />
    </form>
</body>

</html>
  • 입력하면 이렇게 주소가 이동된다. ⇒ http://localhost:9999/routes/is_odd_2?number=10
  • 매개변수 : 서버에 요청하는 추가적인 데이터로, 키와 값으로 구분됨
  • 매개변수가 2개 이상이 넘어오면 &로 구분한다.

 

📝 .env

  • 환경변수 파일
  • npm i dotenv로 설치
  • const dotenv = require("dotenv");
  • dotenv.config();
const express = require("express");
const dotenv = require("dotenv"); // env

const index = require("./routes/index");

const app = express();
dotenv.config(); // env

// app.set -> 환경설정을 저장할 수 있음.
// app.set("이름", 값)
// process -> Node.js 내장 객체
// dotenv -> process.env에 .env 파일에 있는 값을 다 넣음.
// .env 파일 없음 -> ? process.env.PORT => undefined
// .env 파일이 있으면 거기에 있는 PORT를 쓰고, 없으면 9999로 함.
app.set("port", process.env.PORT || 9999);
app.use("/routes/", index);

app.listen(app.get("port"), () => {
  console.log(`${app.get("port")}번 포트에서 서버가 돌아가고 있어요!`);
});
  • 이렇게 env파일로 따로 관리하지만 결국엔 env 파일을 수정하면 문제 반복 아닌가요?!
    • gitignore을 사용하자. 포트번호는 각자 알아서 쓰고 env파일만 gitignore 해줘서 커밋하자.
  • gitignore.io : 프로젝트에서 사용하는 환경에 맞게 gitignore을 자동으로 생성해준다.

 

📝 미들웨어

  • router.get.은 목적지와 함수로 이루어져 있다.
  • 미들웨어란 클라이언트에서 요청을 받아 그 요청을 처리하는 과정에서 거치는 모든 함수들이다.
  • express.js에서는 미들웨어를 순차적으로 처리할 수 있다.
  • 즉, 요청과 응답 사이에서 추가적인 구현을 해주는 것이 미들웨어이다.
router.use(func1);
router.get("/", (req, res) => {
  res.send("/");
});

router.get("/test", (req, res, next) => {
  res.send("/test");
  next();
});

router.use(func2);
  • next()란 다음으로 넘긴다는 말이다. ⇒그래서 다음에 뭔데?! ⇒ next가 있으면 다음까지 오케이, 없으면 여기서 끝!

 

📕 미들웨어를 사용하는 이유?

  • 그냥 미들웨어를 밖에서 빼서 따로 쓰는 이유는? 그냥 router.get()으로 사용해도 되지 않나요? ⇒ 아니다. 미들웨어를 유용한 상황이 있다. ⇒ 역할의 구분!!!!
  • 예를 들면 쇼핑몰에 내 주문 선물함 등 보려면 일단 로그인을 해야 하니까 로그인이라는 미들웨어를 만들고 그 아래에 라우터들을 구현하면 한번 로그인 되면 그 아래 라우터들이 실행시킬 수 있다. ⇒ 이런 목적으로 미들웨어를 사용한다.

 

📝 미들웨어 예제

🛠 app.js

const express = require("express");
const dotenv = require("dotenv"); // env

// reoutes에 있는 index.js 가져오기
const index = require("./routes/index");

// 미들웨어 연결
const middleware_test = require("./routes/middleware_test");

const rest_api = require("./routes/rest_api_practice");
const kakao = require("./routes/kakao");

const app = express();
dotenv.config(); // env

// app.set -> 환경설정을 저장할 수 있음.
// app.set("이름", 값)
// process -> Node.js 내장 객체
// dotenv -> process.env에 .env 파일에 있는 값을 다 넣음.
// .env 파일 없으면? -> process.env.PORT => undefined
// .env 파일이 있으면 거기에 있는 PORT를 쓰고, 없으면 9999로 함. => process.env.PORT || 9999
app.set("port", process.env.PORT || 9999);
app.use("/routes/", index);
app.use("/middleware", middleware_test);
app.use("/restapi", rest_api);
app.use("/kakao", kakao);

app.listen(app.get("port"), () => {
  console.log(`${app.get("port")}번 포트에서 서버가 돌아가고 있어요!`);
});

 

🛠 /routes/middleware_test.js

const express = require("express");
const router = express.Router();

const func1 = (req, res, next) => {
  console.log("무조건 거쳐가야 해요!");
  next(); // 2. 왔더니 next가 있어서 다음 미들웨어가 실행 되어야 한다.
};

const func2 = (req, res) => {
  console.log("이건 뜰까요?"); // 5. 출력
};

// use는 여기에 도달하면 해당 미들웨어를 실행한다!!
router.use(func1); // 1. 여기를 먼저 도착, 조건 없이 실행

// 해당 조건을 충족하면 실행
router.get("/", (req, res) => {
  res.send("/"); // 3. 조건을 충족해서 코드가 실행되고 그 후 next가 없어서 여기서 종료
});

// 해당 조건을 충족하면 실행
router.get("/test", (req, res, next) => {
  res.send("/test");
  next(); // 3. 조건을 충족해서 코드가 실행되고 다음 미들웨어가 실행 되어야 한다.
});

// use는 여기에 도달하면 해당 미들웨어를 실행한다!!
router.use(func2); // 4. /middleware/test로 들어오면 위 next가 실행되어서 실행

module.exports = router;

 

🛠 /routes/index.js

const express = require("express");
const path = require("path");

// ** router로 생성
const router = express.Router();

// app이 아닌 router
router.get("/", (req, res) => {
  res.send("안녕!");
});

// 동적으로 값 넣어주기
router.get("/is_odd_1/:id", (req, res) => {
  const id = parseInt(req.params.id);

  if (isNaN(id)) res.send("아 숫자만 넣으라고 --;;");
  else if (id % 2 === 0) res.send(`${id}는 짝수에요!`);
  else res.send(`${id}는 홀수에요!`);
});

router.get("/is_odd_2_page", (req, res) => {
  res.sendFile(path.join(__dirname, "../static/get_test.html"));
});

router.get("/is_odd_2", (req, res) => {
  // params가 query로 바뀜
  // number는 form태그 안에 있는 name값이 number, query string는 form 태그로 보낸 데이터를 자동으로 받아옴
  const id = parseInt(req.query.number);

  // http://localhost:9999/routes/is_odd_2?number=23 이렇게 주소 전달 된다.
  if (isNaN(id)) res.send("아 숫자만 넣으라고 --;;");
  else if (id % 2 === 0) res.send(`${id}는 짝수에요!`);
  else res.send(`${id}는 홀수에요!`);
});

// 다른 파일에서 index.js을 사용하기 위해 exports로 빼주기
module.exports = router;

 

📝 API

  • 응용 프로그램 프로그래밍 인터페이스
    • 인터페이스가 뭐냐? 사용자가 기기. 프로그램을 쉽게 동작시키기 위해 도움을 주는 것
  • 프로그램을 만들 때 도움을 주는 something
  • 즉, 내부 동작 과정을 몰라도 api를 통해 응용 프로그램 개발이 가능하다.

 

📝REST API란?

  • API지만, 웹을 통해 원하는 요청을 보내고, 그 요청을 받는 것!
  • 실제 클라이언트는 url로 리퀘스트 요청을 보낸다.
  • 그러면 서버는 http 상태 코드와 함께 결괏값을 보낸다.
  • http 코드를 체크하고 적절한 데이터 가공을 처리한다.
 

HTTP Cats

API for HTTP Cats

http.cat

 

📕 GET - 읽을 때 사용

  • 주로 데이터를 읽거나, 검색할 때 사용하는 메서드
  • http명세에 의하면 get요청은 데이터를 읽을 때만 사용되어야 되고 수정될 때는 사용하지 않아야 한다.

 

📕 POST - 생성할 때 사용

  • 주로 새로운 리소스를 생성할 때 사용된다. (성공 시 201 return)
  • 일반적으로 get은 유알엘에 모든 정보를 담는데 비해, POST는 HTML Body나 JSON으로 전달한다.

 

📕 JSON

  • 일반적으로 서버와 클라이언트로 데이터를 보낼 때 사용하는 방식
  • 기존에 사용했던 xml방식에 의해 더 사용하기 쉬워 널리 사용됨

 

📝REST API 사용 예제

🛠 app.js

const express = require("express");
const dotenv = require("dotenv"); // env

// reoutes에 있는 index.js 가져오기
const index = require("./routes/index");

// 미들웨어 연결
const middleware_test = require("./routes/middleware_test");

const rest_api = require("./routes/rest_api_practice");
const kakao = require("./routes/kakao");

const app = express();
dotenv.config(); // env

// app.set -> 환경설정을 저장할 수 있음.
// app.set("이름", 값)
// process -> Node.js 내장 객체
// dotenv -> process.env에 .env 파일에 있는 값을 다 넣음.
// .env 파일 없으면? -> process.env.PORT => undefined
// .env 파일이 있으면 거기에 있는 PORT를 쓰고, 없으면 9999로 함. => process.env.PORT || 9999
app.set("port", process.env.PORT || 9999);
app.use("/routes/", index);
app.use("/middleware", middleware_test);
app.use("/restapi", rest_api);
app.use("/kakao", kakao);

app.listen(app.get("port"), () => {
  console.log(`${app.get("port")}번 포트에서 서버가 돌아가고 있어요!`);
});

 

🛠 /routes/rest_api_practice.js

const express = require("express");
const router = express.Router();

// 사용법 찾아보기 express.json() 이게 뭔지
router.use(express.json()); // 이 페이지에 들어가 있는 내용들은 json 형식으로 통신할 수 있다.

const users = [
  { id: 1, username: "kim" },
  { id: 2, username: "lee" },
  { id: 3, username: "park" },
];

router.get("/", (req, res) => {
  res.json(users); // send가 아닌 json!
});

/*
const data = {
  id: 123,
  username: "jam"
};


-> username 꺼낼 때 => data.username
*/

// 주소가 똑같아도 get post가 다르면 다르게 인식한다.
router.post("/", (req, res) => {
  //클라이언트 측에서 요청을 보냄
  //요청을 까봐야겠다!

  // 일반적으로 id는 서로 다르게 하는게 좋다. => 시간을 넣어준다. => nodejs는 싱글쓰레드라서 동시에 요청을 처리할 수 없어서 같은 시간이 나올 수 없다.

  // 만약에 이미 똑같은 유저가 있다거나, 권한이 없다거나, username이 없거나에 대해서 에러 코드를 넣어보자!
  // try catch를 사용하자
  try {
    const req_data = req.body; // 자바스크립트 객체를 들고 왔다.

    if (!req_data.username) {
      return res.status(400).end(); // username이 올바르지 않으면 상태코드를 400으로 설정하고 end!
    }

    const user_data = {
      id: Date.now(),
      username: req_data.username,
    };

    users.push(user_data);
    res.json(user_data); // 요청이 있다면 항상 응답이 있어야 한다. 데이터가 잘 들어갔는지 확인하기, 반환값 넣어주기
  } catch (err) {
    console.log(err);
    return res.status(500).end();
  }
});

module.exports = router;

 

📝 KAKAO API 사용해보기

🛠 app.js

const express = require("express");
const dotenv = require("dotenv"); // env

// reoutes에 있는 index.js 가져오기
const index = require("./routes/index");

// 미들웨어 연결
const middleware_test = require("./routes/middleware_test");

const rest_api = require("./routes/rest_api_practice");
const kakao = require("./routes/kakao");

const app = express();
dotenv.config(); // env

// app.set -> 환경설정을 저장할 수 있음.
// app.set("이름", 값)
// process -> Node.js 내장 객체
// dotenv -> process.env에 .env 파일에 있는 값을 다 넣음.
// .env 파일 없으면? -> process.env.PORT => undefined
// .env 파일이 있으면 거기에 있는 PORT를 쓰고, 없으면 9999로 함. => process.env.PORT || 9999
app.set("port", process.env.PORT || 9999);
app.use("/routes/", index);
app.use("/middleware", middleware_test);
app.use("/restapi", rest_api);
app.use("/kakao", kakao);

app.listen(app.get("port"), () => {
  console.log(`${app.get("port")}번 포트에서 서버가 돌아가고 있어요!`);
});

 

🛠 /routeskakao.js

const express = require("express");
const axios = require("axios");

const router = express.Router();
// dotenv를 링크 안 해도 되는 이유는? app.js에서 코드가 합쳐지면서 kakao,js에서도 dotenv를 사용할 수 있다.
router.get("/search", (req, res) => {
  const search = req.query.search;

  axios
    .get("https://dapi.kakao.com/v2/search/web", {
      headers: {
        Authorization: `KakaoAK ${process.env.KAKAO_REST_API_KEY}`,
      },
      params: {
        query: search,
      },
    })
    .then((result) => {
      const titles = [];
      for (let idx in result.data.documents) {
        titles.push(result.data.documents[idx].title);
      }
      res.json(titles);
    })
    .catch((err) => console.log(err));
});

module.exports = router;

 

💡 오늘 깨달은 것

  • 라우터는 역할의 구분이다.
  • api 서버를 만들면 api 명세서를 만들어야 한다. 그래야 백이랑 프론트랑 소통이 가능하다.
  • 프로젝트 시작 시 제일 먼저 해야 될 거는 api 규약 확정. ⇒ Swagger

 

📌 참고

반응형