[TIL] 12/17

da__ell·2022년 12월 18일
0

TIL

목록 보기
5/5
post-thumbnail

Intro

백엔드, 프론트 중에 무엇을 해야할 지 고민이 되고 있는 상황이다.. 언어와 프레임워크는 결국 수단에 불과하고, 문제해결을 빠르게 수행할 수 있는 적절한 도구를 선택하는 것이 중요하다. 하지만 취업과 직결되는 사항인만큼, 어떤 분야로 갈지 어떤 언어를 선택할 지 고민이 되는 것은 사실이다.
일단 Node와 React를 입문해보았다. 먼저 NodeJS 입문 강의를 듣고 실습해보면서 공부한 것을 정리해 보았다.

NPM

npm은 세계 최대의 소프트웨어 레지스트리(라이브러리)이며 800,000개 이상의 Node.js 코드 패키지가 존재한다.
오픈소스 개발자는 npm을 사용하여 소프트웨어를 공유하며, 많은 회사나 프로젝트에서 npm을 사용하여 비공개 개발을 관리한다.

Node.js의 모듈이란 필요로하는 자바스크립트 파일을 의미한다

npm 패키지는 Node.js 모듈 및 json 파일, README.md 등을 포함하는 아카이브다. 공용 패키지는 npmjs.com 레지스트리 등에 업데이트 할 수 있으며, private 패키지는 private registry 또는 회사 소유의 레지스트리에 업로드 할 수 있다.
Node.js 자체는 npm 패키지가 무엇인지 인식하지 않고, node_modules 디렉토리에 있는 디렉토리와 파일만 인식한다.

모듈과 패키지 정의 출처 블로그

사용한 CLI 명령어

npm init

npm init은 package.json을 만드는 명령어이다. 새로운 프로젝트나 패키지를 만들 때 사용합니다.

{
  "name": "zoom-clone",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/Daeell/zoom-clone.git"
  },
  "author": "",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/Daeell/zoom-clone/issues"
  },
  "homepage": "https://github.com/Daeell/zoom-clone#readme",
  "dependencies": {
    "cors": "^2.8.5",
    "express": "^4.18.2"
  }
}

프로젝트에 대한 정보들이 기록된다. 여기서 프로젝트의 이름이나, 레포지토리 등을 확인할 수 있다. npm init을 실행하고 커스텀할 수 있다.
여기서 확인할 것은 dependencies인데, 해당 프로젝트에서 활용할 npm 라이브러리와 그 버전이 기록된다.

npm install

npm install은 패키지를 설치하는 명령어입니다. npm install 패키지이름@버전하면 특정한 버전을 설치할 수 있고, npm install 주소하면 특정한 저장소에 있는 패키지를 설치할 수 있는데, 주로 Github에만 있는 패키지를 설치할 때 사용한다고 한다. 옵션을 줄 수 있는데 뒤에 --save 또는 -S를 하면 dependencies에 추가된다.

(npm5부터는 --save옵션이 기본적으로 설정되어 있기 때문에 안 붙여도 된다.

package-lock.json

npm install을 하게 되면 package-lock.json이라는 파일이 생긴다.
해당 파일은 npm을 이용해서 node_modules 트리나 package.json 파일이 수정하게 될 경우 생성되는 파일이다.
해당 파일은 파일이 생성되는 시점의 의존성 트리에 대한 정보를 갖고 있다.

 "packages": {
    "": {
      "name": "zoom-clone",
      "version": "1.0.0",
      "license": "ISC",
      "dependencies": {
        "cors": "^2.8.5",
        "express": "^4.18.2"
      }
    },
    "node_modules/accepts": {
      "version": "1.3.8",
      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
      "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
      "dependencies": {
        "mime-types": "~2.1.34",
        "negotiator": "0.6.3"
      },
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/array-flatten": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
      "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
    },

package.json 파일의 의존성 선언은 특정 버전이 아닌 버전의 범위를 의미한다.

  "dependencies": {
    "cors": "^2.8.5",
    "express": "^4.18.2"
  }

예컨대 package.json을 기반으로 npm install을 실행하게 된다면 현재는 4.18.2 버전이 설치될 것이다. 그런데 새롭게 패치가 이뤄진 버전이 퍼블리싱되어 있고 그것을 설치하게 된다면, 4.18.3이나 4.19.1이 설치될 수도 있는 것이다. 하지만 업데이트된 버전이 오류를 발생시킬 수 있기 때문에 그러한 상황을 방지하고자 필요한 것이 package-lock.json이다.

정리하면
1 . 팀원과의 협업 및 프로젝트를 배포하는 과정에서 프로젝트(패키지 등)의 동일성을 보장해야 한다.
2. 그런데 node_modules를 커밋하거나 매번 npm을 비교해서 설치하는 것은 비효율적이다.
3. 그러므로 package-lock.json을 활용하여 프로젝트에서 활용된 패키지의 정확한 버전을 설치할 수 있도록 한다.

출처 :
syh.log - 벨로그
개발새발 블로그
공식문서 - npm

Express

웹 애플리케이션 구축에 사용되는 노드(Node.js)용 무료 오픈소스 프레임워크이다.

const express = require('express')
const app = express()

app.get('/', function (req, res) {
  res.send('Hello World')
})

app.listen(3000)

예제 코드는 다음과 같다 . 예제코드를 분석해보면서 알게 된 점은 다음과 같다.

HTTP메소드

HTTP메소드는 클라이언트에서 서버로 보내는 요청의 목적과 종류를 알리는 수단이다.
GET메소드와 POST메소드에 대해서 알아보았다.
클라이언트가 서버로 요청을 보내는 방식으로 GET, POST방식을 활용한다.

GET - 주소창에서 데이터를 넘기는 방식
POST - 주소창이 아니라 body로 데이터를 넘기는 방식

GET으로 정보를 전달하는 방식은 2가지가 있다. params,query이다.

params

유튜브에서 채널을 들어가 보면 다음과 같이 youtube.com/@유튜버계정 식으로 도메인이 구성되어 있다. prams방식은 다음과 같은 방식으로 서버에 요청을 보내는 것이다.
우리나라 유튜브채널만 해도 엄청 많은데 각각 해당되는 요청에 대한 응답 코드를 하나씩 다 만드는 것은 비효율적이다. 이를 변수화하여 처리하는 방식이다.

app.get("/user/:id", (req, res) => {
  const q = req.params;
  console.log(q.id);

  res.json({ userid: q.id });
});

:id라는 부분이 변수이다. 그래서 /user/kimdael로 get요청을 보내면 변수 q에 요청보낸 도메인의 params인 :id -> kimdael이 저장되게 될 것이고, 해당 코드를 통해 kimdael이 콘솔에 출력되게 될 것이며, 해당 포트에 접속하게 될 경우 {userid :kimdael}의 json형태로 응답이 되는 것을 확인 할 수 있을 것이다.

app.get("/sound/:name", (req, res) => {
  const { name } = req.params;

  if (name == "dog") {
    res.json({ sound: "멍멍" });
  } else if (name == "cat") {
    res.json({ sound: "야옹" });
  } else if (name == "pig") {
    res.json({ sound: "꿀꿀" });
  } else {
    res.json({ sound: "알 수 없음" });
  }
});

다음과 같이 입력되는 name 변수에 입력되는 값에 따라 응답을 다르게 보낼 수 있다.

query

검색을 하게 될 경우 naver를 검색하게 되면 다음과 같이 도메인이 구성되는 경우를 볼 수 있다.

위와 같이 query형식으로 request를 보내는 방식이다.

app.get("/user/:id", (req, res) => {
  const q = req.query;
  console.log(q);

  res.send(q);
});

위와 같이 user 뒤에 들어가 쿼리 요청을 보내면 변수 q에 저장하고 동일하게 응답을 해보면

다음과 같이 응답을 받을 수 있다. 사용해보면서 느낀 params방식과의 차이점은 좀 더 디테일한 요청이 가능하다.. 정도인 것 같아 이 부분은 더 활용해보면서 공부를 해보려 한다.

Using the Fetch API

클라이언트에서 서버에 매번 데이터를 요청하는 방식을 맛보기로 구현해보았다.

    <h1 id="sound"></h1>
    <input id="name" type="text">
    <button onclick="getSound()">API요청</button>
    <script>
        function getSound() {
            const name = document.getElementById("name").value
            fetch(`http://localhost:3000/sound/${name}`)
                .then((response) => response.json())
                .then((data) => {
                    console.log(data)
                    document.getElementById('sound').innerHTML = data.sound
                });
        }
    </script>

먼저 html 코드를 보자. API요청이라는 button을 누르면 getSound()라는 함수가 실행이 되도록 해놓았다. getSound()가 실행되면 name이라는 id의 input에 작성했던 값(value)가 const name에 저장된다. 이후 http://localhost:3000/sound/${name}에서 name이라는 변수의 값을 가진 주소에서 데이터를 요청하고 가져온다.
그러고 응답의 형태는 json의 형태로 가져온다.
Reoponse.json - MDN
가져온 data는 console에 출력하며 sound라고 불리우는 html element의 innerHTML을 json형식으로 된 data의 sound에 해당되는 value로 변경한다.

const express = require("express");
const app = express();
var cors = require("cors");
const port = 3000;

app.use(cors());

app.get("/", (req, res) => {
  res.sendFile(__dirname + "/index.html");
});

app.get("/sound/:name", (req, res) => {
  const { name } = req.params;

  if (name == "dog") {
    res.json({ sound: "멍멍" });
  } else if (name == "cat") {
    res.json({ sound: "야옹" });
  } else if (name == "pig") {
    res.json({ sound: "꿀꿀" });
  } else {
    res.json({ sound: "알 수 없음" });
  }
});

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`);
});

서버에서는 클라이언트단에서 이루어지는 요청에 대해서 요청에 따른 응답을 json형태로 보내준다.
예를 들어

내가 3000번 포트를 가진 로컬 서버를 열면 위와 같이 html을 통해 구현된 화면을 볼 수 있다.
여기서 내가 dog를 입력하고 api요청 버튼을 누르게 되면
getSound()함수를 통해 localhost:3000/user/dog로 데이터를 보내달라는 요청을 보내게 될 것이다.

그러면 서버에서 이러한 GET요청을 받게되면 params로 받은 dog라는 값을 name이라는 변수에 넣고 그 변수와 일치하는 조건문에 해당되는 {sound:멍멍}이라는 응답을 json 형태로 보내게 된다. - res.json

그러면 클라이언트단에서는 가져오기 함수가 실행된 이후 then함수가 실행되면서 respinse.json을 응답값으로 받고 그 json data의 sound에 해당되는 '멍멍'이라는 값을 sound라는 id를 가진 html요소의 innerHTML이 되어 다음과 같이 화면을 보게 된다.

CORS(Cross-Origin Resource Sharing)

여기서 CORS라는 패키지를 사용했다.
사용한 이유는 서버가 기본적으로 CORS 방식을 제한하고 있기 때문이다.
CORS란 자신이 속하지 않은 다른 도메인, 다른 프로토콜, 혹은 다른 포트에 있는 리소스를 요청하는 방식이다.

위와 같이 domain-1에서 domain-1의 서버에서 데이터를 요청하는 것은 동일한 도메인에서 요청하는 것이기 때문에 Same-origin Request라고 하고 domain-2.com과 같이 다른 도메인 서버에서 데이터를 요청하는 것을 Cross-Origin Requests라고 한다.

아까 말한 대로 서버는 기본적으로 CORS방식을 제한한다. 그 이유는 다른 웹사이트가 특정 서버 리소스에 Request를 보낼 수 있다면, 악의적인 서버에 대한 공격이 이루어 질 수 있기 때문이다.

그래서 다른 사이트에서 나의 서버에 요청하는 것을 허용하는 것을 node.js로 가능하게 할 수 있다.

const app = express();
const cors = require("cors");

app.use(cors());

위와 같이 별도의 처리 없이 app.use(cors())를 하면 모든 도메인에서 제한 없이 서버에 request를 보내고 response를 받을 수 있다.

하지만 특정 도메인에만 허용하고 싶다면 다음과 같이 구현하면 된다.

let corsOptions = {
    origin: 'https://www.domain.com',
    credentials: true
}

app.use(cors(corsOptions));

이렇게 하면 corsOptions에 등록된 도메인만 서버에 request를 보내고 response를 받을 수 있다.

라우팅

특정 포트 안에서도 여러 경로가 존재한다. 라우팅은 포트 내의 경로를 의미하는 말이다.

콜백 함수

콜백 함수는 어떠한 이벤트가 발생하거 특정 시점에 도달했을 때 시스템에서 호출되는 함수이다.

print_(add);

function add(x, y) {
  console.log(x + y);
}

function print_(add) {
  console.log(1);
  add(3, 4);
}

예제를 보면 print_함수가 호출되면서 인자로 들어간 add함수가 호출되는 구조이다.
다른 사람들과 협업할 때 특정 함수를 자주 활용되어 해당 함수를 호출한 이후 다른 함수를 호출할 필요가 있다거나, 일부 비동기적처리를 지원하는 함수들이 콜백함수를 요구하는 경우가 있다고 한다.

profile
daelkdev@gmail.com

0개의 댓글