[강정민] sprint3#38
Hidden character warning
Conversation
There was a problem hiding this comment.
이번 스프린트에서 비동기 처리 로직(.then, async/await)을 학습하시고 직접 API 연동까지 훌륭히 구현해 주셨네요! 전반적인 흐름과 로직 구조가 매우 좋습니다. 👏
다만 실제 서비스 코드라고 상상했을 때 발생할 수 있는 잠재적 버그, 그리고 코드의 중복을 피해 유지보수성을 극대화(DRY 원칙)할 수 있는 심화 과정의 피드백을 다양하게 남겨드립니다. 천천히 읽어보시고 적용해 보시면 큰 도움이 될 것 같습니다!
(※ 참고로, 혹 AI 도구를 활용해 바이브코딩을 진행하셨다면, 이 피드백만큼은 가급적 AI의 도움 없이 직접 원리를 파악하며 보시기를 적극 권장해 드립니다.)
package.json
Outdated
| "start": "node src/main.js" | ||
| }, | ||
| "dependencies": { | ||
| "axios": "^1.x.x" |
There was a problem hiding this comment.
P3
현재 프로젝트의 두 서비스 클래스가 모두 브라우저 내장 fetch API를 사용하여 네트워킹을 잘 처리하고 있습니다. axios가 의존성에 설치되어 있으나 실제로는 사용되지 않는 것으로 보이는데, 패키지 혼란을 막기 위해 사용하지 않는 라이브러리라면 과감하게 제거해 주시는 것을 권장해 드립니다.
src/api/ArticleService.js
Outdated
| @@ -0,0 +1,76 @@ | |||
| // src/api/ArticleService.js | |||
| const BASE_URL = 'https://panda-market-api-crud.vercel.app/articles'; | |||
There was a problem hiding this comment.
P4
ArticleService와 ProductService 모두 BASE_URL이 중복으로 선언되어 있고 하드코딩 되어 있습니다. 중복 선언을 방지하고 조금 더 시니어 레벨의 구조를 고민하신다면, 향후 src/config/index.js나 별도의 상수 파일로 BASE_URL을 분리하여 import 하는 패턴을 적용해 보시는 것도 좋은 베스트 프랙티스입니다!
src/api/ArticleService.js
Outdated
| * 1. 게시글 목록 조회 (GET /articles) | ||
| * 파라미터: page, pageSize, orderBy(recent/like), keyword | ||
| */ | ||
| export const getArticleList = (page = 1, pageSize = 10, orderBy = 'recent', keyword = '') => { |
There was a problem hiding this comment.
P3
keyword = ''인 상태로 URLSearchParams에 넘겨지면 ...?keyword=와 같이 불필요한 빈 쿼리스트링 파라미터가 생성될 수 있습니다. 값이 있을 때만 파라미터에 추가되도록 조건부로 처리하시면 훨씬 더 깔끔하고 견고한 URL이 생성될 것 같습니다.
src/api/ArticleService.js
Outdated
| const params = new URLSearchParams({ page, pageSize, orderBy, keyword }); | ||
|
|
||
| return fetch(`${BASE_URL}?${params.toString()}`) | ||
| .then((response) => { |
There was a problem hiding this comment.
P2
fetch 모듈 호출, response.ok 체크, .json() 파싱을 수행하는 이 로직이 모든 API 메서드(CRUD)에 계속 반복되고 있습니다. 이러한 중복(DRY 위배) 코드를 피하기 위해 request(url, options) 처럼 공통 유틸리티 함수를 만들어서 관리하시면 코드가 절반 이하로 훨씬 간결해질 것입니다. 한 번 고려해 보세요!
src/api/ProductService.js
Outdated
| body: JSON.stringify(productData), | ||
| }); | ||
|
|
||
| if (!response.ok) throw new Error(`상품 생성 실패: ${response.status}`); |
There was a problem hiding this comment.
P3
fetch 통신 요청이 실패했을 경우, 백엔드 서버에서 구체적인 에러 메시지가 담긴 JSON Body를 내려주는 경우가 잦습니다. 실패 시 단순히 HTTP Code(.status)만 던지기보단, await response.text()나 .json()을 활용해 에러 사유를 구체적으로 파싱하여 에러 객체에 담는 코드를 짜보시면 실무 디버깅 난이도가 한결 낮아집니다!
src/main.js
Outdated
| // 5. 상품 삭제 | ||
| if (createdProduct && createdProduct.id) { | ||
| const deletedProduct = await ProductService.deleteProduct(createdProduct.id); | ||
| console.log(`✅ [Product] ${createdProduct.id}번 삭제 완료:\n`, deletedProduct); |
There was a problem hiding this comment.
P3
runProductTests는 비동기(async) 함수이므로 뒷단의 코드도 기다림 없이 곧바로 실행되게 됩니다. 그 결과 터미널 로그의 출력 시점이 뒤섞이게 되어(Race Condition 현상) 결과를 확인하기 쉽지 않습니다. async IIFE(즉시 실행 함수) 등을 활용하여 해당 테스트가 온전히 끝난 후 다른 테스트가 순차적으로 실행되도록 제어 메커니즘을 부여해 보시는 것을 권장해 드립니다.
| image: "https://example.com/test-image.png", | ||
| }; | ||
|
|
||
| ArticleService.createArticle(newArticleData) |
There was a problem hiding this comment.
P4
생성 데이터가 누락되거나 ID가 제대로 반환되지 않았을 불확실성을 사전 대비한 아주 훌륭한 방어적 프로그래밍 관점의 체크 포인트입니다! 👏 아주 좋습니다.
src/main.js
Outdated
|
|
||
| ArticleService.createArticle(newArticleData) | ||
| .then((createdData) => { | ||
| console.log("✅ [Article] 생성 결과:\n", createdData); |
There was a problem hiding this comment.
P3
이 부분의 .then() 내부를 보면, 하위 구조에서 다시 ArticleService.patchArticle 체이닝 구조를 만들어 리턴하고 있습니다. 바깥 로직과 잘 연동은 되지만 Promise Hell 징후를 다소 보이고 있습니다. 뎁스(Depth)를 깊게 들어가지 말고 바깥쪽 스코프의 플래트닝(Flattening) 체인으로 연결을 시도해 보시면 더욱 가독성 높고 유려한 비동기 컨트롤 흐름을 구사하실 수 있을 것 같습니다!
src/main.js
Outdated
| return ArticleService.deleteArticle(createdData.id); | ||
| }) | ||
| .then((deleteData) => { | ||
| console.log(`✅ [Article] ${createdData.id}번 삭제 완료:\n`, deleteData); |
There was a problem hiding this comment.
P2
비동기 Promise 체이닝의 종단점 체인 끝에는 반드시 단일 .catch() 블록을 두는 것이 좋습니다. 체인 과정 속 어느 시점에서 이슈가 터지더라도 한 곳에서 확실하게 잡아내어(Unhandled Promise Rejection 방지) 앱의 크래시를 막고 통일된 예외 처리가 가능하므로 로직 마지막에 꼭 추가해 주시기 바랍니다!
요구사항
기본 요구사항
공통
getArticleList(): GET 메서드를 사용해 주세요.page,pageSize,keyword쿼리 파라미터를 이용해 주세요.getArticle(): GET 메서드를 사용해 주세요.createArticle(): POST 메서드를 사용해 주세요.title,content,image를 포함해 주세요.patchArticle(): PATCH 메서드를 사용해 주세요.deleteArticle(): DELETE 메서드를 사용해 주세요.fetch혹은axios를 이용해 주세요..then()메서드를 이용하여 비동기 처리를 해주세요..catch()를 이용하여 오류 처리를 해주세요.getProductList(): GET 메서드를 사용해 주세요.page,pageSize,keyword쿼리 파라미터를 이용해 주세요.getProduct(): GET 메서드를 사용해 주세요.createProduct(): POST 메서드를 사용해 주세요.name,description,price,tags,images를 포함해 주세요.patchProduct(): PATCH 메서드를 사용해 주세요.deleteProduct(): DELETE 메서드를 사용해 주세요.async/await을 이용하여 비동기 처리를 해주세요.try/catch를 이용하여 오류 처리를 해주세요.export를 활용해 주세요.ProductService.js파일 Product API 관련 함수들을 작성해 주세요.ArticleService.js파일에 Article API 관련 함수들을 작성해 주세요.main.js파일에 작성해 주세요.import를 활용해 주세요.