Node.js 기본 라이브러리로 웹 서버를 만들었지만…

지난번 까지는 Node.js 기본 라이브러리(http, url 등)를 이용하여 구현했지만, 일반적으로 아래와 같이 웹 서버가 제공하는 기능을 제공하기에는 부족하다. 널리 사용되는 Express로 웹 서버를 구축해보자.

항목 설명
라우팅 URL 요청을 함수와 매핑시켜주는 기능
정적 파일 서비스 CSS, JS, 이미지 등의 정적인 파일을 다루는 기능
템플릿 엔진 동적인 웹페이지를 HTML과 인스턴스를 사용해 생성하는 기능
요청(request) 데이터 다루기 HTTP 요청을 추상화해 편리하게 다룰 수 있게 하는 기능
응답(response) 데이터 다루기 HTTP 응답을 커스터마이징할 수 있는 기능. 파일 내려받기, 이미지 출력 등
파일 업로드 HTTP로 전송된 파일을 읽고 다룰 수 있는 기능
쿠키 및 세션 지원 클라이언트 측 혹은 서버 측의 메모리에 일정 기간 동안 저장해야 하는 데이터를 다루는 기능
리다이렉트 서버의 응답 시 다른 페이지로 전달(redirect)시키는 기능
에러 페이지 요청이 잘못되었거나, 서버 에러 시 특정 에러 페이지를 보여주기
미들웨어 요청 혹은 응답 사이에 공통된 기능을 추가하는 기능

1. 예제 연습 1 - “헬로 Express”를 반환하는 서버

const express = require("express"); // 1. express 모듈 불러오기
const app = express(); // 2. express를 초기화 후 app에 할당
const port = 3000;

app.get("/", (req, res) => { // 3. '/'로 요청이 오는 경우 실행
    res.set({ "Content-Type": "text/html; charset=utf-8" }); // 4. 헤더값 설정
    res.end("헬로 Express");
});

app.listen(port, () => { // 5. 서버를 기동해 클라이언트 요청을 기다림
    console.log(`START SERVER : use ${port}`);
})

2. 예제 연습 2 - Express로 라우팅다루기

지난 번에 http로 라우팅을 다루었던 코드(urlMap)를 Express로 아래와 같이 손쉽게 라우팅할 수 있다. 이 때, 라우팅을 담당했떤 urlMap 코드가 제거된 걸 확인할 수 있다.

const express = require("express");
const url = require("url");
const app = express();
const port = 3000;

app.listen(port, () => {
    console.log("익스프레스로 라우터 리펙토링하기")
})

// 1. GET 메서드의 라우팅 설정
// 이전 코드에서 urlMap으로 라우팅 하던 코드가 제거
app.get("/", (_, res) => res.end("HOME"));
app.get("/user", user);
app.get("/feed", feed);

function user(req, res) {
    const userInfo = url.parse(req.url, true).query;
    // 2. 응답결과로 json 으로 내려줌
    res.json(`[user] name : ${userInfo.name}, age : ${userInfo.age}`);
}

function feed(_, res) {
    res.json(`<ul>
            <li>picture1</li>
            <li>picture2</li>
            <li>picture3</li>
            </ul>`);
}

3. 예제 연습 3 - 게시판 API 코드 작성하기

아래 게시판 API 스펙에 따라 Express로 게시판 API를 만들어보자.

경로 HTTP 메서드 설명
/ get 게시판 목록을 가져온다.
/posts post 게시판에 글을 씁니다. 글은 아이디(id), 제목(title), 작성자(name), 내용(text), 생성일시(createdDt)로 구성된다.
/posts/:id delete 게시글 아이디가 id인 글을 삭제한다.
const express = require("express");
const app = express();
const port = 3001;
let posts = [];

// 1. req.body를 사용하려면 JSON 미들웨어를 사용
// 사용하지 않으면 undefined로 반환
app.use(express.json()); // json 미들웨어 활성화

// POST 요청 시 컨텐트 타입이 application/x-www-form-urlencoded인 경우 파싱
app.use(express.urlencoded({ extended: true })); // 2. json 미들웨어와 함께 사용

app.get("/", (_, res) => {
    res.json(posts); // "/"로 요청이 오면 실행
    // res.end(posts); // 에러 발생
})

app.post("/posts", (req, res) => { // "/posts"로 요청이 오면 실행
    const { title, name, text } = req.body; // HTTP 요청의 body 데이터를 변수에 할당

    // 게시글 리스트에 글 추가
    posts.push({
        id: posts.length + 1,
        title: title,
        name: name,
        text: text,
        createdDt: Date()
    })

    res.json({
        title, name, text
    })
})

app.delete("/posts/:id", (req, res) => {
    const id = req.params.id; // 3. app.delete에 설정한 path 정보에서 id값을 가져옴
    const filteredPosts = posts.filter((post) => post.id !== +id); // 글 삭제 로직
    const isLengthChanged = posts.length !== filteredPosts.length;
    posts = filteredPosts;
    if (isLengthChanged) { // posts의 데이터 개수가 변경되었으면 삭제 성공
        res.json(posts);
        return
    }
    res.json("NOT CHANGED"); // 변경되지 않음 알림
});

app.listen(port, () => {
    console.log("게시판 API 오픈");
})
  1. app.use()는 미들웨어를 사용할 때 사용하는 함수이다. 익스프레스에서 미들웨어는 요청과 응답 사이에 로직을 추가할 수 있는 함수를 제공한다. app.use(express.json())을 실행하지 않으면, req.body값이 undefined로 나오게 된다.
  2. express.urlencoded({ extended: true })는 컨텐트 타입이 application/x-www-form-urlencoded인 경우 파싱한다. POST 요청 대부분이 application/x-www-form-urlencoded 타입이라서 express.json()과 함께 사용한다. application/x-www-form-urlencoded 타입이란 body에 키=값&키2=값2 같은 조합형태의 데이터를 말한다.
  3. id 변수에 요청(req)의 path에 할당된 변수 id를 할당한다. 라우팅 규칙에 따라 :id로 표기한 부분은 데이터가 들어오면 문자열 타입으로 params.id에 할당된다.

예제 테스트하기

  • 아래 화면은 3번의 포스트 후, get으로 posts를 받아본 결과화면이다.

image-20230812154133800

  • id 1번을 delete 요청하면, 남아있는 배열의 요소가 응답된다.

image-20230812154318060

연습문제 오답노트

  • 다국어를 표현하는 데 가장 많이 사용되는 가변 길이 문자열 인코딩 방식은?
    • UTF-8
  • HTTP 메서드로 API 작성 시 URL 자원을 표현하고 가져오는 행위를 표현하는 규칙은?
    • REST

참고

다음에 다루게 될 것

  • npm으로 패키지 관리하기

댓글남기기