Skip to content

Commit

Permalink
[BE][Feat] #159 : 회원가입 api 구현
Browse files Browse the repository at this point in the history
- 회원가입 api에 대한 swagger 문서 추가
- 회원가입 api 구현
- auth에 대한 jsdoc 추가
- 회원가입시 비밀번호 암호화해서 db에 저장
  • Loading branch information
happyhyep committed Nov 13, 2024
1 parent c2ab9cd commit 06e3e19
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 5 deletions.
28 changes: 26 additions & 2 deletions backend/src/controllers/authController.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { loginUser } from '../services/authService.js';
import { loginUser, registerUser } from '../services/authService.js';

export const login = async (req, res) => {
/**
* @description 로그인 컨트롤러
*/
export const loginController = async (req, res) => {
const { id, password } = req.body;

try {
Expand All @@ -18,3 +21,24 @@ export const login = async (req, res) => {
return res.status(500).json({ success: false, message: 'Server error occurred' });
}
};

/**
* @description 회원가입 컨트롤러
*/
export const registerUserController = async (req, res) => {
try {
const { id, name, password, email } = req.body;
const newUser = await registerUser(id, name, password, email);
return res.status(201).json({
success: true,
message: 'Login successfully',
data: newUser,
});
} catch (error) {
if (error.message === 'User ID already exists') {
return res.status(409).json({ error: 'User ID already exists' });
}
console.error('User registration error:', error);
res.status(500).json({ error: 'Server error' });
}
};
40 changes: 40 additions & 0 deletions backend/src/repositories/userRepository.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,46 @@
import { pool } from '../db/db.js';

/**
* @description 데이터베이스에 새로운 사용자 생성
* @param {string} id - 사용자 id
* @returns {object} id로 찾은 사용자 정보
*/
export const findUserById = async id => {
const result = await pool.query('SELECT * FROM "main"."user" WHERE id = $1', [id]);
return result.rows[0];
};

/**
* @description 사용자 ID 중복 여부 확인
* @param {string} id - 사용자 ID
* @returns {boolean} 중복 여부
*/
export const isUserIdDuplicate = async id => {
const query = `
SELECT 1 FROM "main"."user"
WHERE id = $1;
`;
const result = await pool.query(query, [id]);

return result.rows.length > 0;
};

/**
* @description 데이터베이스에 새로운 사용자 생성
* @param {string} id - 사용자 ID
* @param {string} name - 사용자 이름
* @param {string} password - 사용자 비밀번호
* @param {string} email - 사용자 이메일
* @returns {object} 새로 생성된 사용자 정보
*/
export const createUserInDB = async (id, name, password, email) => {
const query = `
INSERT INTO "main"."user" (id, name, password, email)
VALUES ($1, $2, $3, $4)
RETURNING id, name, email;
`;
const values = [id, name, password, email];
const result = await pool.query(query, values);

return result.rows[0];
};
42 changes: 40 additions & 2 deletions backend/src/routes/authRouter.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import express from 'express';
import { body } from 'express-validator';
import { login } from '../controllers/authController.js';
import { loginController, registerUserController } from '../controllers/authController.js';
import { validationMiddleware } from '../middleware/validationMiddleware.js';

export const authRouter = express.Router();
Expand All @@ -11,6 +11,7 @@ export const authRouter = express.Router();
* post:
* summary: 사용자 로그인 API
* description: 사용자가 로그인할 수 있도록 ID와 비밀번호를 통해 인증 후 토큰을 반환합니다.
* tags: [Auth]
* requestBody:
* required: true
* description: 로그인을 위한 ID와 비밀번호를 포함한 요청 body
Expand Down Expand Up @@ -41,5 +42,42 @@ authRouter.post(
.withMessage('Password must be at least 6 characters long'),
],
validationMiddleware,
login,
loginController,
);

/**
* @swagger
* /user/register:
* post:
* summary: "회원가입 API"
* description: "사용자가 회원가입을 통해 계정을 생성합니다."
* tags: [Auth]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/RegisterRequest'
* responses:
* "201":
* description: "회원가입 성공"
* "400":
* description: "유효성 검사 실패"
* "409":
* description: "중복된 사용자 ID"
* "500":
* description: "서버 오류"
*/
authRouter.post(
'/register',
[
body('id').isLength({ min: 4 }).withMessage('User ID must be at least 4 characters long'),
body('name').notEmpty().withMessage('Name is required'),
body('password')
.isLength({ min: 6 })
.withMessage('Password must be at least 6 characters long'),
body('email').isEmail().withMessage('Valid email is required'),
],
validationMiddleware,
registerUserController,
);
28 changes: 27 additions & 1 deletion backend/src/services/authService.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import { findUserById } from '../repositories/userRepository.js';
import { createUserInDB, findUserById, isUserIdDuplicate } from '../repositories/userRepository.js';

/**
* @description 로그인 서비스
* @param {string} name - 사용자 이름
* @param {string} password - 사용자 비밀번호
* @returns {object} 로그인된 사용자의 토큰과 id
*/
export const loginUser = async (id, password) => {
const user = await findUserById(id);
if (!user) {
Expand All @@ -17,3 +23,23 @@ export const loginUser = async (id, password) => {
const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { expiresIn: '1h' });
return { token, userId: user.id };
};

/**
* @description 회원가입 서비스
* @param {string} id - 사용자 ID
* @param {string} name - 사용자 이름
* @param {string} password - 사용자 비밀번호
* @param {string} email - 사용자 이메일
* @returns {object} 새로 생성된 사용자 정보
*/
export const registerUser = async (id, name, password, email) => {
const isDuplicate = await isUserIdDuplicate(id);
if (isDuplicate) {
throw new Error('User ID already exists');
}

const hashedPassword = await bcrypt.hash(password, 10);
const newUser = await createUserInDB(id, name, hashedPassword, email);

return newUser;
};
25 changes: 25 additions & 0 deletions backend/swaggerConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,31 @@ const swaggerDefinition = {
},
},

// 회원가입 요청 스키마
RegisterRequest: {
type: 'object',
properties: {
id: {
type: 'string',
description: '사용자 고유 ID (중복 불가)',
},
name: {
type: 'string',
description: '사용자 이름',
},
password: {
type: 'string',
description: '사용자 비밀번호 (최소 6자 이상)',
},
email: {
type: 'string',
format: 'email',
description: '사용자 이메일 주소',
},
},
required: ['id', 'name', 'password', 'email'],
},

// 채널 생성 요청 스키마
CreateChannelRequest: {
type: 'object',
Expand Down

0 comments on commit 06e3e19

Please sign in to comment.