Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ implement recipe and recipe steps creation #143

Merged
merged 16 commits into from
Aug 3, 2024
Merged

✨ implement recipe and recipe steps creation #143

merged 16 commits into from
Aug 3, 2024

Conversation

oshyun00
Copy link

@oshyun00 oshyun00 commented Aug 1, 2024

구현 API

(1) POST /api/recipes
(2) POST /api/recipes/{recipeId}/steps
(3) GET /api/recipes/{recipeId}/steps/{sequence}

참고 사항

  • 레시피 생성 흐름은 다음과 같습니다.
    Recipe 생성 요청(1) -> 생성된 Recipe의 id 응답 -> Recipe id와 함께 각 Recipe Step 생성 요청(2) -> 생성된 Recipe Step 정보 응답
    레시피 생성 중 레시피 스텝 전/후로 이동하기 위해 Recipe id, sequence로 Step 조회하는 API(3) 가 추가되었습니다.

  • 필드 수정
    RecipeStep에 해당 Step의 소요시간 필드 추가


레시피 생성 하나의 이슈인데 레시피 생성을 위한 단계가 많아 코드 변경사항이 조금 있습니다.
레시피 생성, 레시피 스텝 생성, 레시피의 스텝 조회 각각의 흐름을 따라가며 보시면 좀 더 보기 편하실 것 같습니다.

중복 sequence 검증 등의 예외 처리는 되어있지 않습니다. 참고 부탁드리며 편하게 피드백 부탁드립니다!!! 🙇🏻‍♀️

Copy link

github-actions bot commented Aug 1, 2024

Overall Project 89.79% -0.72% 🍏
Files changed 92.54% 🍏

File Coverage
RecipeStepRequest.java 100% 🍏
RecipeRequest.java 100% 🍏
RecipeResponse.java 100% 🍏
RecipeController.java 100% 🍏
RecipeService.java 95.71% -4.29% 🍏
RecipeStep.java 89.29% -5.36% 🍏
Recipe.java 68.18% 🍏

Copy link

@HaiSeong HaiSeong left a comment

Choose a reason for hiding this comment

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

고생하셨습니다!!
예외 코드만 다시 말해보면 좋을것 같아요!

public List<RecipeStepResponse> readRecipeSteps(long id) {
List<RecipeStep> recipeSteps = recipeStepRepository.findAllByRecipeIdOrderBySequence(id);
return convertToRecipeStepResponses(recipeSteps);
}

public RecipeStepResponse readRecipeStep(long recipeId, long sequence) {
RecipeStep recipeStep = recipeStepRepository.findByRecipeIdAndSequence(recipeId, sequence)
.orElseThrow(() -> new RecipeException(HttpStatus.NO_CONTENT, "해당되는 레시피 스텝 정보가 없습니다."));
Copy link

Choose a reason for hiding this comment

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

이전에 새양이 예외처리를 RecipeException을 상속받는 새로운 예외를 만들자고 했었어요. 예외를 하나 만들어주면 좋을것 같아요!

Copy link
Author

Choose a reason for hiding this comment

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

좋은 말씀이네요 👍🏻 RecipeException을 상속받는 NotFoundException으로 분리했습니다.
다만 나중에 다같이 얘기해봐야할 것 같은 부분이 있습니다. 도메인별로 exception 을 구현하게 되면서 DuplicationException과 같이 비슷한 이름의 예외가 도메인마다 생길수도 있을 것 같은데요, 네이밍을 어떻게 해야할지 한번 생각해보면 좋을 것 같아요!

Copy link

Choose a reason for hiding this comment

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

맞아요! 저도 네이밍에 대한 고민을 계속 하고 있었는데 다같이 이야기 해보는 시간이 필요할것 같아요.
우선 적절하게 네이밍 잘하신것 같아요👍👍👍👍👍

public List<RecipeStepResponse> readRecipeSteps(long id) {
List<RecipeStep> recipeSteps = recipeStepRepository.findAllByRecipeIdOrderBySequence(id);
return convertToRecipeStepResponses(recipeSteps);
}

public RecipeStepResponse readRecipeStep(long recipeId, long sequence) {
RecipeStep recipeStep = recipeStepRepository.findByRecipeIdAndSequence(recipeId, sequence)
.orElseThrow(() -> new RecipeException(HttpStatus.NO_CONTENT, "해당되는 레시피 스텝 정보가 없습니다."));
Copy link

Choose a reason for hiding this comment

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

204 보다는 404가 맞지 않나 생각해요!

Copy link
Author

Choose a reason for hiding this comment

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

말씀해주신대로 사용자의 부적절한 호출이라 404가 더 적절한 것 같네요! 수정했습니다.


public RecipeStepResponse createRecipeStep(long recipeId, RecipeStepRequest recipeStepRequest) {
Recipe recipe = recipeRepository.findById(recipeId)
.orElseThrow(() -> new RecipeException(HttpStatus.NO_CONTENT, "해당되는 레시피가 없습니다."));
Copy link

Choose a reason for hiding this comment

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

이 부분도 404 에러가 아닌가 생각합니다!

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.test.context.jdbc.Sql;

@WithLoginUserTest
Copy link

Choose a reason for hiding this comment

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

👍👍👍👍🙇🙇🙇🙇

Copy link
Author

Choose a reason for hiding this comment

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

만들어주신 덕분에 정말 편하게 사용했습니다. 감사합니다 👍🏻👍🏻👍🏻👍🏻👍🏻👍🏻

@@ -57,6 +67,52 @@ void readRecipes() {
.body("size()", is(3));
}

@Test
@WithLoginUser(email = "[email protected]")
Copy link

Choose a reason for hiding this comment

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

👏👏👏👏👏

fieldWithPath("sequence").description("레시피 스텝 순서")
)))
.when()
.get("/api/recipes/{recipeId}/steps/{sequence}", 1L, 1L)
Copy link

Choose a reason for hiding this comment

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

저도 맨날 하드코딩으로 스트링에 아이디값 넣었었는데 엘라한테 배웠습니다! 🤗🤗

Comment on lines 34 to 35
@Import({RecipeService.class, CategoryService.class, IngredientService.class, IngredientRecipeService.class,
IngredientSubstitutionService.class})
Copy link

Choose a reason for hiding this comment

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

다른 서비스 테스트들이랑 일관성을 지키려고 DataJpaTest를 유지하신것 같아요!
그런데 너무 많이 임포트 되고 있어서 DataJpaTest가 아니라 SpringBootTest가 더 좋지 않나 생각이 들어요.
이따 다같이 논의해보면 좋을것 같아요

Copy link
Author

Choose a reason for hiding this comment

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

말씀하신것처럼 일관성 유지때문에 DataJpaTest를 쓰기는 했는데요, 서비스 클래스들이 모두 필요하다면 SpringBootTest가 유리할수 있을 것 같습니다. (처음에 임포트할 서비스가 많아 연관된 서비스 클래스들을 찾아오는게 헷갈리기도 했어요)
이 부분은 다 같이 한번 얘기해보면 좋을 것 같네요!

Copy link

@Hogu59 Hogu59 Aug 2, 2024

Choose a reason for hiding this comment

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

여기서 시작된 "다음에 얘기하기"....
이 이야기는 2024년 엘라의 pr에서 시작하여...

import java.util.List;
import net.pengcook.ingredient.dto.IngredientCreateRequest;

public record RecipeRequest(
Copy link

Choose a reason for hiding this comment

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

@NotNull 이나 @notblank 등으로 예외처리 해줘도 좋을것 같아요!

Copy link
Author

Choose a reason for hiding this comment

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

@notblank 설정 추가했습니다. 아직 다른 예외처리는 되어있지 않아서 해당 부분은 이슈 분리해서 처리할 예정입니다. 😁

Copy link

github-actions bot commented Aug 2, 2024

Overall Project 89.79% -0.72% 🍏
Files changed 92.54% 🍏

File Coverage
RecipeStepRequest.java 100% 🍏
RecipeRequest.java 100% 🍏
RecipeResponse.java 100% 🍏
RecipeController.java 100% 🍏
RecipeService.java 95.71% -4.29% 🍏
RecipeStep.java 89.29% -5.36% 🍏
Recipe.java 68.18% 🍏

Copy link

github-actions bot commented Aug 2, 2024

Overall Project 89.67% -0.86% 🍏
Files changed 91.18% 🍏

File Coverage
RecipeStepRequest.java 100% 🍏
RecipeRequest.java 100% 🍏
RecipeResponse.java 100% 🍏
RecipeController.java 100% 🍏
RecipeService.java 96.4% -3.6% 🍏
RecipeStep.java 89.29% -5.36% 🍏
Recipe.java 68.18% 🍏
NotFoundException.java 0% 🍏

@oshyun00
Copy link
Author

oshyun00 commented Aug 2, 2024

이미지 URL을 DB에 저장하기 위해서는 S3Service를 사용해야하는 상황이라 지금은 DB에 이미지 제목만 저장되는 상태입니다.
이 부분은 S3 부분 merge 후 반영할 예정입니다.

Copy link

@tackyu tackyu left a comment

Choose a reason for hiding this comment

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

리뷰가 늦어서 죄송합니다!
pr에 작성 해주신대로 흐름에 맞게 코드를 잘 구성해주신 것 같아요
일관성 관련된 부분만 몇가지 표시해두었습니다
고생 많으셨습니다!!

public RecipeResponse createRecipe(@LoginUser UserInfo userInfo, @RequestBody RecipeRequest recipeRequest) {
return recipeService.createRecipe(userInfo, recipeRequest);
}

@GetMapping("/{id}/steps")
public List<RecipeStepResponse> readRecipeSteps(@PathVariable long id) {
return recipeService.readRecipeSteps(id);
}
Copy link

Choose a reason for hiding this comment

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

{recipeId}로 통일하는 것도 괜찮을 것 같습니다!

User author = userRepository.findById(userInfo.getId()).orElseThrow();
Recipe recipe = new Recipe(recipeRequest.title(), author, LocalTime.parse(recipeRequest.cookingTime()),
recipeRequest.thumbnail(), recipeRequest.difficulty(), recipeRequest.description());

Copy link

Choose a reason for hiding this comment

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

개행 컨벤션에 맞춰도 괜찮을 것 같아요!


return new RecipeStepResponse(savedRecipeStep);
}

public List<MainRecipeResponse> readRecipesOfCategory(RecipeOfCategoryRequest request) {
Copy link

Choose a reason for hiding this comment

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

recipeOfCategoryRequest로 매개변수 명을 통일해도 괜찮을 것 같습니다!

Copy link
Author

Choose a reason for hiding this comment

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

아무래도 여러명이 작업하다보니 같은 기능이라도 네이밍이 다른 곳들이 꽤 있는 것 같습니다. 오프라인 리뷰때 같이 보면서 수정하면 좋을 것 같아요!

import net.pengcook.recipe.domain.RecipeStep;
import org.springframework.data.jpa.repository.JpaRepository;

public interface RecipeStepRepository extends JpaRepository<RecipeStep, Long> {

List<RecipeStep> findAllByRecipeIdOrderBySequence(long id);

Copy link

Choose a reason for hiding this comment

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

매개변수 명을 id또는 recipeId로 맞춰도 좋을 것 같아요!

Copy link
Author

Choose a reason for hiding this comment

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

해당부분 일괄 수정했습니다!

@HaiSeong
Copy link

HaiSeong commented Aug 3, 2024

너무 고생 믾으셨습니다!!! 주말에도 고생이 많으시네요! 화이팅해봐요~~

@HaiSeong HaiSeong self-requested a review August 3, 2024 03:00
Copy link

@HaiSeong HaiSeong left a comment

Choose a reason for hiding this comment

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

👏👏👏👏👏

@DataJpaTest
@Import({RecipeService.class, CategoryService.class, IngredientService.class, IngredientRecipeService.class,
IngredientSubstitutionService.class})
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
Copy link

Choose a reason for hiding this comment

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

👍👍

Copy link

@HaiSeong HaiSeong left a comment

Choose a reason for hiding this comment

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

확인했습니다! 수고하셨어요!!

@oshyun00 oshyun00 merged commit deec182 into be/dev Aug 3, 2024
1 check passed
@oshyun00 oshyun00 deleted the be/feat/20 branch August 3, 2024 07:16
Copy link

github-actions bot commented Aug 3, 2024

Overall Project 91.4% -0.86% 🍏
Files changed 92.21% 🍏

File Coverage
RecipeStepRequest.java 100% 🍏
RecipeRequest.java 100% 🍏
RecipeResponse.java 100% 🍏
RecipeController.java 100% 🍏
RecipeService.java 96.59% -3.41% 🍏
RecipeStep.java 89.29% -5.36% 🍏
Recipe.java 68.18% 🍏
NotFoundException.java 0% 🍏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BE Backend ✨ feature new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants