Skip to content

Conversation

@Jin-coding-333
Copy link
Collaborator

📋 스프린트 미션 요구사항

요구사항

기본 요구사항

공통

  • Github에 위클리 미션 PR을 만들어 주세요.
  • React.js 혹은 Next.js를 사용해 진행합니다.
  • RESTful를 설계하고 백엔드 코드를 변경하세요.
    • (풀스택) 설계한 백엔드 코드에 맞게 프론트엔드 코드를 변경해 주세요.
    • (백엔드) 프론트엔드 코드에 맞게 백엔드 코드를 변경해 주세요.
  • 백엔드 코드에 Swagger를 추가해 API 명세 문서를 생성해 주세요.

백엔드 구현 요구사항

상품 등록

  • "상품 등록하기" 버튼 클릭 시, 상품 정보 등록 API 엔드포인트에 요청을 보내 상품을 등록합니다.
  • 상품 등록 시 필요한 필드(이름, 설명, 가격 등)의 유효성을 검증하는 미들웨어를 구현합니다.
  • Multer 미들웨어를 사용하여 이미지 업로드 API를 구현해 주세요.
    • 업로드된 이미지는 서버에 저장하고, 해당 이미지의 경로를 response 객체에 포함해 반환합니다.

상품 상세

  • 상품을 조회할 때, 해당 상품에 대한 댓글 리스트와 사용자가 '좋아요'를 눌렀는지 여부를 확인할 수 있도록 응답 객체에 포함시켜 반환해 주세요.

좋아요 기능

  • '좋아요' API를 만들어 주세요.
    • 사용자는 상품 또는 게시글에 '좋아요'를 할 수 있습니다.
    • $transaction을 사용해 주세요.
  • '좋아요' 취소 API를 만들어 주세요.
    • 사용자는 상품 또는 게시글에 '좋아요'를 취소할 수 있습니다.
    • $transaction을 사용해 주세요.
  • 상품 또는 게시글을 조회할 때, 사용자가 '좋아요'를 누른 항목인지 확인할 수 있도록 isLiked 필드를 응답 객체에 포함시켜 반환해 주세요.

에러 처리

  • 모든 예외 상황을 처리할 수 있는 에러 핸들러 미들웨어를 구현합니다.
    • 서버 오류(500), 사용자 입력 오류(400 시리즈), 리소스 찾을 수 없음(404) 등 상황에 맞는 상태값을 반환합니다.

라우트 중복 제거

  • 중복되는 라우트 경로(예: /users에 대한 GET 및 POST 요청)를 app.route()로 통합해 중복을 제거합니다.
  • express.Router()를 활용하여 중고마켓/자유게시판 관련 라우트를 별도의 모듈로 구분합니다.

인증

  • User 스키마를 작성해 주세요.
    • id, email, nickname, image, encryptedPassword, createdAt, updatedAt 필드를 가집니다.
  • 회원가입 API를 만들어 주세요.
    • email, nickname, password를 입력하여 회원가입을 진행합니다.
    • password는 해싱해 저장합니다.
  • 로그인 API를 만들어 주세요.
    • 사용자의 신원을 확인하고, 성공적인 인증 후에는 액세스 토큰을 발급해 response 객체에 포함해 반환합니다.

기능별 인가 요구사항

상품 기능 인가

  • 로그인한 사용자만 상품을 등록할 수 있습니다.
  • 상품을 등록한 사용자만 해당 상품의 정보를 수정 및 삭제할 수 있습니다.
  • 로그인한 사용자만 상품에 '좋아요'를 추가하거나 삭제할 수 있습니다.

게시글 기능 인가

  • 로그인한 사용자만 게시글을 등록할 수 있습니다.
  • 게시글을 등록한 사용자만 해당 게시글 정보를 수정 및 삭제할 수 있습니다.
  • 로그인한 사용자만 게시글에 '좋아요'를 추가하거나 삭제할 수 있습니다.

댓글 기능 인가

  • 로그인한 사용자만 상품에 댓글을 등록할 수 있습니다.
  • 로그인한 사용자만 게시글에 댓글을 등록할 수 있습니다.
  • 댓글을 등록한 사용자만 댓글을 수정하거나 삭제할 수 있습니다.

심화 요구사항

상태코드 (웹 API 관련)

  • 프론트엔드에서는 서버 응답의 상태코드에 따라 적절한 사용자 피드백을 제공합니다.

인증

  • 토큰 기반 방식을 사용할 경우, 만료된 액세스 토큰을 새로 발급하는 리프레시 토큰 발급 기능을 구현합니다. (JWT Sliding Session 적용)

OAuth를 활용한 인증

  • 구글 OAuth를 사용하여 회원가입 및 로그인 기능을 구현합니다.

프로젝트 구조 변경

  • 프로젝트의 구조와 복잡성을 관리하기 위해 MVC 패턴이나 Layered Architecture와 같은 설계 방식을 적용해 보세요.

(생략 가능) 자유게시판 게시물 등록

  • 프론트엔드를 Next.js로 Migration 했을 경우에만 진행해 주세요.
  • 게시물 등록 시 이미지 등록 기능을 구현합니다.
    • 파일을 선택해 이미지를 업로드하고, Preview를 볼 수 있도록 구현합니다.
    • 이미지는 최대 3개까지만 등록 가능하도록 구현해 주세요.
  • 게시물 등록 시 필요한 필드(제목, 내용 등)의 유효성을 검증하는 미들웨어를 구현합니다.
  • Multer 미들웨어를 사용하여 이미지 업로드 API를 구현해 주세요.
    • 업로드된 이미지는 서버에 저장하고, 해당 이미지의 경로를 response 객체에 포함해 반환합니다.

Copy link
Collaborator

@kimjong95 kimjong95 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아래 작성해주신 다른 코드들도 남겨드린 코멘트와 같은 원리로 분리가 가능합니다.

현재는 로직이 복잡하지않고, 도메인도 복잡하지 않습니다. 하지만 코드를 분리해서 작성한다. == 코들을 모듈화한다 == 함수의 책임을 분리한다 와 같은 개념을 차차 고민해보셔야합니다.

실제로 서비스를 구성하는 복잡한 코드레벨에서는 적절한 분리가 가독성을 높혀주기도, 디버깅을 더 쉽게 하기도, 더 유연한 구조로 확장성을 제공하기도 합니다.

/** Products Routes **/

// 상품 목록 조회
app.get('/products', asyncHandler(async (req, res) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

express를 통한 api 라우트 구성부터 로직, db접근까지 하나의 함수와 하나의파일들로 구성해주신걸 확인할 수 있어요.

이러한 부분들은 아래 후술하는 방법처럼, 또한 제가이전에 한번 공유드린 것 처럼 layer를 분리해서 파일을 정리하고, 하나의 함수가 하나의 기능만 담당하도록 정리할 수 있습니다. 이러한 방법은 함수의 책임을 좁히고, 코드를 모듈화 하며, 레이어와 레이어사이에 인터페이스를 두고 하나의 레이어가 다른 스펙으로 변경되어도 불변성과 무결성을 유지할 수 있는 방법을 아키텍처레벨에서 제어할 수 있습니다.

app.get('/products', asyncHandler(async (req, res) => {
const { offset = 0, limit = 10, order = 'recent' } = req.query;
const offsetNum = parseInt(offset);
const limitNum = parseInt(limit);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  const { offset = 0, limit = 10, order = 'recent' } = req.query;
  const offsetNum = parseInt(offset);
  const limitNum = parseInt(limit);

위 코드들은 request로부터 가져온 파라미터들을 검증(validation)하는 단계를 거칩니다. 이러한 부분은 레이어 까지는 아니더라도 별도의 함수를 통해서 각 파라미터가 앞으로 사용될 스키마(도메인모델)에 어떤 타입에 매핑되는지 확인하며 타입 또는 값에대한 검증을 진행할 수 있습니다. 아래의 거의 모든 함수들이 이러한 과정을 거칠거에요.

그렇다면 이부분은 검증이라는 단계로써 함수로 따로 구성할 수 있고 그함수는 입력받은 값을 검증하는 즉 같은 입력에 같은 return을 낼 수 있는 순수함수로 구성될 수 있습니다.

orderBy,
skip: offsetNum, // skip으로 offset설정
take: limitNum, // take으로 limit설정
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

위 부분은 prisma(ORM혹은 다른형태의 DB일수도 있습니다.) db에 직접 접근하여 값을 가져오는 query단계로 볼 수 있습니다.
여기선 prisma 에 접근했지만, DB에 접근한다면 connection과 같은 값들을 추가로 제어해야 할 수도 있어요.

때문에 이부분은 store(다른 이름이여도 됩니다)에 관련된 레이어로 분리하여 처리할 수 있습니다. 그럼 여기서는 DB에 접근하는 코드들만 모여서 모듈화가 될 것이고, 앞으로 이 함수는 DB에 관련된 코드를 제어하는 책임으로 분리가 될 수 있습니다.
즉 이 함수에서는 DB와 관련된 로직만 작성한다. 라는 의미로 이해하실 수 있습니다.

take: limitNum, // take으로 limit설정
});
console.log("products, 여기긴", products);
const responseData = await productsPaginationHandler(products, offsetNum, limitNum);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

위 부분은 결국 가져온 값들을 페이지네이션을 시켜주기위한 단계로 보여집니다. 여기도 마찬가지로 레이어까지는 아니지만 별도의 함수로 분리해서 페이지네이션만을 담당하는 함수모듈로 분리할 수 있습니다. 마찬가지로 여기서도 페이지네이션만 담당하는 함수이니 다른것들은 신경쓰지 않는 방식으로 코드를 작성해도 무방합니다.

이미 함수로 나눠주신 부분이고, 그렇기 때문에 나뉘어진 코드는 후에 테스트 코드를 작성하거나, 오류(페이지네이션에 문제가 있어요)등이 발생했을때 코드의 어느부분을 확인하면 되는지 명확한 분리가 이루어질 수 있습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants