(Node.js) Routing with Express

Mirrer·2022년 9월 3일
0

Node.js

목록 보기
2/12
post-thumbnail

Express

ExpressNode.js의 핵심 모듈인 httpConnect 컴포넌트를 기반으로 하는 웹 프레임워크

이전 포스팅에서 Node.jsChromeV8 엔진을 이용해 Javascript로 서버를 구축하고, 서버에서 JavaScript가 작동되도록 해주는 Runtime이라고 설명했다.

Express는 이런 Node.js의 원칙과 방법을 이용하여 웹애플리케이션을 만들기 위한 프레임워크이다.

Express는 프레임워크이므로 웹 애플리케이션을 만들기 위한 각종 라이브러리와 미들웨어 등이 내장돼 있어 사용성이 좋고, 개발 규칙을 적용하여 코드의 통일성을 향상시킨다.

Express는 기존 Node.jshttp코드를 보다 간결하고 구조적으로 사용한다.


REST API

REST API클라이언트와 서버 간에 데이터를 주고받는 방식이다.

REST APIHTTP URI(Uniform Resource Identifier)를 통해 데이터(자원)를 명시하고, Method를 통해 해당 데이터를 CRUD(Create, Read, Update, Delete) 한다.

자주 사용되는 REST Method의 종류는 다음과 같다.

Method용도
get조회
post생성
put전체 수정
delete제거
patch부분 수정
options응답 가능여부

Express Routing

Express를 사용해 서버를 구축하는 방법은 다음과 같다.


  1. 아래 npm명령어를 통해 Express를 설치한다.
npm i express

  1. 이전 포스팅에서 작성한 Node.js서버를 다음과 같이 Express를 사용해 수정한다.
const express = require('express');

const app = express();

// localhost:3065
app.get('/', (req, res) => {
  res.send('Hello Express'); // http의 end가 express에서는 send
});

// localhost:3065/api
app.get('/api', (req, res) => {
  res.send('Hello API'); 
});

// localhost:3065/api/posts
// 게시글 가져오기, json으로 표현
app.get('/api/posts', (req, res) => {
  res.json([ // 응답 데이터
    { id: 1, content: 'Hello1' },
    { id: 2, content: 'Hello2' },
    { id: 3, content: 'Hello3' },
  ]);
});

// 게시글 작성, json으로 표현
app.post('/api/post', (req, res) => {
  res.json({ id: 1, content: 'Hello1' });
});

// 게시글 삭제, json으로 표현
app.delete('/api/post', (req, res) => {
  res.json({ id: 1 });
});

app.listen(3065, () => {
  console.log('서버 실행 중');
});

결과를 확인해보면 다음과 같이 정상적으로 서버가 동작하는 것을 확인할 수 있다.


Postman

브라우저의 주소창은 get요청이므로 위 예제의 post, delete…등과 같은 요청은 다음과 같이 브라우저에서는 불가능하다.

그래서 이러한 문제를 해결하기 위해 Front에서 axios로 요청을 보내거나, Postman이라는 Tool을 사용한다.

  • Front axios 요청
// front/sagas/post.js
function addPostAPI(data) {
  return axios.post('/api/post', data);
}

  • Postman Tool 사용

PostmanAPI를 테스트하고, 결과를 공유하여 API 개발의 생산성을 높여주는 플랫폼이다.

Postman해당 사이트에서 설치가능하며, get이외에 post, put, patch…등과 같은 Method를 전부 사용할 수 있다.


Morgan

Node.js 서버로 구성된 웹 환경에서는 로그(log)를 관리하기 위해 별도의 서드파티 라이브러리, 또는 툴을 사용한다.

그 중 대표적으로 많이 사용되는 것이 Morgan이다, MorganNode.js에서 사용되는 로그 관리를 위한 Middleware이다.

Morgan을 사용하면 Front Server에서 Backend Server로의 요청, 즉 로그를 기록하여 디버깅 작업에 도움을 준다.


  • 사용 방법

아래 npm명령어를 통해 Morgan을 설치한 뒤, app.js파일에서 설정한다.

npm i morgan
// app.js
const morgan = require('morgan');

app.use(morgan('dev'));

Dynamic Address Routing

동적 주소라우팅(Dynamic Address Routing)파라미터(Parameter)라는 변수 값을 이용해 사용자와 상호작용하는 요청 방식이다.

Browser에서 전달받은 파라미터는 Router에서 req.params라는 request 속성으로 사용할 수 있다.

아래 예제는 동적 주소라우팅의 예시로, Browser에서 게시글의 ID를 사용하여 각각의 게시글의 정보를 Backend Server에 요청한다.

// sagas/post.js
function addPostAPI(data) {
    // POST /post/1
	return axios.post(`/post/${data.postId}`, data);
}
// routes/post.js
router.post('/:postId', (req, res) => { // POST /post/1
  try {
    // DB에서 ID를 이용하여 게시글을 검색
    const post = await Post.findById(req.params.id);
      res.json(post);
  } catch (err) {
      res.status(500).send("Server Error");
  }
});

Query String

Query String은 사용자가 path로 접근한 뒤, 해당 경로에서 제공하는 리소스의 조건을 부여하기 위해 사용되는 구문이다.

그래서 주로 하나의 path에서 데이터에 맞게 동적으로 다른 결과를 보여주기 위해 사용된다.

REST APIGET메서드는 두번째 인자에 withCredentials를 사용하기 때문에 데이터를 전달하지 못한다.

function loadPostsAPI(data) {      
  return axios.get('/posts', {
  	withCredentials = true;
  });
}

이 때 Query String을 사용하면 다음과 같이 GET메서드에 데이터를 전달할 수 있다.

데이터는 기본적으로 key=value형태로 작성하며, 다중 데이터시 구분자(&)를 사용하여 여러 데이터를 포함한다.

function loadPostsAPI(lastId) {      
  return axios.get(`/posts?lastId=${lastId}`); // 단일 data전달
}

function loadPostsAPI(lastId, limit) {      
  return axios.get(`/posts?lastId=${lastId}&limit=${limit}&offset=10`); // 다중 data전달
}

이렇게 전달된 데이터는 라우터에서 req.query로 접근할 수 있다.

// routes/posts.js
const express = require('express');
const { Op } = require('sequelize');

const { Post } = require('../models');
const router = express.Router();

router.get('/', async (req, res, next) => {
  try {
    const where = {};
	if (parseInt(req.query.lastId, 10)) { // 초기 로딩이 아닐 때
	  where.id = { [Op.lt]: parseInt(req.query.lastId, 10)} // lastId보다 작은 10개의 게시글을 불러오기
	}
    const posts = await Post.findAll({
	  where,
      limit: 10,     
      res.status(200).json(posts);
  } catch (error) {
    console.error(error);
    next(error);
  }
});

module.exports = router;

encodeURIComponent, decodeURIComponent

서버요청시 주소에 한글, 특수문자를 포함하면 에러가 발생한다.

encodeURIComponent, decodeURIComponent는 이러한 문제를 해결하기 위해 사용되는 JavaScript의 내장 함수이다.

encodeURIComponentURI로 데이터를 전달하기 위해서 문자열을 인코딩하며, decodeURIComponent는 인코딩된 문자열을 정상적인 문자열로 되돌려주는 역활을 한다.

해당 함수를 사용하여 문자열이 포함된 요청을 처리하는 방법은 다음과 같다.

function loadHashtagPostsAPI(data) { // data: '떡볶이'    
  return axios.get(`/hashtag/${encodeURIComponent(data)}`);
}
router.get('/hashtag/:tag', async (req, res, next) => { 
  try {
    const where = { name: decodeURIComponent(req.params.tag) };    
    res.status(200).json(posts);
  } catch (error) {
    console.error(error);
    next(error);
  }
});

Split Express Router

이전 포스팅에서 설명했듯 요청과 응답은 1:1 대응되어야 한다.

하지만 이로 인해 다양한 Router들이 생성되고 코드의 양이 길어져 가독성 측면에서 악영향을 끼친다.

그래서 다음과 같이 routes 폴더를 생성하여 Router들을 개별적으로 관리한다.

// app.js
const express = require('express');
const postRouter = require('./routes/post');

const app = express();

// app.post('/api/post', (req, res) => {
//   res.json({ id: 1, content: 'hello1' });
// });

// app.delete('/api/post', (req, res) => {
//   res.json({ id: 1 });
// });

app.use('/post', postRouter);

server.listen(3065, () => {
  console.log('서버 실행 중');
});
// routes/post.js
const express = require('express');

const router = express.Router();

router.post('/', (req, res) => { // POST /post
  res.json({ id: 1, content: 'Hello1' });
});

router.delete('/', (req, res) => { // DELETE /post
  res.json({ id: 1 });
});

module.exports = router;

참고 자료

Node.js 공식문서
Node.js 교과서 - 조현영
React로 NodeBird SNS 만들기 - 제로초

profile
memories Of A front-end web developer

0개의 댓글