블로그용 API 만들기-2

Photo by Nahil Naseer on Unsplash

회원정보를 수정하거나 삭제하는 라우터를 만들어보자

routes/users.js

수정은 업데이트이므로 put 메서드를 사용한다.
삭제는 delete 메서드를 사용한다.

const router = require("express").Router();
const User - require("../models/User");

//수정
router.put("/", async (req, res) => {
	try {
    } catch {
    	res.status(500).json(err);
    }
});

//삭제
router.delete("/" ...

회원정보 수정

url parameter에 UserId를 넣어 구별한다.

router.put("/:id",

ex)

  • 클라이언트가 보낸 요청
    api/users/123456
  • 서버가 가지고 있는 UserId
    { userId : 123456 , password: 123456abcd ... }
  1. 사용자 인증 (나중에 jwt 토큰으로 대체)
    라우트 파라미터가 가지고 있는 id(정보수정 페이지로 넘어올때 url에 넘긴 id값을 캡쳐해온다)와 (api/users/:id) 요청body안의 UserId와 비교한다.
    같다면 업데이트 작업 수행 / 다르다면 401 Unauthorized(인증실패) 메세지 출력

req.params | Express 5.x API Reference
현재 라우트 이름에 따라 바뀌는 객체. 예를들어 라우터 경로가 user/:name 일 경우에 req.params.name으로 사용할 수 있다. 기본값은 빈 객체({})다.

route parameters
요청url에 들어있는 특정 값을 가져오기 위한 url의 한 부분( :id , :name ...등등)이다.
req.params 안에 { 라우트파라미터이름 : 파라미터 값 } 으로 들어간다.

Route path: /users/:userId/books/:bookId
Request URL: http://localhost:3000/users/34/books/8989
req.params: { "userId": "34", "bookId": "8989" }

Express.js req.params Property - geeks for geeks

if (req.body.userId === req.params.id)

//UPDATE
router.put("/:id", async (req, res) => {
    if(req.body.userId === req.params.id) {
        try {
          
        } catch {
            res.status(500).json(err);
        }
    } else {
        res.status(401).json("잘못된 접근입니다.")
    }
});
  1. 사용자 인증 성공 시 body에 비밀번호가 있다면 암호화
    사용자보낸 body에 password값이 있다면 bycrypt로 암호화 후 진행한다.
if(req.body.password) {
	const saltRounds = 10;
    const salt = await bcrypt.genSalt(saltRounds);
    req.body.password = await bcypt.hash(req.body.password, salt);
}
  1. 업데이트한 값을 findByIdAndUpdate를 이용해 $set으로 넣어준다.
    findByIdAndUpdate : document의 _id를 기준으로 MongoDB findAndModify를 수행한다.

findAndModify - MongoDB
findByIdAndUpdate - mongoose
$set - mongoose

Example:
Model.findByIdAndUpdate(id, { name: 'jason bourne' }, options, callback)

// is sent as
Model.findByIdAndUpdate(id, { $set: { name: 'jason bourne' }}, options, callback)
This helps prevent accidentally overwriting your document with { name: 'jason bourne' }.

const router = require("express").Router();
const e = require("express");
const User = require("../models/User");
const bcrypt = require("bcrypt");

//UPDATE
router.put("/:id", async (req, res) => {
    if(req.body.userId === req.params.id) {
        if(req.body.password) {
            const saltRounds = 10;
            const salt = await bcrypt.genSalt(saltRounds)
            req.body.password = await bcrypt.hash(req.body.password, salt);
        }
        try {
            const updatedUser = await User.findByIdAndUpdate(req.param.id, {
                $set: req.body,
            });
            res.status(200).json(updatedUser);
    
        } catch {
            res.status(500).json(err);
        }
    } else {
        res.status(401).json("계정 소유자만 수정 가능합니다.")
    }
});

module.exports = router;

index.js에서 라우터를 불러온다.

const userRoute = require("./routes/users");
app.use("/api/user", userRoute");

이제 MongoDB에 저장되있는 유저 아이디로 요청해보자

  • body에 담긴 userId가 라우트파라미터와 일치하지 않을 경우

  • 일치하는 경우 (200)

    여기서 응답객체가 업데이트되지 않은 상태로 보여지는데 MongoDB를 확인해보면 업데이트 되어있다.

다시 users.js route파일로 돌아가서 updatedUserfindByIdAndUpdate에 옵션으로 {new: true}를 추가해준다.

findOneAndUpdate()는 업데이트가 적용되기 전 document를 반환하지만, new: true로 설정하면 엄데이트 된 후의 객체를 반환한다.

const updatedUser = Users.findByIdAndUpdate(req.params, {
  $set: req.body
}, {new = true});

다시 요청을 시도해보자

이제 업데이트된 후의 데이터를 반환한다.

계정삭제

//DELETE
router.delete('/:id', async (req, res) => {
    if(req.body.userId === req.params.id) {
      try {
        await User.findByIdAndDelete(req.params.id);
        res.status(200).json("계정이 삭제되었습니다.")
      } catch (err) {
        res.status(500).json(err);  
    } else {
        res.status(401).json("본인 소유 계정만 삭제 가능합니다.")
    }
})

사용자 정보 수정과 마찬가지로 유저아이디를 비교한 후
findByIdAndDelete를 사용해 파라미터에 명시된 계정id를 db에서 찾아 삭제한다.

단, 이 과정에서 계정이 삭제되면 계정사용자가 업로드한 게시물도 지워져야 한다.

User.findById로 id를 검색했을때 계정이 있다면 작업을 계속하고 없는 경우에는 사용자를 찾을 수 없다는 메시지(404)를 출력하는 조건문을 추가한다.

  • 통신은 항상 await로 실행한다 -> 언제 응답할 지 모르니까
//DELETE
router.delete('/:id', async (req, res) => {
    if(req.body.userId === req.params.id) {
        if(await User.findById(req.params.id)) {
            try {
                await User.findByIdAndDelete(req.params.id);
                res.status(200).json("계정이 삭제되었습니다.")
            } catch (err) {
                res.status(500).json(err);
            }
        } else {
            res.status(404).json("사용자를 찾을 수 없습니다.")
        }
    } else {
        res.status(401).json("본인 소유 계정만 삭제 가능합니다.")
    }
})

이제 포스트 정보를 가져오기 위해 포스트모델을 불러온다.
const Post = require("../models/Post");

Post모델을 기준으로 deleteMany를 사용해 DB안에서 username이 User.username과 같은 모든 document들을 삭제하는 코드를 추가한다.

포스트맨에서 삭제요청을 테스트한다.

DB내에서도 사라졌다.

유저 정보 불러오기

//GET USER
router.get("/:id", async (req, res) => {
    try {
        const user = await User.findById(req.params.id);
        const {password, ...others} = user._doc;
        res.status(200).json(others);
    } catch(err) {
        res.status(500).json(err);   
    }
})

데이터를 수정하지 않고 열람만 할 경우get메서드를 사용해 불러온다.
findById로 파라미터의 id값과 일치하는 document를 user라는 변수에 저장하고
로그인 라우터를 만들때처럼 디스트럭처링으로 mongoose document class를 받아오고 _doc프로퍼티를 이용해서 비밀번호만 빼고 사용자 정보를 보여줄 수 있다.

패스워드를 제외한 나머지 정보가 정상적으로 들어온다.

좋은 웹페이지 즐겨찾기