여러번 회의를 통해 ERD도 여러번 수정하고 DB의 컬럼이나 제약조건도 수정하면서 진행하고 있습니다.
여러번 고뇌를 겪고 하니 DB를 제대로 설계하는 것이 중요하다고 느껴집니다. 로직에 맞고 기획에 맞게 db를 설계하는 것이 많이 까다롭더라구요. 하지만 점점 경험을 하다보면 익숙해질거라고 생각이 듭니다.
저희 팀의 방식은 한 API마다 여러 사람이 같이 동시 개발을 하여 메인으로 개발하는 사람을 정하고, 서브로 그때 그때 구현하면서 막히는 부분에 대해 같이 고민하면서 도와줄 사람을 정하여 과제 제출 기한에 맡게 구현하기 위해 이렇게 진행하였습니다.
자 그럼 이제 본격적인 내용을 작성해 보겠습니다. 이번에 저는 팀관련 API를 메인으로 맡아서 해보았습니다.
팀관련 API 종류
저희가 기획하기에 필요한 팀관련 API는 위에 3가지 API입니다.
저는 오늘까지 팀 목록 조회 API랑 선수 선발 등록 API를 구현하였습니다. 중간 중간 서브로 도와준 팀원분의 도움으로 API를 구현할 수 있었습니다.
팀 선수 목록 조회 API
router.get("/team/:teamId", async (req, res, next) => {
try {
const { teamId } = req.params;
const team = await userPrisma.teams.findFirst({
select: {
userPlayerId1: true,
userPlayerId2: true,
userPlayerId3: true,
},
where: {
teamId: +teamId,
},
});
if (!team) throw new NotFoundError("해당 팀이 존재하지 않습니다.");
// userPlyaerId에서 playerId 찾기
const playerIds = [];
for (const userPlayerId in team) {
if (team[userPlayerId]) {
const playerId = await userPrisma.userPlayers.findFirst({
select: { playerId: true },
where: { userPlayerId: team[userPlayerId] },
});
playerIds.push(playerId.playerId);
}
}
// 구한 playerId를 이용해 player 구하기
const resultMessage = [];
for (const playerId of playerIds) {
const player = await gamePrisma.players.findFirst({
select: {
playerId: true,
name: true,
position: true,
speed: true,
decision: true,
power: true,
defense: true,
stamina: true,
tierId: true,
},
where: { playerId: playerId },
});
if (!player) throw new NotFoundError("선수정보가 존재하지 않습니다.");
resultMessage.push(player);
}
return res.status(200).json({ Team: resultMessage });
} catch (err) {
next(err);
}
});
선수 선발 등록 API
router.post("/team/:teamId/:userId", async (req, res, next) => {
try {
const { userId } = req.params;
const { teamId } = req.params;
const { userPlayerId, teamPlayerNumber } = req.body;
// userPlayerId는 유저가 가지고 있는 선수 등록할 userPlayerId를 요청받습니다.
// teamPlayerNumber는 team컬럼 중 userPlayerId1, userPlayerId2, userPlayerId3 등 어느 위치(실제 축구라면 포지션)에 등록할 것인지를 요청받습니다.
const userPlayer = await userPrisma.userPlayers.findFirst({
where: {
userPlayerId: userPlayerId,
},
});
if (!userPlayer)
throw new NotFoundError("현재 소유하고 있는 선수가 아닙니다.");
if (+userId !== userPlayer.userId)
throw new ConflictError("현재 계정의 선수가 아닙니다.");
const player = await gamePrisma.players.findFirst({
where: { playerId: userPlayer.playerId },
});
if (!player) throw new NotFoundError("해당 선수 정보가 없습니다.");
let team = await userPrisma.teams.findFirst({
where: {
teamId: +teamId,
},
});
if (team && +userId !== team.userId)
throw new ConflictError("현재 계정의 팀이 아닙니다.");
// 해당 userPlayerId 선수가 이미 팀에 존재하고 선발 위치만을 변경해 주기위한 코드들입니다. 그리고 선발할 위치에 다른 선수가 있으면 다른 선수의 userPlayerId를 서로 위치를 변경하기 위해 작성해 보았습니다.
let originUserPlayerNumber = null; // 선발할려던 userPlayerid가 이미 존재하여 그 해당 위치를 알기위해 사용합니다. 그래야 선발할 위치에 있던 다른 선수의 userPlayerId를 넣어주기 위해서 입니다.
let originUserPlayerId = null; // 선발할 위치에 있던 다른 선수의 userPlayerId를 가집니다.
// 선발할려는 userPlayerId가 이미 팀에 있으면
if (
(team && userPlayerId === team.userPlayerId1) ||
(team && userPlayerId === team.userPlayerId2) ||
(team && userPlayerId === team.userPlayerId3)
) {
// 이미 존재어딘가에 존재하는 userPlayerId의 위치를 찾아서 지정합니다.
if (userPlayerId === team.userPlayerId1) originUserPlayerNumber = 1;
if (userPlayerId === team.userPlayerId2) originUserPlayerNumber = 2;
if (userPlayerId === team.userPlayerId3) originUserPlayerNumber = 3;
console.log("userPlayer원래 있던 위치 : " + originUserPlayerNumber);
// 해당 선발할려는 위치에 이미 다른 선수가 존재하면 그 다른 선수의 userPlayerId를 가져옵니다.
if (team.userPlayerId1 && teamPlayerNumber === 1)
originUserPlayerId = team.userPlayerId1;
if (team.userPlayerId2 && teamPlayerNumber === 2)
originUserPlayerId = team.userPlayerId2;
if (team.userPlayerId3 && teamPlayerNumber === 3)
originUserPlayerId = team.userPlayerId3;
console.log(
"선발할려는 위치에 있는 다른 선수 userPlayerId : " + originUserPlayerId,
);
// 다른 선수의 위치를 원래 선발할려는 선수의 위치로 변경해 줍니다.
if (originUserPlayerNumber === 1) {
await userPrisma.teams.update({
data: {
userPlayerId1: originUserPlayerId,
},
where: { teamId: +teamId },
});
} else if (originUserPlayerNumber === 2) {
await userPrisma.teams.update({
data: {
userPlayerId2: originUserPlayerId,
},
where: { teamId: +teamId },
});
} else if (originUserPlayerNumber === 3) {
await userPrisma.teams.update({
data: {
userPlayerId3: originUserPlayerId,
},
where: { teamId: +teamId },
});
}
}
// 해당 팀이 있으면 해당 자리에 유저 선발 등록
if (team) {
if (teamPlayerNumber === 1) {
await userPrisma.teams.update({
data: {
userPlayerId1: userPlayerId,
},
where: { teamId: +teamId },
});
} else if (teamPlayerNumber === 2) {
await userPrisma.teams.update({
data: {
userPlayerId2: userPlayerId,
},
where: { teamId: +teamId },
});
} else if (teamPlayerNumber === 3) {
await userPrisma.teams.update({
data: {
userPlayerId3: userPlayerId,
},
where: { teamId: +teamId },
});
} else {
throw new BadRequestError("해당 한 팀의 엔트리는 1,2,3번만 있습니다.");
}
} else {
// 한 계정 당 3개의 팀만을 가집니다.
const isTeamCountCheck = await userPrisma.teams.findMany({
where: {
userId: +userId,
},
});
if (Object.keys(isTeamCountCheck).length >= 3)
return res.status(400).json({
message: "이미 3개의 팀을 가지고 있습니다.",
yourTeamId1: isTeamCountCheck[0].teamId,
yourTeamId2: isTeamCountCheck[1].teamId,
yourTeamId3: isTeamCountCheck[2].teamId,
});
// 팀이 없으면 새로 팀을 생성하고 선발할 선수를 해당 자리에 등록합니다.
if (teamPlayerNumber === 1) {
team = await userPrisma.teams.create({
data: {
userId: +userId,
userPlayerId1: userPlayerId,
},
});
} else if (teamPlayerNumber === 2) {
team = await userPrisma.teams.create({
data: {
userId: +userId,
userPlayerId2: userPlayerId,
},
});
} else if (teamPlayerNumber === 3) {
team = await userPrisma.teams.create({
data: {
userId: +userId,
userPlayerId3: userPlayerId,
},
});
} else {
throw new BadRequestError("해당 한 팀의 엔트리는 1,2,3번만 있습니다.");
}
}
return res.status(201).json({
message: `${player.name} 선수를 teamid : ${team.teamId}번 팀에 등록했습니다.`,
});
} catch (err) {
next(err);
}
});
선수 선발 부분은 다소 코드가 길어 난잡할 수 있어 팀원분들이 조금이라도 이해하기 쉽게 주석을 디테일하게 적어보았습니다.
하 알수 없었던 에러도 여러번나면서 우여곡절 끝에 그나마 원하던 구현기능을 완성할 수 있었습니다. 저희가 만든 API명세서와 테이블 모델링을 보면서 어떻게 API로직을 작성할까 많은 고민을 하면서 했던거 같습니다. 그리고 확실히 팀원분들과 같이 하니 몰랐던 부분들에 대해서도 알게되고 깃 허브의 여러 사용법이나, 여러 에러가 나는 이유등에 대해 도움을 많이 받았습니다. 그리고 제 코드를 보고 수정하면 좋은 부분들을 알려주니 좀 더 완성된 API를 만들 수 있었습니다. 굿 이번 프로젝트를 통해 많은것들을 얻어갈 것 같습니다.
그럼 오늘도 화이팅