17주차
이번주는 node.js를 이용해서 백엔드 서버를 구현해 보는 입문 주차였다.
node.js 입문주차에서는 동기/비동기, 에러 핸들링 등의 자바스크립트 문법과, 서버를 구현하고 배포하기 위한 패키지 관리, DB연결, REST API의 개념, github 사용, 도메인 연결까지 간단하게 따라 하며 학습했다.
1. 동기와 비동기 (Synchronous / Asynchronous)
공부하면서 단어가 직관적이진 않다고 생각했다.
Synchronous는 동시에 일어나거나 시간이 연동된다는 의미가 더 먼저 떠오르기 때문인데, 자바스크립트에서 동기와 비동기의 개념은 연속성에 대한 이야기로 이해하는 것이 더 좋다. Synchronous는 연속적으로 실행되는 것이고, Asynchronous는 연속적이지 않게 코드가 처리된다고 이해하는 것.
setTimeout 함수로 동기와 비동기를 설명하는 글이나 예시는 많이 봤고 흔하기 때문에 정리할 필요는 없을 것 같다. 다만, async와 await을 왜 쓰는지에 대한 이유를 정리하는 게 더 좋을 것 같다.
예를 들어 아래와 같은 함수가 있다고 하자.
function fetchData() {
const response = fetch('https://api.example.com/data');
const data = response.json();
return data;
}
함수를 만든 목적은, url에서 정보를 가져와서, json형태로 바꿔 반환하는 것인데 이때 fetch는 비동기 함수이기 때문에, 위와 같이 작성하면, fetch 함수는 반환된 Promise 객체에서 데이터를 추출하는 대신, 즉시 response.json()을 호출하게 된다.
이 경우, 비동기 fetch 함수는 비동기적으로 실행되지만, 우리가 만든 fetchData 함수는 fetch 함수가 완료되지 않은 상태에서 즉시 response.json()을 호출하므로, data 변수에는 Promise 객체가 할당되어 원하는 데이터를 얻지 못하게 된다.
따라서, fetchData 함수가 반환하는 값이 Promise일 때, 이 Promise 객체에서 데이터를 추출하기 위해서는 then() 메서드나 async/await을 사용해서 아래와 같이 만들어줘야 한다.
async function fetchData() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
}
function fetchData() {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
return data;
})
.catch(error => console.error(error));
}
2. 에러 핸들링 (Error handling)
에러 핸들링은 try - catch 문으로, python의 try - except 문과 유사하다.
try {
// 예외가 발생할 가능성이 있는 코드
} catch (error) {
// 예외를 처리하는 코드
}
약간의 차이가 있다면, catch로 오는 error는 어떤 에러든 다 받아와서 그 error를 가지고 세부적인 처리를 해야 한다면, 파이썬은 except에, 구체적인 에러 코드에 따른 예외처리를 구분하여 명시할 수 있다는 차이가 보인다. 두 언어 다 finally 라는 문구로,
try {
// 예외가 발생할 가능성이 있는 코드
} catch (error) {
// 예외를 처리하는 코드
} finally {
// 예외와 관계없이 항상 실행되어야 하는 코드
}
이렇게 작성도 가능하다.
3. 패키지 관리
node.js의 서비스를 위한 라이브러리와 개발을 위한 라이브러리 등의 패키지 관리는 npm(Node Package Manager)으로 한다. npm을 이용해 라이브러리나 패키지를 설치하거나 삭제하고, 업데이트가 가능하다. 파이썬의 pip과 같은 기능을 한다고 보면 된다.
npm init
이때 위와 같이 npm을 초기화 하면, package.json이 만들어지고, 여기에 해당 프로젝트에 대한 정보와, 라이브러리나 프레임워크의 설치 버전 및 의존성 등에 대한 정보가 자동으로 생성되고 작성할 수 있다.
프로젝트에 대한 정보를 입력하지 않았다면, 라이브러리나 모듈 설치 때 아래 정보만 입력되는데, 설치한 것들에 대한 정보다.
{
"dependencies": {
"cookie-parser": "^1.4.6",
"express": "^4.18.2",
"jsonwebtoken": "^9.0.0",
"mysql2": "^3.2.4",
"sequelize": "^6.31.0"
},
"devDependencies": {
"nodemon": "^2.0.22",
"sequelize-cli": "^6.6.0"
}
}
이렇게 package.json으로 저장하는 이유는 개발자가 보기 위함도 있지만 동시에 배포하는 환경에서 프로젝트가 의존하는 패키지에 대한 정보를 동일하게 유지하기 위함도 크다.
즉, 내 컴퓨터에서 코딩을 열심히 해서, 배포할 때, aws 서버에서 동일하게 작동하려면 동일한 패키지들이 설치되어야 하고, 이때 package.json 파일을 배포해서 npm install 명령을 하면, package.json에 적힌 것을 바로 설치할 수 있다.
위 package.json에서 dependencies와 devDependencies 두가지 항목으로 나눠져 있는 것을 확인할 수 있는데, dependencies는 이 프로젝트를 작동하려면 의존하는 패키지의 목록이고, devDependencies는 개발 과정에서 필요한 패키지를 따로 표시해서, 내 환경에서 설치하였으나, 개발할 때만 필요하고, 배포할때는 필요없는 패키지라는 것을 명시하기 위해 구분하는 것.
4.RESTful API
이번주차에 실제로 BE API를 구현하면서 지난주차이 미리 학습했던 RESTul에 대해서 학습해보는 시간을 가졌다. 이것을 API 관점에서 조금 더 직관적으로 공부할 수 있었는데, 내가 이해한 바로 한문장으로 설명하면,
HTTP 메서드와 URI만으로 API의 기능을 유추할 수 있게끔 설계하는 것
으로 쉽게 정리할 수 있었다. 즉, 자원(DB나 비즈니스 기능 등)은 URI로 구분하고 식별하면서, HTTP 메서드(GET, POST, PUT, DELETE 등)으로 CRUD(Create, Read, Update, Delete)기능을 수행하는 것이다.
실제로 간단한 기능이라도, 만들어보면서 그 내용을 학습해보니 왜 그렇게 하는지에 대해서 더 잘 이해할 수 있었다.
(23.05.12. 추가)
REST API에 대해서 더 공부하다보니, 위에 정리한건 아주 일부분이고, 그것만으로는 REST API라고 부를 수 없다는 사실을 배웠다. 그렇지만 현실적으로 여러 리소스의 한계로 self-descriptive와 HATEOAS를 지키지 못하는 경우가 많은데, 못지킨 경우 REST API로 부르지 않거나, 지키거나 해야 한다. 그렇지만 현실적으로 굳이 지킬 필요는 없으나 대충 다 REST API로 부르고 있는 현실을 감안, 상황에 따라 그러려니 해야 하겠다.
'daily' 카테고리의 다른 글
23.05.06. Refresh token, Access token (0) | 2023.05.06 |
---|---|
23.05.01. Sequelize findOne에서, 테이블 조인과 이름 변경 (0) | 2023.05.01 |
23.04.29. express routes index에서의 export 이름 설정 (0) | 2023.04.29 |
23.04.29. Sequelize와 Mongoose의 차이? (0) | 2023.04.29 |
23.04.28. sequelize로 mySQL migration하기 (0) | 2023.04.29 |