오늘은 Express.js와 Prisma를 이용해 RESTful API를 구축하는 작업을 진행했다. CRUD(Create, Read, Update, Delete) 작업을 API로 구현하면서 Prisma의 다양한 쿼리 메서드를 활용했다.
특히, 아이템 생성 API를 만들면서 요청 본문에서 데이터를 추출하고, 유효성 검사를 진행했다. 아이템 이름이 필수라는 점을 체크하고, 체력, 공격력, 가격이 각각 숫자인지 확인하여 기본값을 설정하는 로직을 구현했다.
// 아이템 생성 API
router.post("/items", authMiddleware, async (req, res) => {
const { userId } = req.user; // 인증된 사용자 ID
const { name, health, strength, price } = req.body; // 요청 본문에서 데이터 추출
// 유효성 검사
if (!name) {
return res.status(400).json({ message: "아이템 이름은 필수입니다." });
}
try {
const item = await prisma.items.create({
data: {
userId,
name,
health: health || 0,
strength: strength || 0,
price: price || 0,
},
});
return res.status(201).json({ data: item });
} catch (error) {
console.error(error);
return res.status(500).json({ message: "서버 오류가 발생했습니다." });
}
});
또한, 사용자 정보 수정 API를 통해 수정할 수 있는 필드를 유효성 검사했다. 업데이트할 필드가 없으면 에러 메시지를 반환하도록 하여 사용자 경험을 개선했다.
// 사용자 정보 수정 API
router.patch("/users", authMiddleware, async (req, res) => {
const updatedData = req.body;
const { userId } = req.user;
if (!updatedData.name && !updatedData.age) {
return res.status(400).json({ message: "수정할 필드가 필요합니다." });
}
try {
const updatedUser = await prisma.users.update({
where: { userId },
data: updatedData,
});
return res.status(200).json({ data: updatedUser });
} catch (error) {
console.error(error);
return res.status(500).json({ message: "서버 오류가 발생했습니다." });
}
});
회원가입 시 트랜잭션을 사용하여 사용자와 관련된 캐릭터 정보를 동시에 생성하는 방법도 익혔다. 이를 통해 데이터의 일관성을 유지하는 것이 얼마나 중요한지 깨달았다.
// 사용자 회원가입 API
const [user, character] = await prisma.$transaction(async (tx) => {
const user = await tx.users.create({
data: { username, password: hashedPassword },
});
const character = await tx.characterinformations.create({
data: { userId: user.userId, name, age, gender: gender.toUpperCase() },
});
return [user, character];
});
에러 핸들링에 대한 부분도 강화했다. API에서 발생하는 다양한 오류를 처리하고, 클라이언트에게 적절한 오류 메시지를 반환하여 문제를 이해할 수 있도록 도왔다.
// 캐릭터 삭제 API
try {
const character = await prisma.character.delete({
where: { characterId: +characterId },
});
return res.status(200).json({ message: "정상적으로 삭제되었습니다!" });
} catch (err) {
if (err.code === "P2025") {
return res.status(404).json({ message: "존재하지 않는 아이디입니다." });
}
console.error(err);
return res.status(500).json({ message: "캐릭터 삭제 중 오류가 발생했습니다." });
}
마지막으로, JWT를 사용한 사용자 인증과 권한 부여를 구현했다. 이를 통해 사용자 정보를 안전하게 보호하고, 인증된 사용자만 특정 API에 접근할 수 있도록 설정했다.
// 사용자 로그인 API
const token = jwt.sign({ userId: user.userId }, "custom-secret-key", {
expiresIn: "1h",
});
res.cookie("authorization", `bearer ${token}`, {
httpOnly: true,
secure: true,
maxAge: 3600000, // 1시간
});
앞으로는 더 많은 기능을 추가하고, 현재 시스템을 개선할 계획이다. 힘들었지만, 실제로 적용해보면서 깊이 있는 이해를 할 수 있었다.
오늘 하루도 잘 버텼고 내일 하루도 힘내보자!