BE_[Node] 1. Express를 사용하는 이유_11.1

송철진·2022년 10월 31일
0

요약

  • Express 장점:
    • 조건문(if-elif)으로 라우팅을 처리했던 것이 보다 간편해짐.
    • 각각의 요청을 처리하는 함수의 분리로 인해 직관적으로 코드를 설계할 수 있다.

0. 들어가며

노드 개발자는 npm 에 등록 되어있는 노드 패키지(라이브러리 or 프레임워크)에 대한 주기적인 관심을 늘 가져야 함
Node.js와 호환 될 수 있는 Server-side Framework 들이 무수히 많기 때문
동향 파악: React conference, GraphQL conference, JavaScript conference

1. Express.js 없이 HTTP API 서버 구축하기

1-1. 간단한 API server

1. directory를 생성 및 프로젝트 시작 ($ : 명령프롬프트, 터미널)

$ mkdir westagram-backend
$ cd westagram-backend
$ npm init -y

2. serverWithoutExpress.js 파일 생성

// serverWithoutExpress.js
const http = require('http') 

const server = http.createServer((req, res) => { 
  console.log('request received')

  res.setHeader('Content-Type', 'application/json')
  res.end(JSON.stringify({ message: "Welcome to http server without express!" }))
});

server.listen(3000, "127.0.0.1", () => {
  console.log('server is running on PORT 3000!')
}) 

1) Node.js 내장 http모듈을 가져와 변수에 담는다.

const http = require('http') 

2) 서버에 요청이 들어오면 http.createServer 메소드는 인자로 또 다른 함수(콜백함수)를 받아 실행한다.

  • req: http request 의 정보가 담겨있는 객체
  • res: http response 객체
const server = http.createServer((req, res) => { 
	//이하 내용 3) 참조
} );

3) 요청에 대한 응답의 header 를 application/json 형태로 세팅.

res.setHeader('Content-Type', 'application/json')

res.end 함수의 인자로 클라이언트가 받는 응답을 넘겨주어 마무리한다

res.end(JSON.stringify({ message: "Welcome to http server without express!" })

4) server의 객체의 listen 함수는 인자로 서버를 열 포트 번호와 서버 실행될 떄의 로직인 콜백함수(서버가 켜져있다는 로그 메시지)를 받는다.

server.listen(3000, "127.0.0.1", () => {
  console.log('server is running on PORT 3000!')
}) 

Port 번호 3000
Express 프레임워크에서 공식적으로 지정한 default Port 번호.
늘 고정된 값은 아니며 3000 이외의 번호로도 언제든지 서버를 열 수 있다!

3. 서버를 실행한다(노드 서버 개설!)

$ node serverWithoutExpress.js

4. 응답 확인하기

  • 웹브라우저

  • httpie (터미널 전용 http client 프로그램)

  • postman (http client 프로그램)

1-2. 복잡한 API server

웹 프레임워크를 적용하지 않으면 코드가 복잡해진다

1. 회원, 게시물 변수 생성 & 데이터 담기

const users = [
  {
    id: 1,
    name: "Rebekah Johnson",
    email: "Glover12345@gmail.com",
    password: "123qwe",
  },
  {
    id: 2,
    name: "Fabian Predovic",
    email: "Connell29@gmail.com",
    password: "password",
  },
];

const posts = [
  {
    id: 1,
    title: "간단한 HTTP API 개발 시작!",
    content: "Node.js에 내장되어 있는 http 모듈을 사용해서 HTTP server를 구현.",
    userId: 1,
  },
  {
    id: 2,
    title: "HTTP의 특성",
    content: "Request/Response와 Stateless!!",
    userId: 1,
  },
];

2. 조건문 분기로 라우팅 진행하기
request 객체에서 urlmethod에 따라 조건문으로 분기하여 라우팅.
회원가입, 게시물 확인 등 다양한 로직을 처리.
라우팅은 http method 별로 GET, POST, PUT, DELETE 등의 내용을 적절한 로직으로 안내하여 이루어진다.

  const http = require("http");
  const server = http.createServer((request, response) => {
    const { url, method } = request;
  
    if (method === "GET") {
      if (url === "/ping") {
        response.writeHead(200, { "Content-Type": "application/json" });
        response.end(JSON.stringify({ message: "pong" }));
      } else if (url === "/users") {
        response.writeHead(200, { "Content-Type": "application/json" });
        response.end(JSON.stringify({ users: users }));
      } else if (url.startsWith("/users")) {
        const userId = parseInt(url.split("/")[2]);
        const user = users.find((user) => user.id === userId);
  
        response.writeHead(200, { "Content-Type": "application/json" });
        response.end(JSON.stringify({ user: user }));
      } else if (url === "/posts") {
        response.writeHead(200, { "Content-Type": "application/json" });
        response.end(JSON.stringify({ posts: posts }));
      }
    } else if (method === "POST") {
      if (url === "/users") {
        let body = "";
  
        request.on("data", (data) => {
          body += data;
        });
        request.on("end", () => {
          const user = JSON.parse(body);
  
          users.push({
            id: user.id,
            name: user.name,
            email: user.email,
            password: user.password,
          });
  
          response.end("ok");
        });
      } else if (url === "/posts") {
        let body = "";
  
        request.on("data", (data) => {
          body += data;
        });
        request.on("end", () => {
          const post = JSON.parse(body);
  
          posts.push({
            id: post.id,
            name: post.title,
            content: post.content,
          });
  
          response.end("ok");
        });
      }
    } else if (method === "PATCH") {
      if (url.startsWith("/posts")) {
        let body = "";
  
        request.on("data", (data) => {
          body += data;
        });
  
        request.on("end", () => {
          const inputPost = JSON.parse(body);
          const postId = parseInt(url.split("/")[2]);
          const post = posts.find((post) => post.id === postId)
  
          post.title = inputPost.title;
          post.content = inputPost.content;
  
          response.writeHead(200, { "Content-Type": "application/json" });
          response.end(
            JSON.stringify({
              id: post.id,
              title: post.title,
              content: post.content,
            })
          );
        });
      }
    } else if (method === "DELETE") {
      if (url.startsWith("/posts")) {
        const postId = parseInt(url.split("/")[2]);
        const post = posts.find((post) => post.id === postId);
        delete post;
  
        response.writeHead(204, { "Content-Type": "application/json" });
        response.end(
          JSON.stringify({
            message: "NO_CONTENT",
          })
        );
      }
    }
  });
  
  server.listen(3000, "127.0.0.1", () => {
    console.log("Listening to requests on port 3000");
  });

순수한 node.js로만 코드를 짜면?

  • 그 규모가 커지면 다양한 로직들에 대해 if-else if 의 연쇄 중첩을 적용하여 분기처리와 소스코드의 양이 배 이상으로 증가.
  • 서버 실행 함수 내에 수많은 조건문과 로직을 모듈화 하는 불필요한 수고로움 발생.
  • 가독성이 떨어짐

👉 Express.js로 불편함 해결!

Routing(라우팅)
해당 자원에 대해 다른 함수(로직)을 실행하도록 하는 것.
👉 유저의 회원가입, 로그인 처리, 프론트엔드 측에서 요구하는 다양한 정보에 응답 등

2. Express.js로 HTTP API 서버 구축하기

” Express is fast, unopinionated, minimalist web framework for node.js.”
” Express는 빠르고 자유롭고 가벼운 웹 프레임 워크이다.”

라우팅로직의 모듈화

개발자가 더욱더 읽기 쉽고 유연하며 지속가능한 백엔드 앱을 개발할 수 있게 돕는 도구

  • 필요한 요청에 필요한 비즈니스 로직이 적재적소에 쓰일 수 있게 구성됨
  • 기능별로 소스코드를 별도의 파일로 관리 가능.

Express.js여야 하는가?

  • 빠르고 자유롭고 가벼운 프레임워크이다
  • 최소한의 기능부터 가볍게 웹서버를 구현할 수 있다
  • 개발입문자가 동작원리를 초석부터 다지기 좋다

2-1. 실행

  • serverWithExpress.js
const modularizedFunctions = require('./modularizedFunctions.js')
const express = require('express')
const app = express()

app.use(express.json())

//get 요청 처리 라우팅
app.get('/ping', (req, res) => {res.json({ message: '/pong'})})
app.get('/users', modularizedFunctions.getUsers)
app.get('/users/:userId', modularizedFunctions.getUserByUserId)
app.get('/posts', modularizedFunctions.getPosts)

//post 요청 처리 라우팅
app.post('/users', modularizedFunctions.createUser)
app.post('/posts', modularizedFunctions.createPost)

//patch 요청 처리 라우팅
app.patch('/posts/:postId', modularizedFunctions.updatePost)

//delete 요청 처리 라우팅
app.delete('/posts/:postId', modularizedFunctions.deletePost)

app.listen(3000, "127.0.0.1", function() {
  console.log('listening on port 3000')
})
  • modularizedFunctions.js
// 먼저 서버통신시 가공할 데이터를 정의합니다.
const users = [
    {
      id: 1,
      name: "Rebekah Johnson",
      email: "Glover12345@gmail.com",
      password: "123qwe",
    },
    {
      id: 2,
      name: "Fabian Predovic",
      email: "Connell29@gmail.com",
      password: "password",
    },
  ];
  
const posts = [
{
    id: 1,
    title: "간단한 HTTP API 개발 시작!",
    content: "Node.js에 내장되어 있는 http 모듈을 사용해서 HTTP server를 구현.",
    userId: 1,
},
{
    id: 2,
    title: "HTTP의 특성",
    content: "Request/Response와 Stateless!!",
    userId: 1,
},
];
  

// 앞서 express 없이 작성한 sendPosts 함수와 비교했을 때,
// express 덕분에 JSON.stringify 함수를 별도로 사용할 필요없이
// response 객체의 json 메소드를 활용합니다.

const getUsers = (req, res) => {
    res.json({ users })
  }

const getUserByUserId = (req, res) => {
    const userId = req.params.userId
    const user = users.find((user) => user.id == userId)
    res.json({ user })
}  
  
const getPosts = (req, res) => {
    res.json({ posts })
  }

const createUser = (req, res) => {
    const user = req.body
    const newUser = users.push({
        id: user.id,
        name: user.name,
        email: user.email,
        password: user.password,
      });  
    res.json({ message: 'created!', 'user_id' : newUser })
}

const createPost = (req, res) => {
    const post = req.body
    const newPost = posts.push({
        id: post.id,
        title: post.title,
        content: post.content,
      });
    res.json({ message: 'created!', 'post_id' : newPost })
}

const updatePost = (req, res) => {
    const inputPost = req.body
    const postId = req.params.postId
    const post = posts.find((post) => post.id == postId)

    post.title = inputPost.title;
    post.content = inputPost.content;

    res.json({ message: 'updated!', 'updatedPost' : post })
}

const deletePost = (req, res) => {
    const postId = req.params.postId
    const indexOfPostId = posts.findIndex((post) => post.id == postId)

    delete posts[indexOfPostId]

    res.json({ message: 'deleted!'})
}

// serverWithExpress.js 에서 사용하기 위해 모듈로 내보냅니다.
module.exports = {
    getUsers,
    getUserByUserId,
    getPosts,
    createUser,
    createPost,
    updatePost,
    deletePost
};

웹 프레임워크
이미 존재하는 코드들을 제공받아 재사용할 수 있게 하는 간편한 서비스
ex) Express.js

프레임워크 장단점

장점단점
효율성 상승학습기간 길다(복잡한 구조 이해)
Quality 향상(버그 발생 빈도 감소)제작자의 의도된 제약사항(구조)
유지보수 유리(체계적 구조)

profile
검색하고 기록하며 학습하는 백엔드 개발자

0개의 댓글