[JavaScript] 4-5. Node.js

Node.js


Rest API 실습

REST API 란?

REST(Representational State Transfer)는
월드 와이드 웹과 같은 분산 하이퍼미디어 시스템을 위한 소프트웨어 아키텍처의 한 형식으로,
엄격한 의미로 REST 는 네트워크 아키텍처 원리의 모음입니다.
여기서 ‘네트워크 아키텍처 원리’란 자원을 정의하고 자원에 대한 주소를 지정하는 방법 전반을 일컫습니다.
간단한 의미로는, 웹 상의 자료를 HTTP 위에서 SOAP 이나 쿠키를 통한 세션 트랙킹 같은
별도의 전송 계층 없이 전송하기 위한 아주 간단한 인터페이스를 말합니다.
이 두 가지의 의미는 겹치는 부분과 충돌되는 부분이 있습니다.

API 를 제공하는 사이트로 부터 API 를 제공받을 떄 필요한 부분을 필요에 맞게 가져다가 씀으로
웹 어플리케이션을 좀 더 강력하게 만들 수 있습니다.

// yts(영화서비스를 하는 곳) api를 받아와서 다운로드 수대로 정렬 (이처럼 원하는 정보를 알맞게 사용할 수 있습니다.)
_callApi = () => {
  return fetch("https://yts.am/api/v2/list_movies.json?sort_by=download_count")
    .then(potato => potato.json())
    .then(json => json.data.movies)
    .catch(err => console.log(err));
};



Node.js 실습

Node.js 는 언어가 아닌 JavaScript 런타임의 일종입니다.


JavaScript Runtime

JavaScript Runtime 은 JS 를 구동하기 위해 필요한 실행환경입니다.


V8 JavaScript Engine


Event-driven Programming

프로그램의 흐름이 외부 요인에 의해 일어나는 사건에 의해 결정되는 프로그래밍 방식으로
약속된 방식으로 이벤트 핸들러를 작성함으로써 외부 이벤트가 일어났을 때 코드를 실행합니다.


Node.js Module

// module.exports에 저장한 값은 다른 모듈에서 불러올 수 있습니다.
module.exports = {
  familyName: "",
  givenName: "근환",
  fullName: function() {
    return this.familyName + this.givenName;
  }
};
// exports로도 참조 가능합니다.
exports.add = (x, y) => x + y;
exports.sub = (x, y) => x - y;
// node.js에 내장되어 있는 것을 불러오고 싶을 때 이렇게 사용합니다.
const os = require("os");
console.log(os.platform());
console.log(os.freemem());

// node.js에서 내가 작성한 것을 불러오고 싶을 때 이렇게 사용합니다.
const m = require("./module.js");
// require('../module');
console.log(m.name);


NPM

Node.js 패키지 관리 도구 + 클라우드 패키지 저장소


package.json

패키지 정보를 담고 있는 파일입니다.

dependencies
‘npm install –save’ 명령으로 설치한 패키지가 기록됩니다.

scripts
원래 목적은 패키지 생명주기마다 자동으로 실행되는 명령을 등록하기 위함이나,
개발자의 편의를 위해 자주 사용되는 명령을 등록하는 용도로 더 많이 사용됩니다.

// 패키지 이름, 버전, 설명등을   있습니다.
// package.json이란 파일은 npm이 관리합니다.
{
  "name": "hello-npm",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    // 자주 쓰는 명령어를 이렇게 해놓으면 간편히 사용가능합니다.
    // npm start라고 하면 바로 실행되게끔!
    // parcel, webpack등에도 사용가능합니다.
    "start": "node index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

.gitignore

git 을 이용하는 모든 명령에서 예외 처리를 할 수 있습니다.
.gitignore 파일을 생성하고 안에 예외 처리할 폴더 및 파일의 이름을 적어주면 됩니다.



HTTP

일반 홈페이지의 대다수가 이러한 HTTP 로 시작됩니다.


HTTP 역사


HTTPS

주로 은행, 쇼핑몰, 정부사이트등 보안이 중요한 곳에서 사용합니다.


HTTP 와 HTTPS 의 차이


HTTP 와 HTTPS 의 장단점


HTTP/2


HTTP 1.1 과 HTTP/2 와 차이점

TCP (Transmission Control Protocol)
웹 브라우저들이 웹에서 서버에 연결할 때 사용되며, 이메일 혹은 파일 전송시에도 사용됩니다.


Request & Response


Request Method


HTTP URL Anatomy

[주의]
위의 주소(도메인)은 절대적인 주소가 아닙니다.
사람들이 이용하기 쉽게 문자 혹은 숫자로 구성된 주소(도메인)은
우리가 해당 주소로 요청을 보냈을 때 DNS 서버에 질의를 통해 해당 주소의 웹서버 IP 를 제공받게 되고,
그 해당 주소의 웹서버 IP 에 요청을 하여 응답을 받게 되는 것입니다.


Percent Encoding

encodeURIComponent("한글");
// "%ED%95%9C%EA%B8%80"

decodeURIComponent("%ED%95%9C%EA%B8%80");
// "한글"


Response Status



Content Negotiation

요청의 Accept, Accept-Language 등의 헤더를 보고 서버가
그에 맞는 형태의 자료를 응답하는 절차를 Content-negotiation 이라 합니다.


chrome Devtools



Express

Glitch 실습

Glitch 는 웹 브라우저 위에서 Node.js 기반 앱을 만들고, 복제하고,
편집하고, 공동 작업하고, 호스팅할 수 있는 환경을 제공합니다.

https://glitch.com/


Express

// Express 앱의 기본 구조

// Express 인스턴스 생성
const app = express();

// 미들웨어 주입
app.use(sessionMiddleware());
app.use(authenticationMiddleware());

// 라우터 핸들러 등록
app.get("/", (request, response) => {
  response.send("Hello World");
});

// 서버 구동
app.listen(3000, () => {
  console.log("Example app listening on port 3000!");
});


Routing

// HTTP 요청 메소드 (GET, POST, ...)와 같은 이름의 메소드를 사용합니다.
app.get("/articles", (req, res) => {
  res.send("Hello Routing!");
});

// 특정 경로에만 미들웨어를 주입하는 것도 가능합니다.
app.post("/articles", bodyParserMiddleware(), (req, res) => {
  database.articles.create(req.body).then(() => {
    res.send({ ok: true });
  });
});

// 경로의 특정 부분을 함수의 인자처럼 입력 받을 수 있습니다.
app.get("/articles/:id", (req, res) => {
  database.articles
    .find(req.params.id) // 'req.params'에 저장됨
    .then(article => {
      res.send(article);
    });
});


Request 객체


Reponse 객체


Express 실습 - glitch 사용

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

const app = express();
app.enable('trust proxy');
app.use(bodyParser.json());


// GET method
app.get('/', (req, res) => {
  res.send('Hello, Express!')
});

// POST method
app.post('/', (req, res) => {
  /*
  Mission:
  요청의 바디에 실려 온 JSON에 name이라는 속성이 있으면 해당 값을 이용해 응답하고, 없으면 400 Bad Request를 응답한다.
  응답 형태는 'Hello, <name>!' 으로 한다.
  */
  if (req.body.name) {
  res.send(`Hello, ${req.body.name}!`);
  } else {
    res.status(400);
    res.send('400 Bad Request');
  }
});

// query parameter, res.status
app.get('/add', (req, res) => {
  /*
  Mission:
  query parameter에 x와 y라는 이름을 가진 두 값을 정수로 바꾸어서 더한 후 응답한다.
  값을 정수로 바꿀 수 없다면 400 Bad Request로 응답한다.
  */
  req.query.x = parseInt(req.query.x);
  req.query.y = parseInt(req.query.y);
   if (Number.isInteger(req.query.x) && Number.isInteger(req.query.y)) {
    res.send({sum: req.query.x+ req.query.y});
  } else {
    res.status(400);
    res.send('400 Bad Request')
  }
})

// req.ip
app.get('/ip', (req, res) => {
  /*
  Mission:
  요청한 쪽의 ip를 응답한다.
  */
  res.send(req.ip);
});

// req.get, res.set, res.end
app.get('/header', (req, res) => {
  /*
  Mission:
  요청의 X-Custom-Header 헤더를 그대로 응답에 포함시켜 응답한다.
  응답에는 바디를 포함시키지 않도록 한다.

  hint 1: req.get 메소드는 요청에 포함된 특정 헤더의 값을 가져온다.
  예) req.get('X-Custom-Header')

  hint 2: res.set 메소드는 응답에 새로운 헤더를 지정한다.
  예) res.set('X-Custom-Header', value)

  hint 3: res.end 메소드는 응답을 보낸다. res.send와 비슷하지만, 아무런 인자도 받지 않는다.
  */

  res.set('X-Custom-Header', req.get('X-Custom-Header'));
  res.end();
});

const listener = app.listen(process.env.PORT, function () {
  console.log('listening on port ' + listener.address().port);
});



Template Language


EJS (Embedded JavaScript Template)


EJS Syntax

<%# 주석입니다 %>
<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="/static/index.css">
  </head>
  <body>
    <% if (name) { %>
      <p>당신의 이름은 <%= name %>입니다.</p>
    <% } else { %>
      <p>이름이 주어지지 않았습니다. query parameter에 name을 추가해보세요.</p>
    <% } %>
    <hr>
    <h1>List</h1>
    <ul>
      <% items.forEach(item => { %>
        <li><%= item %></li>
      <% }) %>
    </ul>
    <% if (showSecret) { %>
      <p>my secret is: <%= secret %></p>
    <% } %>
  </body>
</html>


파일을 그대로 제공하기

// 'public' 폴더에 있는 파일을 '/static' 경로 아래에서 제공
app.use("/static", express.static("public"));
<!--템플릿 파일에서 참조할 수 있음-->
<link rel="stylesheet" href="/static/index.css">
<script type="text/javascript" src="/static/index.js"></script>



HTML Form


HTML Form Example


multipart/form-data



URL shortener 구현 실습



2. Today I Found Out

통신에 대해서 기대를 갖고 있었고 기대에 상당부분 만족할 수 있는 공부였습니다.
REST API가 무엇인지 알아보고 실습을 통해 이런 것들이구나 하고 깨달을 수 있었습니다.
배우면서도 어서 써먹어보고 싶다는 생각이 가득할 정도로 좋았습니다.
또한 Node.js를 배워봄으로써 런타임에 대해서 알아볼 수 있었고,
평소에 궁금했던 것들을 상당수 체험해서 궁금증을 해결할 수 있었습니다.



3. refer

https://fds9.github.io/fds-nodejs-http/

https://developer.github.com/v3/

https://www.slideshare.net/GihyoJoshuaJang/ss-71668518