9/3 Node.js 입문 2주차 (1)

성준호·2024년 9월 3일
0

1. 코드에서 MongoDB 적용

1) mongoose 라이브러리

mongoose는 MongoDB에 데이터를 쉽게 읽고 쓰게 해주는 JavaScript 라이브러리.
ODM(Object Document Mapper)이라고도 부릅니다.

2) mongoose 설치

yarn add mongoose

3) mongoose 문서란?

  • MongoDB에서 갖고있는 각 데이터 하나하나를 문서라고 정의한다.
  • 1개 이상의 Key-Value 쌍으로 이루어져있다.
  • JSON 형식으로 구성
#document
{
    "_id": ObjectId("6682192a1c155bd2f27881"),
    "name": "lyw",
}

4) mongoose 컬렉션이란?

  • 여러개의 문서를 보유할 수 있는 MongoDB의 구성요소
  • JSON 형식의 여러가지 문서를 보유할 수 있다.
  • 컬렉션은 고정된 구성요소가 존재하지 않고, 유연하게 구성할 수 있다.
  • 관계형 데이터베이스의 Table과 동일한 역할

5) monsgoose 스키마란?

  • 컬렉션에 들어가는 문서가 어떤 종류의 값을 가질 것인지 정의
  • 데이터의 구조와 어떤 제약 사항을 가지는지 정의하기 위해 사용한다. 일반적으로 데이터를 모델링할 때 사용
  • 어떤 필드가 있어야 하는지, 필드는 어떤 데이터 타입을 가져야 하는지 정의
const UsersSchema = new mongoose.Schema({
  name: String, // 문자열 타입입니다.
  age: Number, // 숫자 타입입니다.
  favorites: [String], // 문자열 배열 타입입니다.
  createdAt: { type: Date, default: Date.now }, // 날짜 타입입니다.
  someId: mongoose.Schema.Types.ObjectId // ObjectId 타입입니다.

});

대표적인 스키마 타입

  • null: null 값과 존재하지 않는 필드
    • e.g: null
  • String: 문자열
    • e.g: "mongoDB"
  • Number: 숫자
    • e.g: 3.14
  • Date: 날짜
    • e.g: new Date()
  • Buffer: 파일을 담을 수 있는 버퍼, UTF-8이 아닌 문자열 저장
    • e.g: 0x65
  • Boolean: true or false
    • e.g: true
  • ObjectID(Schema.Types.ObjectID): 객체 ID, 주로 다른 객체를 참조할 때 넣음
    • e.g: ObjectID()
  • Array: 배열 형태의 값
    • e.g: ["a","b","c"]

6) mongoose 모델이란?

  • 데이터베이스에 데이터를 저장하고 읽어올 때 사용되는 데이터의 구조
  • 스키마를 바탕으로 만들어진다. JS 객체와 MongoDB 간의 상호작용을 하기 위해 사용
  • MongoDB의 실제 데이터를 다룰 수 있는 메서드를 지닌다.

1. 미들웨어

1) 미들웨어 기본 개념

웹 서버에서 요청을 받을 때, 모든 요청에 대한 공통적인 처리를 하고 싶을 때 필요한 것이 미들웨어

app.use(express.urlencoded({ extended: false }));
app.use(express.json());
  • urlencoded: form-rulencoded라는 규격의 body 데이터를 손쉽게 코드에서 사용할 수있게 도와준다.
  • json: JSON이라는 규격의 body 데이터를 손쉽게 코드에서 사용할 수 있게 도와준다.

2) Express.js에서 미들웨어 작성

app.use((req, res, next) => {
  // 필요한 코드
});
  • req: 요청에 대한 정보가 담겨있는 객체
    • HTTP Headers, Query Parameters, URL 등 브라우저가 서버로 보내는 정보
  • res: 응답을 위한 기능 제공
    • 어떤 HTTP Status Code로 응답할지, 어떤 데이터 형식으로 응답할지, 헤더는 어떤 값을 넣어 응답할지 다양한 기능 제공
  • next: 다음 스택으로 정의된 미들웨어를 호출
//로그를 남기는 미들웨어
app.use((req, res, next) => {
    console.log('Request URL:', req.originalUrl, ' - ', new Date());
    next();
});

3) 여러개의 미들웨어가 겹치는 경우 동작 방식

  • 어디에 위치시키느냐에 따라 다르게 동작한다. 일반적으로 어플리케이션에 등록된 순서대로 실행된다.
  • 여러개의 미들웨어가 겹치는 경우, 첫번째 미들웨어부터 순차적으로 진입한다.
app.use((req, res, next) => {
    console.log('첫번째 미들웨어');
    next();
});

app.use((req, res, next) => {
    console.log('두번째 미들웨어');
    next();
});

app.use((req, res, next) => {
    console.log('세번째 미들웨어');
    next();
});

// print: 첫번째 미들웨어
// print: 두번째 미들웨어
// print: 세번째 미들웨어
  • 미들웨어를 거치는 중간에 next()가 실행되지 않으면 다음 미들웨어는 실행되지 않고, 클라이언트의 요청은 종료된다.
  • 현재 미들웨어에서 응답을 보내는 경우, 즉 res.send()res.json() 등의 메서드를 호출하는 경우에는 next()를 호출하면 안 된다. 이미 요청이 종료된 상태에서 다른 미들웨어가 응답을 보내려고 하여 중복된 요청이 전달되는 문제가 발생한다.

4) Router와 미들웨어의 차이

  • Router와 미들웨어는 서로 다른 방식처럼 보이지만 Router는 미들웨어 기반으로 구현된 객체이므로 미들웨어와 동일한 방식으로 작동한다.
  • 즉, Router는 미들웨어 함수를 특정 경로에 바인딩하는 역할을 하며, 요청이 들어온 URL 경로에 따라 서로 다른 미들웨어를 실행시킨다.

5) Express.js의 미들웨어가 실행되는 경우

  • app.use(Middleware): 모든 요청에서 미들웨어가 실행된다.
  • app.use('/api', Middleware): /api로 시작하는 모든 요청에서 미들웨어를 실행한다.
  • app.post('/api', Middleware, (req,res,) => {}): /api로 시작하는 POST 요청에서 미들웨어를 실행한다.

2. 데이터 유효성 검증 라이브러리

1) Joi란?

JS 유효성 검증을 위한 라이브러리. 여러 타입과 규칙을 이용해 유효성을 검증할 수 있다. 유효성 검증에 실패하면 오류를 발생시킨다.

2) Joi 설치

# yarn을 이용해 Joi를 설치합니다.
yarn add joi

3) Joi를 이용한 Validation

문자열 길이 검증

import Joi from 'joi';

// Joi 스키마를 정의합니다.
const schema = Joi.object({
  // name Key는 문자열 타입이고, 필수로 존재해야합니다.
  // 문자열은 최소 3글자, 최대 30글자로 정의합니다.
  name: Joi.string().min(3).max(30).required(),
});

// 검증할 데이터를 정의합니다.
const user = { name: 'Foo Bar' };

// schema를 이용해 user 데이터를 검증합니다.
const validation = schema.validate(user);

// 검증 결과값 중 error가 존재한다면 에러 메시지를 출력합니다.
if (validation.error) {
  console.log(validation.error.message);
} else {
  // 검증 결과값 중 error가 존재하지 않는다면, 데이터가 유효하다는 메시지를 출력합니다.
  console.log('Valid Data!');
}
  • name 속성이 문자열인지 검증하고, 3~30 글자 사이인지 검증한다.

이메일 검증

import Joi from 'joi';

// Joi 스키마를 정의합니다.
const schema = Joi.object({
  // name Key는 문자열 타입이고, 필수로 존재해야합니다.
  // 문자열은 이메일 형식에 맞아야합니다.
  email: Joi.string().email().required(),
});

// 검증할 데이터를 정의합니다.
const user = { email: 'foo@example.com' };

// schema를 이용해 user 데이터를 검증합니다.
const validation = schema.validate(user);

// 검증 결과값 중 error가 존재한다면 에러 메시지를 출력합니다.
if (validation.error) {
  console.log(validation.error.message);
} else {
  // 검증 결과값 중 error가 존재하지 않는다면, 데이터가 유효하다는 메시지를 출력합니다.
  console.log('Valid Email User!');
}
  • email 속성이 문자열이고, 이메일 형식인지 검증한다.

5) Joi를 이용한 Validation (비동기)

import Joi from 'joi';

// Joi 스키마를 정의합니다.
const schema = Joi.object({
  // name Key는 문자열 타입이고, 필수로 존재해야합니다.
  // 문자열은 최소 3글자, 최대 30글자로 정의합니다.
  name: Joi.string().min(3).max(30).required(),
});

// 검증할 데이터를 정의합니다.
const user = { name: 'Foo Bar' };

try {
  // schema를 이용해 user 데이터를 검증합니다.
  const validation = await schema.validateAsync(user);
  // 검증 결과값 중 error가 존재하지 않는다면, 데이터가 유효하다는 메시지를 출력합니다.
  console.log('Valid Data!');
} catch (error) {
  // 검증에 실패한다면, 에러 메시지를 출력합니다.
  console.log(error.message);
}
  • 유효성 검증을 위해 사용하는 메서드를 validate() -> validateAsync()로 변경하여 데이터를 비동기적으로 검증
  • 비동기로 Joi를 사용하게 된다면, 이전과 다르게 반환되는 결과값에 에러 메시지가 포함되지 않고, 바로 에러가 발생
  • 에러가 발생하여 서버가 종료되는 것을 방지하기 위해 try/catch 구문 사용

3. 에러 처리 미들웨어

1) Express.js의 에러 처리 미들웨어

app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});
  • err, req, res, next는 각각 에러, 요청, 응답, 다음 미들웨어를 호출하는 함수이다.
    • err은 이전 미들웨어에서 발생한 에러를 전달받은 객체
    • req, res는 HTTP 요청과 응답을 관리하는 객체
    • next는 다음 미들웨어를 실행하는 함수
  • 에러를 인자로 전달받아 클라이언트에게 에러 응답을 반환하거나 다음 미들웨어로 에러를 전달

Express.js에서는 미들웨어나 라우터에서 에러가 발생하면, 해당 에러를 next 함수를 통해 다음 미들웨어로 전달한다. 그리고 등록된 미들웨어 중 에러를 매개변수로 받는 미들웨어를 찾아 실행한다.

profile
안녕하세요

0개의 댓글