Miracle Morning, LHWN

2_0. 조회(GET), 삭제(DELETE), 수정(PUT, PATCH) 본문

IT 기술/[React] Project

2_0. 조회(GET), 삭제(DELETE), 수정(PUT, PATCH)

Lee Hye Won 2021. 6. 1. 14:26
데이터 조회 (GET)

 

# 데이터베이스의 데이터를 조회할 때에는 find() 메서드를 사용한다.

exports.list = async (ctx) => {
    let books;

    try {
        books = await Book.find().exec();
    } catch (e) {
        return ctx.throw(500, e);
    }

    ctx.body = books;
};

※ let 이나 const 는 scope 가 블록단위이다.

books = await Book.find().exec();

.exec() 함수를 뒤에 붙여주어야 실제로 데이터베이스에 요청이 이루어진다.

이때의 반환 값은 Promise 이기 때문에 await 을 사용할 수 있다.

# 이번에는 여러 옵션을 주어 최근에 생성된 3개의 데이터만 조회해보자. (_id 가 역순으로 정렬되고, 3개만 조회)

exports.list = async (ctx) => {
    let books;

    try {
        books = await Book.find()
            .sort({_id: -1}) 
            .limit(3) 
            .exec();
    } catch (e) {
        return ctx.throw(500, e);
    }

    ctx.body = books;
};
.sort({_id: -1}) // _id 의 역순으로 정렬
.limit(3) // 3개만 조회
.exec(); // 데이터를 실제 서버에 요청

 

# 이번에는 특정 _id 을 가진 데이터를 조회해보자.

exports.get = async (ctx) => {
    const { id } = ctx.params; 

    let book;

    try {
        book = await Book.findById(id).exec();
    } catch (e) {
        return ctx.throw(500, e);
    }

    if(!book) {
        ctx.status = 404;
        ctx.body = { message: 'book not found' };
        return;
    }

    ctx.body = book;
};

뜯어보자.

const { id } = ctx.params;

요청된 URL 의 파라미터에서 id 값을 읽어온다.

book = await Book.findById(id).exec();

findById () 함수를 이용하여 특정 id 를 가진 데이터를 조회한다.

근데 위 코드처럼 id 를 파라미터로 받을 때에는 사전에 id 값을 검증해주거나, 에러를 처리해주어야 한다.

일단 에러를 처리해보자.

try {
  book = await Book.findById(id).exec();
} catch (e) {
  if(e.name = 'CastError') {
    ctx.status = 400;
    return;
  }
  return ctx.throw(500, e);
}

 

데이터 삭제 (DELETE)

 

# 데이터를 삭제하는 함수에는 여러 종류가 있다.

- remove() : 특정 조건을 만족하는 데이터들을 모두 지운다.

- findByIdAndRemove() : id 를 찾아서 지운다.

- findOneAndRemove() : 특정 조건을 만족하는 데이터 하나를 찾아서 지운다.

exports.delete = async (ctx) => {
    const { id } = ctx.params; 

    try {
        await Book.findByIdAndRemove(id).exec();
    } catch (e) {
        if(e.name === 'CastError') {
            ctx.status = 400;
            return;
        }
    }

    ctx.status = 204; // No Content
};

 

데이터 수정 (PUT, PATCH)

 

# PUT 과 PATCH 는 둘 다 데이터를 변경해주지만,

PUT 은 데이터를 통째로 바꾸어주는 메서드이고, → 데이터의 모든 필드를 검증해야 할 것이고, 필드가 존재하지 않으면 새로 만들어줘야 한다.

PATCH 는 주어진 일부 필드만 바꾸어주는 메서드이다.

# PUT 구현해보기

PUT 메서드를 사용할 때 각 필드를 if, 배열, 반복문을 통해 일일이 체크해야 하지만 번거로우니까

이를 편리하게 해주는 'Joi 라이브러리'를 사용해보자.

 

yarn add joi
const Joi = require('joi');
const { Types: { ObjectId } } = require('mongoose');
// (같은 코딩) cnost ObjectId = require('mongoose').Types.ObjectId;

exports.replace = async (ctx) => {
    const { id } = ctx.params; 

    if(!ObjectId.isValid(id)) {
        ctx.status = 400; // Bad Request
        return;
    }

    // 먼저, 검증 할 스키마를 준비해야합니다.
    const schema = Joi.object().keys({ 
        title: Joi.string().required(),
        authors: Joi.array().items(Joi.object().keys({
            name: Joi.string().required(),
            email: Joi.string().email().required()
        })),
        publishedDate: Joi.date().required(),
        price: Joi.number().required(),
        tags: Joi.array().items((Joi.string()).required())
    });

    const result = schema.validate(ctx.request.body);

    if(result.error) {
        ctx.status = 400; // Bad Request
        ctx.body = result.error;
        return;
    }
}

    let book;

    try {
        book = await Book.findByIdAndUpdate(id, ctx.request.body, {
            upsert: true, 
            new: true 
        });
    } catch (e) {
        return ctx.throw(500, e);
    }
    ctx.body = book;
}

또 하나하나 뜯어보자

if(!ObjectId.isValid(id)) {
  ctx.status = 400;
  return;
}

ObjectId 의 유효성을 검증하는 부분이다.

    const schema = Joi.object().keys({
        title: Joi.string().required(),
        authors: Joi.array().items(Joi.object().keys({
            name: Joi.string().required(),
            email: Joi.string().email().required() 
        })),
        publishedDate: Joi.date().required(),
        price: Joi.number().required(),
        tags: Joi.array().items((Joi.string()).required())
    });

검증할 Schema 를 정의해주었다. 여기서 각 필드 뒤에 붙은 required() 는 필수 요소라는 의미이다.

또한 email: Joi.string().email().required() 를 통해 이메일도 쉽게 검증할 수 있다.

const result = schema.validate(ctx.request.body);

validate() 를 통해서 request body 를 검증해주는 단계이다.

- schema : 검증의 기준인 스키마

- ctx.request.body : 검증 대상

try {
        book = await Book.findByIdAndUpdate(id, ctx.request.body, {
            upsert: true, 
            new: true 
        });
    } catch (e) {
        return ctx.throw(500, e);
    }

findByIdAndUpdate() 함수의 파라미터는 아래와 같다.

findByIdAndUpdate(아이디, 변경할 값, 설정)

- id : 업데이트할 id 값

- ctx.request.body : 변경할 값

- 설정 : upsert 는 '데이터가 존재하지 않으면 새로 만들어준다.'는 뜻이다.

new 는 이 값을 넣어주어야 반환하는 값이 업데이트된 값이다. 안넣어주면 ctx.body = book 했을 때 업데이트되기 전의 데이터를 보여준다.

# PATCH 구현해보기

exports.update = async (ctx) => {
    const { id } = ctx.params; 

    if(!ObjectId.isValid(id)) {
        ctx.status = 400; // Bad Request
        return;
    }

    let book;

    try {
        book = await Book.findByIdAndUpdate(id, ctx.request.body, {
            new: true 
        });
    } catch (e) {
        return ctx.throw(500, e);
    }

    ctx.body = book;
};

 

PUT 이랑 매우 유사하지만 upsert 옵션을 주지 않는 점이 다르다.

book = await Book.findByIdAndUpdate(id, ctx.request.body, {
  new: true
});

findByIdAndUpdate 함수의 upsert 옵션의 기본 값은 false 이기 때문에 해당 옵션을 주지 않는다는 것은

데이터가 존재하지 않으면 생성하지 않는 것이다. = PATCH


출처 : https://backend-intro.vlpt.us/2/06.html

 

2-6. 데이터 삭제와 수정, 그리고 요청 검증 · GitBook

2-6. 데이터 삭제와 수정, 그리고 요청 검증 데이터 삭제 이번엔 데이터 삭제를 해보겠습니다. 데이터를 삭제 할 때에는 여러가지 방법이 있습니다: .remove: 특정 조건을 만족하는 데이터들을 모두

backend-intro.vlpt.us

 

Comments