이번 주는 Express.js로 웹 서버를 구축하며 다음과 같은 주요 사항을 진행했다.
주요 진행 사항
Express 서버 설정:

express와 dotenv를 사용하여 서버를 설정하고 환경 변수를 관리했다.
기본 포트를 3000으로 설정하고 서버를 실행했다.
const app = express();
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`서버가 ${PORT} 포트에서 열렸습니다.`);
});
라우터 연결:

여러 라우터(signup_router, item_router, character_router)를 /api 경로에 연결하여 기능을 모듈화 했다.
app.use("/api", [goodsRouter, ItemRouter, characterRouter]);
미들웨어 사용:

요청 로그를 기록하는 LogMiddleware와 에러를 처리하는 ErrorHandlingMiddleware를 추가했다.
JSON 및 URL 인코딩 된 데이터를 처리할 수 있도록 설정했다.
app.use(LogMiddleware);
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
주요 API 기능
회원가입 API (/signup):



사용자 이름, 비밀번호, 이름, 나이, 성별을 받아 회원가입을 처리한다.
아이디는 영어 소문자와 숫자만 허용하며, 비밀번호는 최소 6자리 이상이어야 한다.
아이디 중복 체크 후, 비밀번호를 해싱하여 데이터베이스에 사용자와 캐릭터 정보를 저장한다.
router.post("/signup", async (req, res, next) => {
// 유효성 검사 및 중복 체크
// 비밀번호 해싱 및 DB 저장
});
로그인 API (/signin):


사용자 이름과 비밀번호를 받아 로그인 과정을 처리한다.
사용자 인증에 성공하면 JWT 토큰을 생성하고, 쿠키에 저장한다.
로그인 API (/signin):
사용자 이름과 비밀번호를 받아 로그인 과정을 처리한다.
사용자 인증에 성공하면 JWT 토큰을 생성하고, 쿠키에 저장한다.
사용자 정보 수정 API (/users):
인증된 사용자가 자신의 정보를 수정할 수 있도록 한다.
기존 정보를 확인하고, 변경 사항을 기록하여 사용자 이력을 저장한다.
router.patch("/users", authMiddleware, async (req, res, next) => {
// 사용자 정보 수정 및 이력 기록
});
아이템 생성 API (/items):


인증된 사용자가 아이템을 생성할 수 있다.
아이템 이름은 필수이며, 체력, 공격력, 가격은 숫자로 검증된다.
아이템 생성 후, 성공적인 응답을 반환한다.
router.post("/items", authMiddleware, async (req, res) => {
const { userId } = req.user;
const { name, health, strength, price } = req.body;
if (!name) {
return res.status(400).json({ message: "아이템 이름은 필수입니다." });
}
// 유효성 검사
let validatedHealth = typeof health === "number" ? health : 0;
let validatedStrength = typeof strength === "number" ? strength : 0;
let validatedPrice = typeof price === "number" ? price : 0;
try {
const item = await prisma.items.create({
data: { userId: +userId, name, health: validatedHealth, strength: validatedStrength, price: validatedPrice },
});
return res.status(201).json({ data: item });
} catch (error) {
console.error(error);
next(error);
}
});
아이템 목록 조회 API (/items):

모든 아이템을 최신순으로 조회할 수 있다.
성공적인 조회 후, 아이템 데이터를 반환한다.
router.get("/items", async (req, res) => {
try {
const items = await prisma.items.findMany({
select: { ItemId: true, name: true, price: true },
orderBy: { createdAt: "desc" },
});
return res.status(200).json({ data: items });
} catch (error) {
console.error(error);
return res.status(500).json({ message: "서버 오류가 발생했습니다." });
}
});
아이템 상세 조회 API (/items/:id):

특정 아이템의 상세 정보를 조회할 수 있다.
아이템이 존재하지 않을 경우, 404 오류를 반환한다.
router.get("/items/:id", async (req, res) => {
try {
const itemId = parseInt(req.params.id);
const item = await prisma.items.findFirst({ where: { ItemId: itemId } });
if (!item) {
return res.status(404).json({ message: "아이템을 찾을 수 없습니다." });
}
return res.status(200).json({ data: item });
} catch (error) {
console.error(error);
return res.status(500).json({ message: "서버 오류가 발생했습니다." });
}
});
아이템 수정 API (/items/:id):


인증된 사용자가 자신의 아이템 정보를 수정할 수 있다.
수정할 필드가 없을 경우, 400 오류를 반환한다.
아이템이 존재하지 않거나 사용자의 것이 아닐 경우, 403 오류를 반환한다.
router.patch("/items/:id", authMiddleware, async (req, res) => {
const itemId = parseInt(req.params.id);
const { item_name, item_stat } = req.body;
const { userId } = req.user;
if (!item_name && !item_stat) {
return res.status(400).json({ message: "수정할 필드가 필요합니다." });
}
try {
const item = await prisma.items.findUnique({ where: { ItemId: itemId } });
if (!item || item.userId !== userId) {
return res.status(403).json({ message: "권한이 없거나 아이템이 존재하지 않습니다." });
}
const updatedItem = await prisma.items.update({
where: { ItemId: itemId },
data: {
name: item_name || item.name,
health: item_stat?.health !== undefined ? item_stat.health : item.health,
strength: item_stat?.strength !== undefined ? item_stat.strength : item.strength,
},
});
return res.status(200).json({ message: "아이템이 수정되었습니다.", data: updatedItem });
} catch (error) {
console.error(error);
return res.status(500).json({ message: "서버 오류가 발생했습니다." });
}
});
캐릭터 구현 api는 아이템과 거의 유사해서 따로 추가는 안 하겠다.
번 주는 Express.js를 활용하여 사용자 인증 및 아이템 관리 API를 구현하며 다음과 같은 주요한 깨달음을 얻었다.
API 설계의 중요성: 각 API의 기능을 명확하게 정의하고, 사용자의 요구에 맞게 설계하는 것이 중요함을 깨달았다. 이를 통해 코드의 가독성을 높이고, 유지보수가 용이한 구조를 만들 수 있었다.
보안 강화: 인증 미들웨어와 비밀번호 해싱을 통해 사용자의 데이터를 안전하게 보호하는 방법을 배웠다. 보안은 API 개발에서 필수적인 요소임을 깊이 이해하게 되었다.
문제 해결 능력 향상: 실제로 API를 구현하면서 발생한 다양한 오류를 해결하는 과정에서 문제 해결 능력이 향상되었다. 직접 부딪히고 경험하는 것이 실력 향상에 큰 도움이 된다는 것을 느꼈다.
이번 주의 경험은 향후 프로젝트에 큰 밑거름이 될 것이며, 더 나은 개발자로 성장하는 데 기여하고 싶다.
이번주도 고생했고 다음 주에도 힘내자!