찔끔찔끔씩😎

[Sopt] 3차 세미나(2) - NodeJS CRUD 실습✨ 본문

Server/Nodejs

[Sopt] 3차 세미나(2) - NodeJS CRUD 실습✨

댕경 2022. 5. 17. 02:06
728x90

세팅

🔎 프로젝트 구조

 


Create / User Collection 생성

이름, 핸드폰 번호, 이메일, 학교(학교이름, 전공)

 

🔎 1. Model 만들기

src/models/User.ts

// User Collection 위치
import mongoose from 'mongoose';
import { UserInfo } from '../interfaces/user/UserInfo';

const UserSchema = new mongoose.Schema({
    /*
    type: field type 지정
    required: 필수 field 인가?
    unique: 고유한 값인가?
    */
    name: {
        type: String,
        required: true,
    },
    phone: {
        type: String,
        required: true,
    },
    email: {
        type: String,
        required: true,
        unique: true, // 중복불가
    },
    age: {
        type: Number,
    },
    school: {
        // 중첩 document
        name: { type: String },
        major: { type: String },
    },
});

//UserSchema를 User라는 이름으로 내보내겠다
export default mongoose.model<UserInfo & mongoose.Document>('User', UserSchema);

 

src/interfaces/user/UserInfo.ts

import { SchoolInfo } from '../school/SchoolInfo';

export interface UserInfo {
    //이름,핸드폰,이메일,학교
    name: string;
    phone: string;
    email: string;
    age: number;
    school: SchoolInfo;
    //school(학교이름, 전공)
    // scool:{
    //     name: string;
    //     major: string;
    // }
    // 로 해도 되지만, 기능별로 세분화하자
}

 

src/interfaces/user/UserInfo.ts

export interface SchoolInfo {
    name: string;
    major: string;
}

 

🔎 2. Controller 만들기

src/controllers/UserController.ts       

res.status(XXX).send(json)

  • .status: status code를 정수로 입력
  • .send(json): json형식으로 response body에 입력한다. 통일된 형식을 유지해야한다.
/**
 *  @route POST /user
 *  @desc Create User
 *  @access Public
 */
const createUser = async (req: Request, res: Response) => {
    const UserCreateDto: UserCreateDto = req.body; // User Create Dto 로 req.body 받아옴

    try {
        const data: PostBaseResponseDto = await UserService.createUser(
            UserCreateDto,
        );

        res.status(statusCode.CREATED).send(
            util.success(statusCode.CREATED, message.CREATE_USER_SUCCESS, data),
        );

    } catch (error) {
        console.log(error);
        //서버 내부에서 오류 발생
        res.status(statusCode.INTERNAL_SERVER_ERROR).send(
            util.fail(
                statusCode.INTERNAL_SERVER_ERROR,
                message.INTERNAL_SERVER_ERROR,
            ),
        );
    }
};

 

 

🔎 3. DTO 만들기

src/interfaces/user/UserCreateDto.ts

import { SchoolInfo } from '../school/SchoolInfo';

export interface UserCreateDto {
    name: string;
    phone: string;
    email: string;
    age?: number;
    school: SchoolInfo;
}

src/interfaces/common/PostBaseResponseDto.ts

import mongoose from 'mongoose';

export interface PostBaseResponseDto {
    _id: mongoose.Schema.Types.ObjectId;
}

 

🔎 4. Service 만들기

src/services/UserService.ts

const createUser = async (
    userCreateDto: UserCreateDto,
): Promise<PostBaseResponseDto> => {
    //Dto로 객체를 전달한다.
    try {
        const user = new User({
            name: userCreateDto.name,
            phone: userCreateDto.phone,
            email: userCreateDto.email,
            age: userCreateDto.age,
            school: {
                name: userCreateDto.school?.name,
                major: userCreateDto.school?.major,
            },
        }); // document 를 만들 준비 끝

        await user.save();
        // 편리한 mongoose~
        // .save로 새로운 document 생성 후 mongoDB에 저장

        const data = {
            _id: user.id,
        };
        // 반환 값 가공

        return data;
        // 위에 저장된 데이터의 id를 반환
    } catch (error) {
        console.log(error);
        throw error;
    }
};

 

🔎 5. 잊지 말고 export default 를 통해 모듈화 해주기 + index.ts 들에 등록해주기

 

🔎 6. Router 연결하기

src/route/UserRouter.ts

import { Router } from 'express';
import { UserController } from '../controllers';
const router: Router = Router();

// routes => use(/user) => post(/)
router.post('/', UserController.createUser);

 

🔎 7. VSC Thunder Client를 사용하여 API 확인하기


Update / User Collection 수정

🔎 1. Controller 만들기

/**
 *  @route PUT /user/:userId
 *  @desc Update User
 *  @access Public
 */
const updateUser = async (req: Request, res: Response) => {
    const userUpdateDto: UserUpdateDto = req.body; // DTO 사용
    const { userId } = req.params; // route에서 userId를 받아온다.

    try {
        await UserService.updateUser(userId, userUpdateDto);
        // UserService 에서

        res.status(statusCode.NO_CONTENT).send();
        // 해당 값이 없다면 204 NO CONTENT
    } catch (error) {
        console.log(error);
        //서버 내부에서 오류 발생
        res.status(statusCode.INTERNAL_SERVER_ERROR).send(
            util.fail(
                statusCode.INTERNAL_SERVER_ERROR,
                message.INTERNAL_SERVER_ERROR,
            ),
        );
    }
};

 

🔎 2. DTO 만들기

전체가 수정되는 것이 아니기 때문에 모든 것을 optional 로 지정한다.

import { SchoolInfo } from '../school/SchoolInfo';

export interface UserUpdateDto {
    name?: string;
    phone?: string;
    email?: string;
    age?: number;
    school?: SchoolInfo;
}

 

🔎 3. Service 만들기

const updateUser = async (userId: string, userUpdateDto: UserUpdateDto) => {
    try {
        //findByIdAndUpdate 함수 사용할 것
        // createUser에서 한거 처럼 일일이 넣어줘도 되긴 함
        await User.findByIdAndUpdate(userId, userUpdateDto);
    } catch (error) {
        console.log(error);
        throw error;
    }
};

 

🔎 4. Router 연결하기

router.put('/:userId', UserController.updateUser);

Read / User Collection 조회

🔎 1. Controller 만들기

/**
 *  @route GET /user/:userId
 *  @desc Read User
 *  @access Public
 */
const findUserById = async (req: Request, res: Response) => {
    const { userId } = req.params; // route에서 userId를 받아온다.

    try {
        const data = await UserService.findUserById(userId);

        if (!data) {
            return res
                .status(statusCode.NOT_FOUND)
                .send(util.fail(statusCode.NOT_FOUND, message.NOT_FOUND));
        }

        res.status(statusCode.OK).send(
            util.success(statusCode.OK, message.READ_USER_SUCCESS, data),
        );
    } catch (error) {
        console.log(error);
        res.status(statusCode.INTERNAL_SERVER_ERROR).send(
            util.fail(
                statusCode.INTERNAL_SERVER_ERROR,
                message.INTERNAL_SERVER_ERROR,
            ),
        );
    }
};

 

🔎 2. DTO 만들기

UserCreateDto와 같은 field를 공유하기 때문에 extends로 퉁친다.

import { UserCreateDto } from './UserCreateDto';

// 차피 UserCreatDto랑 쓰는거 똑같으니가 extends
export interface UserResponseDto extends UserCreateDto {}

 

🔎 3. Service 만들기

mongoose의 findById를 사용하여 userId로 조회한다.

const findUserById = async (
    userId: string,
): Promise<UserResponseDto | null> => {
    try {
        const user = await User.findById(userId);

        if (!user) {
            return null;
        }

        return user;
    } catch (error) {
        console.log(error);
        throw error;
    }
};

 

🔎 4. Router 연결하기

router.get('/:userId', UserController.findUserById);

Delete / User Collection 삭제

🔎 1. Controller 만들기

/**
 *  @route DELETE /user/:userId
 *  @desc Delete User
 *  @access Public
 */
const deleteUser = async (req: Request, res: Response) => {
    const { userId } = req.params; // route에서 userId를 받아온다.

    try {
        await UserService.deleteUser(userId);
        return res.status(statusCode.NO_CONTENT).send();
    } catch (error) {
        console.log(error);
        //서버 내부에서 오류 발생
        res.status(statusCode.INTERNAL_SERVER_ERROR).send(
            util.fail(
                statusCode.INTERNAL_SERVER_ERROR,
                message.INTERNAL_SERVER_ERROR,
            ),
        );
    }
};

 

🔎 2. DTO 만들기

데이터를 주고 받을 필요 없이 바로 DB에서 삭제 해줄거기 때문에, DTO가 따로 필요 없다.

 

🔎 3. Service 만들기

mongoose의 findByIdAndDelete()를 사용해 userId로 조회 후 해당 데이터를 삭제한다.

const deleteUser = async (userId: string): Promise<void> => {
    try {
        await User.findByIdAndDelete(userId);
    } catch (error) {
        console.log(error);
        throw error;
    }
};

 

🔎 4. Router 연결하기

router.delete('/:userId', UserController.deleteUser);

User CRUD 완성! ✨✨

 

Comments