드디어 오늘 부터 3주동안 본격적으로 javascript의 언어이자 백앤드 개발자의 주특기로 Node.js 공부를 시작하였다. 오늘은 전반적으로 이론과 기본적인 강의 실습 위주로 공부하였다. 새로운 요소들도 많이 배웠지만 저번주에 배웠던 복습도 일부 있었다.
이거랑 유사한 것으로는 Blocking Model & Non-Blocking Model도 있는데 이것도 간단하게 요약하면 이렇다.
동기랑 비동기에 차이점이라면 제어권을 넘기면(Non-blocking) 다른 코드도 실행될 수 있으므로 비동기 처리가 가능하지만, 제어권을 넘기지 않으면(Blocking) 비동기 처리가 가능한 환경이어도 비동기 처리가 불가능하다.
그 외로 중요한 개념 단어라면 다음과 같이 있다. 자세한 내용은 이전 TIL 16~18일차를 보면 된다.
객체(Object) - Javascript의 데이터 타입은 크게 원시 타입과 객체 타입으로 분류됩니다.
객체 리터럴(literal) : 사람이 이해할 수 있는 문자 또는 약속된 기호를 사용해 값을 생성하는 표기법이다.
객체 리터럴은 객체를 생성하기 위해 Class를 먼저 선언하고 new 연산자와 함께 생성자를 호출할 필요가 없이 일반적인 숫자, 문자열을 만드는것과 유사하게 객체를 생성할 수 있습니다.
프로퍼티(Property) : 객체의 상태를 나타내는 값(Data)이며, 키(Key)와 값(Value)으로 구성
메서드(Method) : 프로퍼티를 참조하고 조작할 수 있는 동작(behavior), 객체의 프로퍼티 값이 함수로 구성되어 있을 경우
에러 핸들링은 에러를 관리하는 방법이고, 예상치 못한 상황에 대처하는 방식이다.
에러는 예상할 수 있는 에러와 예상치 못한 에러로 구분할 수 있는데, 일반적인 어플리케이션을 설계할 때에는 예상치 못한 에러 상황이 더욱 많이 일어날 것으로 가정해야 한다.
프로그래머가 작성한 코드에서 예상치 못한 에러가 일어날 가능성은 언제나 존재하고, 이러한 에러 상황을 대비해 언제든지 처리할 수 있어야 한다.
이러한 대비로는 try...catch, throw, finally를 사용 가능한데 다음과 같이 예외 처리를 할 수 있다.
const users = ["Lee", "Kim", "Park", 2];
try {
for (const user of users) {
console.log(user.toUpperCase());
}
} catch (err) {
console.error(`Error: ${err.message}`);
}
// LEE
// KIM
// PARK
// Error: user.toUpperCase is not a function
function withdraw(amount, account) {
if (amount > account.balance)
throw new Error("잔고가 부족합니다.");
account.balance -= amount;
console.log(`현재 잔고가 ${account.balance}남았습니다.`); // 출력되지 않음
}
const account = { balance: 1000 };
withdraw(2000, account);
// Error: 잔고가 부족합니다.
function errorException(isThrow) {
try {
console.log('자원을 할당하였습니다.');
if (isThrow) throw new Error();
} catch (error) {
console.log('에러가 발생했습니다.');
} finally {
console.log('자원을 제거하였습니다.');
}
}
errorException(false);
// 자원을 할당하였습니다.
// 자원을 제거하였습니다.
errorException(true);
// 자원을 할당하였습니다.
// 에러가 발생했습니다.
// 자원을 제거하였습니다.
👉 클래스는 정보를 묶는 것입니다!
class User { // User 부모 클래스
constructor(name, age, tech) { // 부모 클래스 생성자
this.name = name;
this.age = age;
this.tech = tech;
}
getTech(){ return this.tech; } // 부모 클래스 getTech 메서드
}
class Employee extends User{ // Employee 자식 클래스
constructor(name, age, tech) { // 자식 클래스 생성자
super(name, age, tech);
}
}
const employee = new Employee("이용우", "28", "Node.js");
console.log(employee.name); // 이용우
console.log(employee.age); // 28
console.log(employee.getTech()); // 부모 클래스의 getTech 메서드 호출: Node.js
위 코드는 클래스 예시 코드를 한번에 정리한 코드이다.
간단하게 용어들 더 설명하면 자기 자신을 나타내는 this, 객체(Object) 에 묶여 있는 함수라고 말하는 메서드, 부모클래스와 자식클래스를 연결하는 상속이나, 그걸 해당하는
class (자식 클래스) extend (부모클래스)와 부모클래스의 생성자와 메서드를 호출 가능한 super 키워드도 있으나, javascript와 node.js에서는 자주 쓰는 건 아니기에 이정도만 대략 이렇다고 이해하고 넘어가도 무방하다.
개발자 도구를 통해서 네트워크가 어떻게 돌아가는지 볼 수 있다.
Node.js에서 대표적으로 사용하는 패키지 매니저는 npm과 yarn이 존재한다.
다만 저 두개를 같이 쓰는거는 좋지 않다. 여러가지로 충돌이 일어날 수 있기 때문이다.
이제 우리가 앞으로 실습 할 것은 npm을 이용해서 패키지 설치하는 실습을 하였다.
그리고 이제 패키지를 설치하다보면 다음과 같은 두개의 json이 받아지게 되는데 다음 두개의 json을 요약하면 다음과 같다.
package.json
파일을 참조package.json
파일에서 정의한 패키지 외에도 node_modules
에 들어있는 패키지들의 버전과 의존 관계가 상세하게 기록되어 있음package-lock.json
파일에 저장이제 우리가 앞으로 실습 할 것은 npm을 이용해서 패키지 설치하는 실습을 하였다. VScode안에 있는 터미널에 가서 실습을 하였고, 다음과 같은 명령어로 설치하면 된다.
앞으로의 실습을 위해서 'npm install express'를 이용을 했고, express 패키지는 바로 하단에서 설명 할 예정이다.
이제부터 본격적으로 실습을 하기 시작하였다. 실습하기 위한 아무 폴더을 만들었다.
폴더의 제목은 spa_mall
으로 하였다. 그리고 나서 VScode에 들어가서 해당 폴더를 열었다. 이 다음에는 만들어진 폴더에 app.py
파일을 만들어줬다. 그리고 VScode에서 제공하는 터미널에 들어가서 'npm init -y' 명령어를 입력해서 package.json을 생성해주고 'npm install express' 명령어를 입력해 express.js 패키지를 설치를 하였다.
모두 완료되면 아래와 같은 사진처럼 기본 세팅이 마무리 된다.
const express = require('express');
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(port, () => {
console.log(port, '포트로 서버가 열렸어요!');
});
app.py에 다음과 같이 입력해서 기본적인 서버 코드를 작성해서 실습을 하였다, 포트번호는 3000으로 지정했다. 그리고 localhost:3000 입력하면 서버가 연결 된 것을 확인 할 수 있다.
그리고 이후에 VScode에 있는 확장을 눌러서 Thunder Client를 추가적으로 설치하였다. 이 기능은 API Client의 확장 프로그램중 하나인데, API Client란, 개발단계에서 우리가 작성한 API의 요청을 확인하거나 테스팅 할 때 도움을 주는 툴이다. API Client를 사용함으로 개발 속도를 높이거나 치명적인 에러를 예방하는데 도움을 받을 수 있다.
이렇게 설치하면 다음과 같이 이용을 할 수 있다. 좌상단에 있는 New Request를 사용해서 위에 테스트 해볼 주소를 적고 요청하는 방식을 정해서 send를 누르면 다양한 결과를 보여 줄 수 있다.
이 후부터는 터미널에 들어가서 node app.js를 치면서 계속 실습을 하였다.
먼저 시작하기 전에 추가적인 개념을 배웠다.
Express.js
기본 기능 중 하나일반적으로 Router는 아래와 같은 구조를 가집니다.
router.**METHOD**(**PATH**, **HANDLER**);
router
: express의 라우터를 정의하기 위해 사용합니다.METHOD
: HTTP Method를 나타냅니다. (ex: get, post, put, delete …)PATH
: 실제 서버에서 API를 사용하기 위한 경로를 나타냅니다.HANDLER
: 라우트가 일치할 때 실행되는 함수힙니다.이제 goods.js 파일을 만들어서 다음과 같이 실습을 하였다.
// routes/goods.js
// localhost:3000/api/ GET
router.get("/", (req, res) => {
res.send("default url for goods.js GET Method");
});
// localhost:3000/api/about GET
router.get("/about", (req, res) => {
res.send("goods.js about PATH");
});
// routes/goods.js
module.exports = router;
// app.js
const goodsRouter = require("./routes/goods");
// localhost:3000/api -> goodsRouter
app.use("/api", [goodsRouter]);
이러면 localhost:3000에서 /api 로 시작되는 주소는 routes/goods.js 에 있는 Router 미들웨어를 통해 처리된다.
모듈(Module)은 Javascript
파일 단위로 분리된 코드를 일컫습니다.
여기서 Javascript
파일은 특정한 기능을 가진 여러 개의 함수와 변수들의 집합이다.
실습은 다음과 같이 했으며 modules
폴더를 생성해 math.js
, run.js
라는 파일을 생성했다.
그리고 모듈을 사용하는 예시는 총 4가지가 있으며 다음과 같이 사용하면 된다. 아래 코드들은 제가 직접 실습한 코드이며, 두 수를 더하면 모두 값은 40으로 출력된다.
run.js 파일
const {add} = require("./math.js");
console.log(add(10,30));
math.js 파일
// Module을 export하는 다양한 방법 4가지
// 모듈을 호출했을 때, add 키 값에는 add 변수 함수가 가지고 있는 값이 할당된다.
const add = (a, b) => {
return a + b;
}
exports.add = add;
// 모듈을 호출했을 때, add 키 값에는 (a,b){return a + b:} 익명함수가 할당되는 방법이다.
exports.add = function(a,b) {
return a + b;
}
// 모듈을 호출했을 때, add 키 값에는 add 함수가 들어가는 방법이다.
function add(a, b) {
return a + b;
}
module.exports = { add : add };
// 모듈 그 자체를 바로 add 함수를 할당한다.
function add(a, b) {
return a + b;
}
module.exports = add;
여기서 자주 사용하는 모듈은 Express 모듈이며 req, res 객체의미는 다음과 같이 요약 가능하다. 종류는 이외에도 많지만 대표적인거만 적었다.
req 객체
express.json()
Middleware를 이용하여야 해당 객체를 사용할 수 있습니다.res 객체
REST API의 구성은 세 가지
1. 자원(Resource) - URL
2. 행위 - HTTP method
3. 표현
REST API는 다음과 같이 예시로 사용 가능하다.
router.get('/books', (req, res) => {
res.json({ success: true, data: getAllBooks() });
});
이제 최종적으로 내가 만든 REST API 코드이다. (app.py는 오늘 공부했던 파트들도 것도 같이 들어 있다.)
app.py 파일
const express = require('express');
const app = express();
const port = 3000;
const goodsRouter = require('./routes/good.js');
app.use(express.json());
app.post("/", (req,res) => {
console.log(req.body);
res.send("URI에 POST 메소드가 정상적으로 실행되었습니다.");
});
app.get("/", (req,res) => {
console.log(req.query);
// 첫번째 방법
// const obj = {
// "KeyKey" : "value 입니다.",
// "이름입니다.":"이름일까요?",
// }
// 두번째 방법
// res.json({
// "KeyKey" : "value 입니다.",
// "이름입니다.":"이름일까요?",
// });
// 요청 실패 했을 때
res.status(400).json({
"KeyKey" : "value 입니다.",
"이름입니다.":"이름일까요?",
});
});
app.get("/:id", (req,res) => {
console.log(req.params);
res.send(": id URI에 정상적으로 반환되었습니다.");
});
// app.get('/', (req, res) => {
// res.send('Hello World!');
// });
// localhost:3000/api -> goodsRouter
app.use("/api", [goodsRouter]);
app.listen(port, () => {
console.log(port, '포트로 서버가 열렸어요!');
});
good.js 파일
const express = require("express");
const router = express.Router();
// /routes/goods.js
const goods = [
{
goodsId: 4,
name: "상품 4",
thumbnailUrl:
"https://cdn.pixabay.com/photo/2016/09/07/02/11/frogs-1650657_1280.jpg",
category: "drink",
price: 0.1,
},
{
goodsId: 3,
name: "상품 3",
thumbnailUrl:
"https://cdn.pixabay.com/photo/2016/09/07/02/12/frogs-1650658_1280.jpg",
category: "drink",
price: 2.2,
},
{
goodsId: 2,
name: "상품 2",
thumbnailUrl:
"https://cdn.pixabay.com/photo/2014/08/26/19/19/wine-428316_1280.jpg",
category: "drink",
price: 0.11,
},
{
goodsId: 1,
name: "상품 1",
thumbnailUrl:
"https://cdn.pixabay.com/photo/2016/09/07/19/54/wines-1652455_1280.jpg",
category: "drink",
price: 6.2,
},
];
//상품 목록 조회 API
router.get("/goods", (req, res) => {
res.json({goods});
});
router.get("/goods/:goodsId", (req, res) => {
const {goodsId} = req.params;
// 첫번째 방법
// let result = null;
// for(const good of goods) {
// if(Number(goodsId) === good.goodsId) {
// result = good;
// }
// }
// 두번째 방법
const [result] = goods.filter((good) => Number(goodsId) === good.goodsId)
res.status(200).json({ detail: result });
});
module.exports = router;
이렇게 설정 마무리 되면 다음과 같이 성공적으로 REST API 작성 된것을 볼 수 있다. 아래 사진은 Thunder Client에 가서 localhost:3000/api/goods/2를 지정했을때 나오는 사진이다. 사진을 보면 goodId의 2번이 제대로 출력 된 것을 알 수 있다.
이렇게 오늘의 실습은 express 패키지를 통해서 다양한 실습을 마무리 하였다.
오늘은 하루종일 실습만 하다가 부랴부랴 자정이 되서 끝나게 되었다. 강의 영상만 보고 실습하고 복습할겸 TIL을 작성했는데 벌써 15시간이 지나가버렸다. 특히나 제일 나한테 애를 먹었던거는 REST API 작성하는 것이였다. 계속 서버를 키고 실행을 시키는데 자꾸 뭔가 안되서 기술매니져님한테 도움을 받아서 겨우 해결을 했었다. 다른 실험을 해보려고 주석 처리를 한것을 풀어야 했던 것인데 이걸 잘 몰라서 막막하였다. 코드 애러가 났을때는 한번 제대로 살펴보고 수정을 해야 한다는 것을 알았다.
실습한 부분은 아직 완전히 이해 된건 아니지만, 이것은 나중에 기본적인 강의가 다 마무리 되고 나서 개인 과제로 다시 복습 할 시간을 가질 수 있기에 그때 가서 다시 복습하고 공부하면 된 다는 것을 알게 되었다. 그리고 다행인 것은 ES6 빼고는 다른 개념은 지난 3일동안 공부 했던것 덕분에 이해는 빨리 할 수 있었다.
내일은 어제보다는 그나마 수월할 것이다. 웹종합반과 토이프로젝트에서 미리 공부했던 몽고디비와 Git 커밋하는 방법, ec2 도메인을 만드는 것이기에 저번에 했던 기억을 살펴보면서 공부해야겠다. 물론 기존 개념에서 더 추가되는 것이니 방심은 금물이다.