node-express로 REST API 만들기(2)

Seungsoo Lee·2022년 8월 24일
0

web

목록 보기
7/13

앞선 포스트에서
1. 설치
2. mongo db 연결
3. port 열기
4. route 설정
5. DB Schema 설정
이 과정을 다 해주었다.

이제 실제로 rest api를 만들어보겠다.

  1. Auth(register, login) api
  2. Users api
  3. Posts api

Auth(register, login) api

  • 가장 먼저 해야할게 회원가입과 로그인 절차이다. 이 부분을 api로 작성해야하는데, 이를 ./server/routes/auth.js 에다가 써보기로 한다.

  • 참고로 index.js를 보면 auth.js 는 http://localhost:8800/api/auth 로 시작된다.

- Register

- 아까 `./server/model/User.js` 에 작성했던 user db schema를 보면 username, email, password가 requied가 true로 되어있었다. 따라서 회원가입 할 때 도 꼭 써주어야 한다.
- User model을 사용하기 위해 `./server/model/User.js` 를 불러와준다.
- `new User`을 통해 새로운 user를 생성하고 `.save()` 해서 mongo db에 write한다. 그리고 response로 정상적으로 회원가입이 되었다고 `res.status(200)`을 보내준다..
- password 같은경우는 그대로 써주면 안되기 때문에 bcrypt라는 라이브러리를 사용할 것이다.
- _참고로 req는 request로 요청이 들어온걸 말하고 res는 그 들어온 요청을 바탕으로 이 코드에서 결과값을 response해준다는 것이다._
- _req.body를 통해 json의 형식을 볼 수 있고, body 뒤에 .key를 입력하면 value를 알아낼 수 있다. (예를 들어 req.body.password 를 하면 { "password" : "1234" } 에서 1234를 불러온다.)_
- _500 error는 서버 내부 에러이다. 따라서 코드가 잘못된경우일때 res.status를 통해 에러를 표시한다. 200은 정상이라는 의미이다._
<auth.js>
const router = require("express").Router();
const User = require("../models/User");
const bcrypt = require("bcrypt");

//REGISTER
router.post("/register", async (req, res) => {
	console.log(req.body);
	

	try{
		// generate new password
		const salt = await bcrypt.genSalt(10);
		const hashedPassword = await bcrypt.hash(req.body.password, salt);
		
		// create new users
		const newUser = new User({
			username: req.body.username,
			email: req.body.email,
			password: hashedPassword,
		});
		
		// save user and respond
		const user = await newUser.save();
		res.status(200).json(user);
	} catch (err) {
		res.status(500).json(err);
	}
});

- Login

- 로그인 같은 경우에는 req로 온 email과 password가 mongo db에 있는 user의 것인지 확인을 해주는 작업을 해야한다.
- 따라서 `User.findOne()` 함수로 email을 먼저 확인하고 없으면 user가 없다는 404에러를 날려준다.
- email은 존재하는데 password가 틀렸을 경우가 있기 때문에 밑에 다시 `bcrypt.compare()`함수로 password가 맞는지 확인한다. bycrypt의 compare을 사용하는 이유는 우리가 회원가입을 할때 비밀번호를 해쉬화 해주었기 때문이다.
- 둘다 정확하게 맞게 된 경우에만 200을 response해준다.

<auth.js>

//LOGIN
router.post("/login", async (req, res) => {
	try {
		const user = await User.findOne({ email: req.body.email });
		!user && res.status(404).json("user not found");

		const validPassword = await bcrypt.compare(req.body.password, user.password)
		!validPassword && res.status(400).json("wrong password");

		res.status(200).json(user);
	} catch (err) {
		res.status(500).json(err);
	}
});

Users api

  • user 관리를 해줘야한다. 만들어줄 api들은 대략 아래와 같다.

update user
delete user
get a user
follow a user
unfollow a user

  • 이 부분을 api로 작성해야하는데, 이를 ./server/routes/users.js 에다가 써보기로 한다.
  • 참고로 index.js를 보면 users.js 는 http://localhost:8800/api/users 로 시작된다.

- update user

일단 user 스스로가 자신의 정보(비밀번호)를 업데이트 할 수 있어야 하기 때문에 update를 해주는 api를 만들어줘야 할 것 같다.
- update를 해주기 때문에 put method를 사용할 것이다.
- 앞의 routing을 보면 /:id라고 되어있는데 이것은 어떤값이 뒤에 들어가더라도 req.params.id로 읽어낼 수 있다고 생각하면 된다.
- 일단 update하려면 그 주체가 나 자신만이 할 수 있게 되어야한다. 따라서 req.body에 적힌 id가 param(url)으로 넘겨진 id와 같아야지 바꿀 수 있게 해주었다.
- 그리고 만약에 req.body에 password를 바꾸려고 입력이 들어갔다면, 이 password를 다시 hash처리하는 부분도 넣어두었다.
- 다음에 이제 실제로 이 req.body에 들어간 내용을 update를 해줘야 하는데 User.findByIdAndUpdate()함수를 이용한다. 첫번째 parameter로는 id가 들어가겠고, 두번째 parameter로는 바뀔 내용이 들어간다. {$set: req.body,}를 하면 바로 자동으로 바꿔준다.
- 그리고 마무리가 되었으니 res.status(200)을 response 날려주고 json형식으로는 update되었다는 메시지를 response 날려준다.
<user.js>

// update user
router.put("/:id", async (req, res) => {
	if (req.body.userId === req.params.id || req.body.isAdmin) {
		if (req.body.password) {
			try{
				const salt = await bcrypt.genSalt(10);
				req.body.password = await bycrypt.hash(req.body.password, salt);
			} catch (err) {
				return res.status(500).json(err);
			}
		}
		try {
			const user = await User.findByIdAndUpdate(req.params.id, {
				$set: req.body,
			});
			res.status(200).json("Account has been updated")
		} catch (err) {
			return res.status(500).json(err);
		}
	} else {
		return res.status(403).json("You can update only your account!");
	}
})

- delete user

user가 만약 이 곳을 탈퇴하고 싶다면, 그럴 수 있게 해줘야한다... 아니면 스팸계정같은것을 관리자가 지울 수 있도록 해줘야한다.
그래서 delete를 해주는 api도 만들어줘야한다.
- 먼저 확인해야하는것은 params(url)로 들어온 id와 req.body에 있는 id를 체킹해준다. 아니면 관리자 권한이 있는 사람이면 이 조건을 통과하게 되도록 만든다.
- 그리고 User.findByIdAndDelete()함수로 id를 통해 해당 유저를 삭제한다.
- 성공이면 res.status(200)을 response로 날려주고 json으로 delete되었다는 메세지를 보내준다.
- 만약 조건에 맞지 않는 경우라면 res.status(403) response를 날려준다.
<users.js>

// delete user
router.delete("/:id", async (req, res) => {
	if (req.body.userId === req.params.id || req.body.isAdmin) {
		try {
			const user = await User.findByIdAndDelete(req.params.id);
			res.status(200).json("Account has been deleted")
		} catch (err) {
			return res.status(500).json(err);
		}
	} else {
		return res.status(403).json("You can delete only your account!");
	}
})

- get a user

user의 프로필 페이지에 들어간다면, user의 정보를 받아와야한다. 따라서 그 각 유저에 대한 데이터를 불러오기위해 api가 필요로 할것이다.
- user에 대한 정보를 불러만 오면 되니까 get method를 사용한다.
- params(url)으로 들어온 id에 대한 정보를 보여주기만 하면 되니까, User.findById()함수를 통해 user을 불러와주고 password와 updateAt 데이터를 뺀 ...other 데이터를 불러서 json으로 response해준다.
<users.js>

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

- follow a user

user끼리 follow할 수 있는 사이트를 만들고 싶었다. 따라서 그 기능을 api에 추가해야한다.
- :id/follow로 follow를 할 수 있게 만들었다.
- 들어가기 앞서 정리를 하자면 param으로 들어오는 id는 follow받는사람. req로 들어오는 id는 follow 하는 사람.
- 먼저 자신을 팔로우 할 수 없기 때문에, req를 보내는 id인 (req.body.userId)가 param.id가 되면 안된다.
- 그리고 그 조건을 통과한 경우 User.findById()를 통해서 follower가 될 사람을 user에다 넣고 following 하는 사람을 currentUser에 넣는다.
- 그 다음, user.updateOne()함수를 통해 user(follower가 될 사람)의 follower array에 req.body.userId(following 하는 사람)을 push해준다. 반대로, currentUser.updateOne()함수를 통해 currentUser(following 하는 사람)의 following array에 req.param.id(follower가 될 사람)을 push해준다.
- 성공하면 res.status(200)을 response해주고, json으로 user가 팔로우했다는 메세지를 response해준다.
<users.js>

// follow a user
router.put("/:id/follow", async (req, res) => {
	if (req.body.userId != req.params.id) {
		try {
			const user = await User.findById(req.params.id);
			const currentUser = await User.findById(req.body.userId);
			if (!user.followers.includes(req.body.userId)) {
				await user.updateOne({ $push: { followers: req.body.userId } });
				await currentUser.updateOne({ $push: { followings: req.params.id } });
				res.status(200).json("user has been followed");
			} else {
				res.status(403).json("you already follow this user");
			}
		} catch (err) {
			res.status(500).json(err);
		}
	} else {
		res.status(403).json("you can't follow yourself");
	}
})

- unfollow a user

특정인물이 어떤사람을 follow를 했지만, 사이가 틀어져서 팔로우를 취소하고 싶을때가 있다. 그렇기 때문에 unfollow하는 부분도 api로 만들어줘야 할 것 같다.
- :id/unfollow로 unfollow를 할 수 있게 만들었다.
- 들어가기 앞서 정리를 하자면 param으로 들어오는 id는 unfollow당하는 사람. req로 들어오는 id는 unfollow 하는 사람.
- follow와 마찬가지로 스스로 follow도 안되기 때문에 unfollow도 할 수 없다.
- User.findById()로 각각의 user를 변수에 할당해준다.
- 그리고 unfollow 당하는 사람의 follower에 unfollow하려는 사람이 속해 있다면, unfollow를 진행한다.
- updateOne()함수를 통해 그리고 $pull:을 통해 각각의 follower following array를 업데이트 해준다.
- 성공하면 res.status(200)을 response해주고 json으로 unfollowed 되었다는 메세지를 response해준다.
<users.js>

// unfollow a user
router.put("/:id/unfollow", async (req, res) => {
	if (req.body.userId != req.params.id) {
		try {
			const user = await User.findById(req.params.id);
			const currentUser = await User.findById(req.body.userId);
			if (user.followers.includes(req.body.userId)) {
				await user.updateOne({ $pull: { followers: req.body.userId } });
				await currentUser.updateOne({ $pull: { followings: req.params.id } });
				res.status(200).json("user has been unfollowed");
			} else {
				res.status(403).json("you don't follow this user");
			}
		} catch (err) {
			res.status(500).json(err);
		}
	} else {
		res.status(403).json("you can't unfollow yourself");
	}
})

다음 포스트에 이어진다.

0개의 댓글