[TIL] 24.09.10 TUE

GDORI·2024년 9월 10일
0

TIL

목록 보기
37/79
post-thumbnail

트러블슈팅?? 아니, 멍청한 짓..

  • 사건 발단
    라우트를 분리하는 과정을 거쳤고, 새로운 라우터를 저장한 후 테스트를 하는데 전혀 먹히지 않음

  • 이슈
    기존 분리하기 전 라우트 파일이 저장되지 않음.
    기존 정보가 남아있었기 때문에 app.js 내에서 앞단에 있는 라우트 목록에서 처리가 됨

  • 해결
    탭 정리를 잘하고.. 저장을 잘하자...

  • 미완결 트러블
    근데 아직도 해결되지 않은 문제가 하나 더 있었는데, 간헐적으로 아무리 저장하고 서버를 재시작해도 내용이 반영되지 않는
    문제가 발생.
    VSCode 내에서 터미널을 다시 열면 해결이 됨.
    캐시 문제로 보고 있으나, 추후 재설치 해볼 예정

오늘은 지식 부족 이슈로 인해 알고리즘 코드카타 시간 내에 풀지 못했음.
내일 이어서 할 예정, 밑에는 오늘 구현한 개인과제 필수기능 API

기본적으로 구현 해야하는 API

  • 회원가입 API
  • 로그인 API
  • 캐릭터 생성 API
  • 캐릭터 삭제 API
  • 캐릭터 상세조회 API
  • 아이템 생성 API
  • 아이템 수정 API
  • 아이템 목록조회 API
  • 아이템 상세조회 API

1. 회원가입 API

요구조건

  1. 아이디, 비밀번호, 비밀번호 확인, 이름 데이터로 회원가입 요청
  2. 보안을 위하여 비밀번호는 해싱처리
  3. 아이디는 중복되지 않으며, 오로지 영어 소문자 + 숫자 조합으로 구성
  4. 비밀번호는 최소 6자 이상이며, 비밀번호 확인과 일치
  5. 실패 시 Status Code 및 메시지 반환
  6. 성공 시 비밀번호를 제외한 사용자 정보 반환
  7. 성공 시 Authorization Header에 토큰값 반환

요청

{
  "userId": "your_Id",
  "userPw": "your_Password",
  "confirmPw" : "one_more_your_Password",
  "userName" : "your_name"
}

응답

  • 성공 (201)
data: {
      userNo: cretead_id_No,
      userId: cretead_id,
      userName: cretead_id_userName,
    }
  • 실패 (400)
{errorMessage: "아이디는 소문자+숫자 형식만 가능합니다."}
{errorMessage: "비밀번호는 최소 6자리 이상만 가능합니다."}
  • 실패 (401)
{errorMessage: "비밀번호와 확인이 일치하지 않습니다."}
  • 실패 (409)
{errorMessage: "이미 존재하는 아이디 입니다."}

API CODE

router.post("/sign-up", async (req, res, next) => {
  const { userId, userPw, confirmPw, userName } = req.body;

  const validUserId = /^[a-z0-9]+$/;

  const isUser = await prisma.users.findFirst({
    where: { userId },
  });
  if (isUser)
    return res.status(409).json({
      errorMessage: "이미 존재하는 아이디 입니다.",
    });
  if (!validUserId.test(userId))
    return res.status(400).json({
      errorMessage: "아이디는 소문자 + 숫자 형식만 가능합니다.",
    });
  if (userPw.length < 6)
    return res.status(400).json({
      errorMessage: "비밀번호는 최소 6자리 이상만 가능합니다.",
    });
  if (userPw !== confirmPw)
    return res.status(401).json({
      errorMessage: "비밀번호와 확인이 일치하지 않습니다.",
    });

  const hashedPw = await bcrypt.hash(userPw, 10);
  const user = await prisma.users.create({
    data: { userId, userPw: hashedPw, userName },
  });

  return res.status(201).json({
    data: {
      userNo: user.userNo,
      userId: user.userId,
      userName: user.userName,
    },
  });
});

2. 로그인 API

요구조건

  • 아이디, 비밀번호로 로그인 요청
  • 계정정보 불일치 시 Status Code 및 메시지 반환(아이디 존재하지 않는 경우, 비밀번호 틀린 경우)
  • 로그인 성공 시 액세스 토큰 반환( 페이로드에 계정 ID 삽입 )

요청

{
  "userId": "your_Id",
  "userPw": "your_Password",
}

응답

  • 성공(200)
{ message: "로그인 성공, 헤더에 토큰값이 반환되었습니다." }
  • 실패(400)
{errorMessage: "없는 아이디 입니다."}
  • 실패(401)
{errorMessage: "틀린 비밀번호 입니다."}

API CODE

router.post("/sign-in", async (req, res, next) => {
  const { userId, userPw } = req.body;
  const isUser = await prisma.users.findFirst({
    where: { userId },
  });
  if (!isUser)
    return res.status(400).json({
      errorMessage: "없는 아이디 입니다.",
    });
  if (!(await bcrypt.compare(userPw, isUser.userPw)))
    return res.status(401).json({
      errorMessage: "틀린 비밀번호 입니다.",
    });
  const token = jwt.sign({ userId: userId }, SECRET_CODE);
  res.setHeader("Authorization", `Bearer ${token}`);
  return res
    .status(200)
    .json({ message: "로그인 성공, 헤더에 토큰값이 반환되었습니다." });
});

3. 캐릭터 생성 API (JWT 인증)

요구조건

  • 캐릭터 명 request 전달, 캐릭터 ID response 반환
  • 캐릭터 스탯 ( health:500, power:100, money:10000 )

요청

Authorization: Bearer <your_token>
{
	"characterName" : "your_characterName"
}

응답

  • 성공(201)
{
	"characterNo : your_created_characterNo"
}
  • 실패(409)
{ message: "이미 있는 캐릭터명입니다. " }

API CODE

router.post("/character", authMiddleware, async (req, res, next) => {
  const { characterName } = req.body;
  const { userNo } = req.user;
  console.log(userNo);
  const isCharacter = await prisma.characters.findFirst({
    where: { characterName },
  });
  if (isCharacter)
    return res.status(409).json({ message: "이미 있는 캐릭터명입니다. " });

  const character = await prisma.characters.create({
    data: {
      characterName,
      userNo,
      inventory: {
        create: {
          items: JSON.stringify([]),
        },
      },
      equip: {
        create: {
          items: JSON.stringify([]),
        },
      },
    },
  });

  const characterNo = character.characterNo;
  return res.status(201).json({
    data: { characterNo },
  });
});

4. 캐릭터 삭제 API (JWT 인증)

요구조건

  • 삭제할 캐릭터 ID params로 전달
  • 내 계정의 캐릭터가 아니면 삭제 불가

요청

GET /characters/delete/:characterId
Authorization: Bearer <your_token>

응답

  • 성공(200)
{ data: { deleteCharacter } }
  • 실패(401)
{ message: "계정 주인이 아닙니다." }
  • 실패(404)
{ message: "삭제하려는 계정이 없습니다. " }

API CODE

router.delete(
  "/character/delete/:characterNo",
  authMiddleware,
  async (req, res, next) => {
    const { characterNo } = req.params;
    const { userNo } = req.user;
    const character = await prisma.characters.findFirst({
      where: { characterNo: +characterNo },
    });
    if (!character)
      return res.status(404).json({ message: "삭제하려는 계정이 없습니다. " });

    if (character.userNo !== userNo)
      return res.status(401).json({ message: "계정 주인이 아닙니다." });

    const deleteCharacter = await prisma.characters.delete({
      where: { characterNo: +characterNo },
    });

    return res.status(200).json({ data: { deleteCharacter } });
  }
);

5. 캐릭터 상세 조회 API

요구조건

  • 조회할 캐릭터 ID params로 전달
  • 캐릭터 이름, HP, 힘 스탯 전달
  • 내 캐릭터 조회시 게임머니까지 조회
  • 다른 유저가 내 캐릭을 조회할 때와 내가 보유한 캐릭을 조회할 때가 달라야한다는 점.

요청

GET /characters/info/:characterId

응답

  • 성공(200)
// 본인의 캐릭터일 때
{
        data: {
          characterName: character.characterName,
          money: character.money,
          health: character.health,
          power: character.power,
        },
      }
// 본인의 캐릭터가 아닐 때
{
        data: {
          characterName: character.characterName,
          health: character.health,
          power: character.power,
        },
      }
  • 실패(404)
{ message: "삭제하려는 계정이 없습니다. " }

API CODE

router.get(
  "/character/info/:characterNo",
  authMiddleware,
  async (req, res, next) => {
    const { characterNo } = req.params;
    const { userNo } = req.user;
    const character = await prisma.characters.findFirst({
      where: { characterNo: +characterNo },
    });
    if (!character)
      return res.status(404).json({ message: "삭제하려는 계정이 없습니다. " });

    if (character.userNo === userNo) {
      return res.status(200).json({
        data: {
          characterName: character.characterName,
          money: character.money,
          health: character.health,
          power: character.power,
        },
      });
    } else {
      return res.status(200).json({
        data: {
          characterName: character.characterName,
          health: character.health,
          power: character.power,
        },
      });
    }
  }
);

6. 아이템 생성 API

요구조건

  • 아이템 코드, 아이템 명, 아이템 능력, 아이템 가격 request.body 전달
  • 아이템 능력 JSON 포맷 전달

요청

{
	"itemNo" : your_itemNo,
    "itemName" : "your_itemName",
    "itemPrice" : "your_itemPrice",
    "itemStat" : "your_itemStat",
}

응답

  • 성공(201)
{ data: item }
  • 실패(409)
{ message: "이미 있는 아이템 넘버입니다." }

API CODE

router.post("/item", async (req, res, next) => {
  const { itemNo, itemName, itemStat, itemPrice } = req.body;
  const isItem = await prisma.items.findFirst({
    where: { itemNo },
  });
  if (isItem)
    return res.status(409).json({ message: "이미 있는 아이템 넘버입니다." });

  const item = await prisma.items.create({
    data: {
      itemNo,
      itemName,
      itemPrice,
      itemStat,
    },
  });

  return res.status(201).json({ data: item });
});

7. 아이템 수정 API

요구조건

  • 아이템 코드 params 전달
  • 아이템 명, 아이템 능력 request 전달

요청

PATCH /updateItem/:itemNo
{
	"itemName" : "change_itemName",
    "itemStat" : {
    	wanted_stat_info
    }
}

응답

  • 성공(200)
{ data: updateItem }
  • 실패(404)
{ message: "없는 아이템입니다." }

API CODE

router.patch("/updateItem/:itemNo", async (req, res, next) => {
  const { itemNo } = req.params;
  const { itemName, itemStat } = req.body;

  const Item = await prisma.items.findFirst({
    where: { itemNo: +itemNo },
  });

  if (!Item) return res.status(404).json({ message: "없는 아이템입니다." });

  const updateItem = await prisma.items.update({
    where: { itemNo: +itemNo },
    data: {
      itemName,
      itemStat,
    },
  });

  return res.status(200).json({ data: updateItem });
});

8. 아이템 목록 API

요구조건

  • 아이템 코드, 아이템 명, 아이템 가격 내용만 조회
  • 아이템 생성 API를 통해 생성된 모든 아이템들이 목록으로 조회

요청

NULL

응답

  • 성공(200)
{ data: items }
  • 실패(404)
{ message: "등록된 아이템이 없습니다." }

API CODE

router.get("/item", async (req, res, next) => {
  const items = await prisma.items.findMany();
  if (!items)
    return res.status(404).json({ message: "등록된 아이템이 없습니다." });

  return res.status(200).json({ data: items });
});

9. 아이템 상세 조회 API

요구조건

  • 아이템 코드를 params 로 전달받아 아이템 코드, 아이템 명, 아이템 능력, 아이템 가격 조회

요청

GET /characters/:characterId

응답

  • 성공(200)
{ data: items }
  • 실패(404)
{ message: "등록된 아이템이 없습니다." }

API CODE

router.get("/item/:itemNo", async (req, res, next) => {
  const { itemNo } = req.params;
  const items = await prisma.items.findFirst({
    where: { itemNo: +itemNo },
  });
  if (!items)
    return res.status(404).json({ message: "등록된 아이템이 없습니다." });

  return res.status(200).json({ data: items });
});
profile
하루 최소 1시간이라도 공부하자..

0개의 댓글