1:N 관계 등록 API

윤태규·2024년 1월 5일
  1. 게시글 API

💡 게시글 생성 API 비즈니스 로직

  1. 게시글을 작성하려는 클라이언트가 로그인된 사용자인지 검증합니다.
  2. 게시글 생성을 위한 title, contentbody로 전달받습니다.
  3. Posts 테이블에 게시글을 생성합니다.

PostsRouter를 등록한 app.js
// src/app.js

import express from 'express';
import cookieParser from 'cookie-parser';
import LogMiddleware from './middlewares/log.middleware.js';
import ErrorHandlingMiddleware from './middlewares/error-handling.middleware.js';
import UsersRouter from './routes/users.router.js';
import PostsRouter from './routes/posts.router.js';

const app = express();
const PORT = 3018;

app.use(LogMiddleware);
app.use(express.json());
app.use(cookieParser());
app.use('/api', [UsersRouter, PostsRouter]);
app.use(ErrorHandlingMiddleware);

app.listen(PORT, () => {
console.log(PORT, '포트로 서버가 열렸어요!');
});

게시글 생성 API
// src/routes/posts.router.js

import express from 'express';
import { prisma } from '../utils/prisma/index.js';
import authMiddleware from '../middlewares/auth.middleware.js';

const router = express.Router();

/ 게시글 생성 API /
router.post('/posts', authMiddleware, async (req, res, next) => {
const { userId } = req.user;
const { title, content } = req.body;

const post = await prisma.posts.create({
data: {
UserId: userId,
title,
content,
},
});

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

export default router;

2) 게시글 조회 API

게시글 목록 조회 API
// src/routes/posts.router.js

/ 게시글 목록 조회 API /
router.get('/posts', async (req, res, next) => {
const posts = await prisma.posts.findMany({
select: {
postId: true,
title: true,
createdAt: true,
updatedAt: true,
},
orderBy: {
createdAt: 'desc', // 게시글을 최신순으로 정렬합니다.
},
});

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

게시글 상세 조회 API
// src/routes/posts.router.js

/ 게시글 상세 조회 API /
router.get('/posts/:postId', async (req, res, next) => {
const { postId } = req.params;
const post = await prisma.posts.findFirst({
where: {
postId: +postId,
},
select: {
postId: true,
title: true,
content: true,
createdAt: true,
updatedAt: true,
},
});

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

  1. 댓글 API
  • 댓글 API에 대한 고찰

👉 댓글 기능은 게시글 기능과 부모-자식 간의 관계로 구성됩니다.

일반적인 사이트를 생각해보더라도, 게시글과 별도로 댓글이 존재하는 사이트는 많이 존재하지 않을 것 입니다. 이는 댓글이 그 자체로 독립적으로 존재하기보다는 특정 게시글에 대한 하위 개념으로 존재하기 떄문입니다.

그렇기 때문에, 댓글 기능을 구현하기 위해서는 거의 필수적으로 게시글이 필요하게 될 것입니다. 댓글은 특히 게시글에 종속되므로, 댓글 API는 게시글 API의 하위에 구현되어야 합니다.

즉, 댓글 API의 URL은 게시글 API의 URL을 기반으로 작성되어야 합니다. 예를 들어, 댓글을 생성하는 API의 경우 POST /api/posts/**:postId**/comments와 같이 작성할 수 있습니다. 이렇게 작성하면, URL만 보더라도 특정 게시글 내부에 댓글을 작성하겠다.라는 것을 명확하게 이해할 수 있을 것입니다.

댓글 생성 API

💡 댓글 생성 API 비즈니스 로직

  1. 댓글을 작성하려는 클라이언트가 로그인된 사용자인지 검증합니다.
  2. 게시물을 특정하기 위한 postIdPath Parameters로 전달받습니다.
  3. 댓글 생성을 위한 contentbody로 전달받습니다.
  4. Comments 테이블에 댓글을 생성합니다.

CommentsRouter를 등록한 app.js
// src/app.js

import express from 'express';
import cookieParser from 'cookie-parser';
import LogMiddleware from './middlewares/log.middleware.js';
import ErrorHandlingMiddleware from './middlewares/error-handling.middleware.js';
import UsersRouter from './routes/users.router.js';
import PostsRouter from './routes/posts.router.js';
import CommentsRouter from './routes/comments.router.js';

const app = express();
const PORT = 3018;

app.use(LogMiddleware);
app.use(express.json());
app.use(cookieParser());
app.use('/api', [UsersRouter, PostsRouter, CommentsRouter]);
app.use(ErrorHandlingMiddleware);

app.listen(PORT, () => {
console.log(PORT, '포트로 서버가 열렸어요!');
});

댓글 생성 API
// src/routes/comments.router.js

import express from 'express';
import authMiddleware from '../middlewares/auth.middleware.js';
import { prisma } from '../utils/prisma/index.js';

const router = express.Router();

/ 댓글 생성 API /
router.post(
'/posts/:postId/comments',
authMiddleware,
async (req, res, next) => {
const { postId } = req.params;
const { userId } = req.user;
const { content } = req.body;

const post = await prisma.posts.findFirst({
  where: {
    postId: +postId,
  },
});
if (!post)
  return res.status(404).json({ message: '게시글이 존재하지 않습니다.' });

const comment = await prisma.comments.create({
  data: {
    UserId: +userId, // 댓글 작성자 ID
    PostId: +postId, // 댓글 작성 게시글 ID
    content: content,
  },
});

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

},
);

export default router;

댓글 조회 API
// src/routes/comments.router.js

/ 댓글 조회 API /
router.get('/posts/:postId/comments', async (req, res, next) => {
const { postId } = req.params;

const post = await prisma.posts.findFirst({
where: {
postId: +postId,
},
});
if (!post)
return res.status(404).json({ message: '게시글이 존재하지 않습니다.' });

const comments = await prisma.comments.findMany({
where: {
PostId: +postId,
},
orderBy: {
createdAt: 'desc',
},
});

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

  • 역할과 책임 보통 커뮤니티 사이트에서는 하나의 게시글과 해당 게시글에 달린 댓글들을 함께 보여줍니다. 이를 구현하는 방법에는 크게 두 가지의 방법이 있습니다. 1️⃣ 게시글 상세 조회 API 내부에서 댓글 목록도 함께 반환한다. 2️⃣ 게시글 조회 API댓글 조회 API를 따로 호출하여, 각 정보를 가져온다. 이 두 가지 방법 모두 장단점이 존재하는데요. 1️⃣ 방법의 경우, 한 번의 API 호출로 모든 정보를 가져올 수 있으므로 효율적일 수 있습니다. 다만, 이 방법은 게시글과 댓글이라는 서로 다른 도메인하나의 API에서 처리되어야 하므로, 코드가 복잡해질 수 있습니다. 반면에, 2️⃣ 방법은 게시글과 댓글이라는 서로 다른 도메인의 데이터를 각각의 API에서 처리하므로, 코드는 간결하고 관리하기 쉬워집니다. 그러나, 이 방법은 프론트엔드에서 두 번의 API 호출이 필요하므로, 응답 시간이 길어질 수 있습니다.

💪 ‘역할과 책임’에 대한 이야기는 프로그래밍을 하면서 자주 나오는 주제입니다.

하나의 코드가 많은 역할과 책임을 가질 때 발생하는 문제와 하나의 코드가 단 하나의 역할과 책임가질 때의 장점에 대한 고민은 많은 개발자들이 아직까지도 고민하고 풀고자하는 문제 중 하나입니다.

이러한 고민을 돕기 위해 “클린 코드(Clean Code)”와 리팩토링(Refactoring)이라는 책이 오랜시간 사랑받아 왔고, 아직까지도 많은 인기를 가지고 있습니다.

profile
끝까지 가자

0개의 댓글