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

데이터 삭제

이번엔 데이터 삭제를 해보겠습니다. 데이터를 삭제 할 때에는 여러가지 방법이 있습니다:

  • .remove: 특정 조건을 만족하는 데이터들을 모두 지웁니다.
  • .findByIdAndRemove: id 를 찾아서 지웁니다.
  • .findOneAndRemove: 특정 조건을 만족하는 데이터 하나를 찾아서 지웁니다.

우리는, .findByIdAndRemove 를 사용하도록 하겠습니다.

src/api/books/books.controller.js

exports.delete = async (ctx) => {
    const { id } = ctx.params; // URL 파라미터에서 id 값을 읽어옵니다.

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

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

그 다음에는 books 라우트 인덱스에서 delete API 에 id 파라미터를 받도록 설정하세요. 그리고 앞으로 구현 할 put 과 patch 도 id 를 필요로 하니, 해당 API 들에도 :id 를 넣으세요.

PUT 과 PATCH

PUT 과 PATCH 는 서로 비슷하지만, 역할이 다릅니다. 둘 다 데이터를 변경하는데요, PUT 의 경우엔 데이터를 통째로 바꿔버리는 메소드이며, PATCH 의 경우엔 주어진 필드만 수정하는 메소드입니다.

따라서, 구현 방식은 비슷 할 수도 있겠지만, PUT 의 경우엔 모든 필드를 받도록 데이터를 검증해야합니다.

추가적으로 PUT 의 경우에 데이터가 존재하지 않는다면 데이터를 새로 만들어주어야 하는게 원칙입니다.

Request Body 를 검증하려면, if 문, 혹은 배열과 반복문을 통하여 각 필드를 일일히 체크하는 방식도 있겠지만, 이를 더 편리하게 해주는 라이브러리가 존재합니다. 심지어 값의 형식도 검사를 할 수 있게 해줍니다.

Joi

바로, Joi 라는 라이브러리 입니다. 이 라이브러리를 먼저 설치해주세요.

$ yarn add joi

그리고, comments.controller.js 의 상단에 Joi 를 불러오세요. 이번엔 ObjectId 도 사전 검증을 해보겠습니다. ObjectId 도 mongoose 에서 불러오도록 하겠습니다.

src/api/comments/comments.controller.js - 상단

const Joi = require('joi');
const { Types: { ObjectId } } = require('mongoose');

코드가 좀 생소하게 느껴질수도있는데, 위 코드의 두번째 줄은 다음 코드와 동일합니다.

const ObjectId = require('mongoose').Types.ObjectId

먼저 PUT 메소드에서 사용 할 replace 를 구현하도록 하겠습니다. 이제 replace 함수에서 id 파라미터와, request body 를 검증하는 코드를 다음과 같이 입력하세요.

src/api/comments/comments.controller.js - replace

exports.replace = async (ctx) => {
    const { id } = ctx.params; // URL 파라미터에서 id 값을 읽어옵니다.

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

    // 먼저, 검증 할 스키마를 준비해야합니다.
    const schema = Joi.object().keys({ // 객체의 field 를 검증합니다.
        // 뒤에 required() 를 붙여주면 필수 항목이라는 의미입니다
        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())
    });

    // 그 다음엔, validate 를 통하여 검증을 합니다.
    const result = Joi.validate(ctx.request.body, schema); // 첫번째 파라미터는 검증할 객체이고, 두번째는 스키마입니다.

    // 스키마가 잘못됐다면
    if(result.error) {
        ctx.status = 400; // Bad Request
        ctx.body = result.error;
        return;
    }
}

지금은, 에러처리만 해주었습니다. 이제 PUT 의 로직을 완성하겠습니다. 데이터를 교체할때는, .findByIdAndUpdate 를 사용하며 upsert 설정을 함으로서, 데이터가 존재하지 않으면 새로 데이터를 만들도록 설정하였습니다. 방금 작성한 코드 하단을 다음과 같이 완성하세요.

src/api/books/books.controller.js - replace 하단

    (...)
    let book;

    try {
        // 아이디로 찾아서 업데이트를 합니다.
        // 파라미터는 (아이디, 변경 할 값, 설정) 순 입니다.
        book = await Book.findByIdAndUpdate(id, ctx.request.body, {
            upsert: true, // 이 값을 넣어주면 데이터가 존재하지 않으면 새로 만들어줍니다
            new: true // 이 값을 넣어줘야 반환하는 값이 업데이트된 데이터입니다.
                      // 이 값이 없으면 ctx.body = book 했을때 업데이트 전의 데이터를 보여줍니다.
        });
    } catch (e) {
        return ctx.throw(500, e);
    }
    ctx.body = book;
}

이제, 기존의 POST 요청때 사용했던 request body 를 복사하고, PUT http://localhost:4000/api/books/:id 요청을 넣어보세요.

만약에 id 가 존재하지 않는다면 새 데이터를 생성하고, 스키마가 잘못되었다면 오류가 뜨게 됩니다.

데이터베이스에 접근하는 REST API 를 만들때에는, 파라미터와 스키마를 검사하는것이 중요합니다. 그렇게 함으로서, 값이 잘못되어서 발생 할 수 있는 버그를 잡아낼 수 있습니다.

PATCH 구현하기

PATCH 메소드는, 주어진 필드만 수정을 해줍니다. 구현 방식은 PUT 과 비슷하지만, 주어진 값만 수정하도록 로직을 작성해야합니다.

src/api/books/books.controller.js - update

exports.update = async (ctx) => {
    const { id } = ctx.params; // URL 파라미터에서 id 값을 읽어옵니다.

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

    let book;

    try {
        // 아이디로 찾아서 업데이트를 합니다.
        // 파라미터는 (아이디, 변경 할 값, 설정) 순 입니다.
        book = await Book.findByIdAndUpdate(id, ctx.request.body, {
            // upsert 의 기본값은 false 입니다.
            new: true // 이 값을 넣어줘야 반환하는 값이 업데이트된 데이터입니다. 이 값이 없으면 ctx.body = book 했을때 업데이트 전의 데이터를 보여줍니다.
        });
    } catch (e) {
        return ctx.throw(500, e);
    }

    ctx.body = book;
};

이제, PATCH http://localhost:4000/api/books/:id 요청을 request body 에 일부 필드를 생략하고 요청을 해보세요. 잘되나요?

축하합니다, 이제 여러분은 REST API 를 만들 수 있게 되었습니다! 앞으로는 결국 이렇게 요청에서 받은 값을 토대로 데이터를 조회하고, 생성하고, 수정하고, 삭제를 하면서 프로젝트의 기능을 구현해나갈것입니다.

이제 우리는 더 이상 books API 와 모델은 필요하지 않습니다. books API 와 모델 코드를 삭제하셔도 좋습니다. 하지만, 작업하면서 참고를 하시고싶다면, 남겨두고 나중에 삭제를 하셔도 됩니다.

results matching ""

    No results matching ""