본문 바로가기
  • soldonii's devlog
Javascript 공부/Zero To Mastery(-)

(20) Node.js와 Express.js 2

by soldonii 2019. 8. 27.

*Udemy의 "The Complete Web Developer in 2019 : Zero To Mastery" 강의에서 학습한 내용을 정리한 포스팅입니다.

*https://soldonii.github.io에서 2019년 8월 7일(수)에 작성한 글을 티스토리로 옮겨온 포스팅입니다.

*자바스크립트를 배우는 단계라 오류가 있을 수 있습니다. 틀린 내용은 댓글로 말씀해주시면 수정하겠습니다. 감사합니다. :)


1. RESTful API

RESTful API는 HTTP 프로토콜(GET, POST, PUT, DELETE)을 통해서 request와 response를 주고 받을 때의 접근 방식을 정해놓은 architecture를 따르는 API를 말한다.

RESTful API는 stateless한 특성을 가지고 있다. 클라이언트에서 서버에 보내는 각각의 요청에는 모든 정보가 포함되어 있어서, 서버가 이전의 요청에서 특정 정보를 불러와서 해당 요청을 처리하지 않도록 해야한다는 점이다.

사례를 통해서 RESTful API를 더 이해해보자. 클라이언트가 보낸 요청을 서버 단에서는 크게 4가지 정도의 메소드를 통해서 조작할 수 있다.

const express = require('express');
const bodyParser = require('body-parser');
const app = express();

app.use(bodyParser.urlencoded({extend: false}));
app.use(bodyParser.json());

app.get('/', (req, res) => {
  console.log(req.query)
  // req.body
  // req.header
  // req.params

  res.send("getting root");
});


app.listen(3000);

 

  • req.query : GET request를 보냈을 때 서버가 받는 정보를 나타낸다. 예를 들어 클라이언트에서 query string으로 ?name=andrei&age=31 와 같은 정보를 보냈을 때, req.query 메소드를 이용하면 {name: 'andrei', age: '31'} 을 얻을 수 있다.
  • req.body : POST request를 보냈을 때 서버는 body에 붙이는데, 이 때 body에 보내진 정보에 접근할 때 사용한다.
  • req.params : URL parameter에 접근할 수 있다. 예를 들어 Postman에서 localhosts:3000/1234 라는 주소에서 GET request를 보냈을 때, console.log(req.params) 의 결과는 { id: '1234'} 이다.
  • req.headers : header에 기록되는 정보에 접근할 수 있다.

RESTful API

 

정리하자면, 위 4개의 request 관련 메소드를 통해 클라이언트가 서버에 보낸 request에 대한 정보를 다 받아볼 수 있다.

동적으로 정보를 주고받는 것 외에, HTML파일이나 CSS 파일을 전달하는 정적인 정보 전달은 어떻게 할까? 현 위치에 public이라는 폴더를 만들고, 그 안에 index.html 파일을 넣었다고 가정해보자. 이 경우 express.static(__dirname + '/public'); 라고 입력하면,__dirname 을 통해 현재의 디렉토리에 접근한 후, 원하는 파일이 위치한 폴더명을 넣어 해당 폴더에 접근함으로써 index.html 파일을 불러올 수 있다. 만약 HTML 파일에 CSS나 Javascript 파일이 함께 포함되었다면 HTML 파일을 읽으면서 함께 로딩이 될 것이다.

const express = require('express');
const bodyParser = require('body-parser');
const app = express();

app.use(express.static(__dirname + '/public'));


app.listen(3000);

 

2. Node File System Module

이전 강의에서 node에 내장된 FS(File System) 모듈에 대해서 살펴봤었다. fs 모듈의 .readFile() 메소드를 더 살펴보자.

 

# .readFile()

const fs = require('fs');

fs.readFile('./hello.txt', (err, data) => {
  if (err) {
    console.log('errrooorr!');
  } else {
    console.log(data);
  }
});

 

script.js 파일 안에 require('fs') 를 통해 fs 모듈을 불러온 후, .readFile() 메소드를 사용했다. 첫번째 parameter는 불러올 파일의 PATH이고, 두번째 parameter는 콜백 함수이다. 이 파일을 node에서 node script.js 명령어로 실행할 경우, 아래와 같은 숫자와 문자로만 이루어진 결과물이 출력된다. 이는 원하는 결과물이 아니다! 이를 해결하기 위해서는 약간의 encoding이 필요하다. console.log(data.toString()); 을 통해서 해결할 수 있다.

<Buffer 68 65 6c 6c 6c 6c 6c 6f 6f 6f 6f 20 74 68 65 72 65 21 21 21>
hellllloooo there!!! // toString()을 붙였을 때 출력되는 결과

 

.toString() 의 경우, parameter로 아무것도 제공하지 않으면 default로 UTF8 encoding을 진행한다. UTF8은 인코딩 종류 중 하나로, HTML5와 웹의 표준이라고 할 수 있다. 라틴어이든, 영어이든, 한국어이든 언어의 각 문자들은 숫자로 매겨져 있는데, UTF8 인코딩을 통해 이 숫자들을 우리가 아는 언어의 문자로 변환하는 것이다.(참고로 UTF8 말고 ASCII 코드도 있다.)

 

# .readFileSync()

const fs = require('fs');

fs.readFile('./hello.txt', (err, data) => {
  if (err) {
    console.log('errrooorr!');
  } else {
    console.log('1', data.toString());
  }
});

const file = fs.readFileSync('./hello.txt');
console.log('2', file.toString());

 

위 코드의 실행 결과는 아래와 같다.

2 hellllloooo there!!!
1 hellllloooo there!!!

 

.readFile() 메소드를 먼저 사용하고, 이후 .readFileSync() 메소드를 사용했음에도 불구하고 .readFileSync() 의 결과가 먼저 콘솔에 출력됐다. 이는 두 메소드가 각각 async, sync한 특성을 가지기 때문이다. .readFile() 메소드는 asynchronous한 메소드이다.(그렇기 때문에 콜백함수가 필요한 것이기도 하다.)

.readFile() 을 해석해보면...
"저기 친구야, 나는 여기서 './hello.txt' 파일을 불러오고 있을테니까, 너는 계속 아래에 써있는 코드를 읽어도 돼! 내가 저 파일 다 불러오면, 너가 나한테 하라고 했던 일(콜백 함수)을 그 다음에 진행할게!" 와 같은 의미이다.

반면 .readFileSync() 는 synchronous한 메소드이다.

.readFileSync() 도 해석해보면...
"야 까불지말고 내가 이 파일 다 불러올 때까지 꼼짝도 하지 말고 기달려. 내가 이거 다 불러오면 나는 file이라는 변수에다가 그 결과를 담을거야. 내가 할 일 다 끝난 다음에 니 할 일 계속 해!" 라는 의미다. (이기적인 쉐끼...)

서버를 만든다고 할 때, .readFileSync() 방식은 문제가 있을 것 같은 느낌이다. 서버가 굉장히 느려질 것이다. 따라서 우리는 .readFile() 메소드를 사용해서 실행을 blocking하지 않도록 해야한다.

 

# .appendFile()

// APPEND
fs.appendFile('./hello.txt', 'This is so cool!', err => {
  if (err) {
    console.log(err);
  }
})

 

.appendFile() 메소드를 이용해서 특정 내용을 파일에 추가하는 것도 가능하다.

 

# .writeFile()

// WRITE
fs.writeFile('bye.txt', 'Sad to see you go', err => {
  if (err) {
    console.log(err);
  }
});

 

같은 폴더에 bye.txt 파일이 생성되고 그 안에 내용은 'Sad to see you go'가 된다.

 

# .unlink()

// DELETE
fs.unlink('./bye.txt', err => {
  if (err) {
    console.log(err);
  }
  console.log('Inception')
});

 

방금 만들었던 bye.txt 파일이 삭제된 후, Inception을 출력한다.

 

이 내용을 배울 때 Andrei는 굉장히 흥미롭다고 했다. 왜 그랬을까?

방금 배운 지식을 활용하면, 웹사이트나 브라우저 안에서 뿐 아니라 그 밖에서도 자바스크립트를 활용할 수 있게 된다. 이 메소드들을 활용해서 엑셀 파일을 읽거나, 엑셀의 특정 column만을 읽어서 계산하거나, 또는 수 많은 사람들에게 엑셀 파일을 첨부해서 메일을 보내는 등의 작업을 할 수 있는 것이다. 말 그대로 자바스크립트를 활용해서 할 수 있는 일이 엄청나게 확장되는 것이다.

댓글