메모장 프로젝트 최종 완성본 코드이다.
package com.sparta.memo.controller;
import com.sparta.memo.dto.MemoRequestDto;
import com.sparta.memo.dto.MemoResponseDto;
import com.sparta.memo.entity.Memo;
import org.springframework.web.bind.annotation.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api")
public class MemoController {
private final Map<Long, Memo> memoList = new HashMap<>();
@PostMapping("/memos")
public MemoResponseDto createMemo(@RequestBody MemoRequestDto requestDto) {
// RequestDto -> Entity
Memo memo = new Memo(requestDto);
// Memo Max ID Check
Long maxId = memoList.size() > 0 ? Collections.max(memoList.keySet()) + 1 : 1;
memo.setId(maxId);
// DB 저장
memoList.put(memo.getId(), memo);
// Entity -> ResponseDto
MemoResponseDto memoResponseDto = new MemoResponseDto(memo);
return memoResponseDto;
}
@GetMapping("/memos")
public List<MemoResponseDto> getMemos() {
// Map To List
List<MemoResponseDto> responseList = memoList.values().stream()
.map(MemoResponseDto::new).toList();
return responseList;
}
@PutMapping("/memos/{id}")
public Long updateMemo(@PathVariable Long id, @RequestBody MemoRequestDto requestDto) {
// 해당 메모가 DB에 존재하는지 확인
// Cilent로 부터 JSON형식으로 넘어오기 때문에 @RequestBody 사용
if(memoList.containsKey(id)) {
// 해당 메모 가져오기
Memo memo = memoList.get(id);
// memo 수정
memo.update(requestDto);
return memo.getId();
} else {
throw new IllegalArgumentException("선택한 메모는 존재하지 않습니다.");
}
}
@DeleteMapping("/memos/{id}")
public Long deleteMemo(@PathVariable Long id) {
// 해당 메모가 DB에 존재하는지 확인
if(memoList.containsKey(id)) {
// 해당 메모 삭제하기
memoList.remove(id);
return id;
} else {
throw new IllegalArgumentException("선택한 메모는 존재하지 않습니다.");
}
}
}
강의를 들으며 위와 같은 코드가 완성되었다. 여기서 나는 궁금한 부분이 생겼다.
이전 springboot로 개발할 때는 경로만 봐도 어떤 행위를 하는지 대략 알 수 있게끔 코드를 짰는데 강의에서 사용한 코드는 달랐기 때문이다.
이에 대해 gpt에게 물어보고 답변을 정리해봤다.
REST API 경로 설계: /memos/delete/{id} vs /memos/{id}
Spring으로 API를 만들다 보면 한 번쯤은 이런 고민을 하게 된다.
예전에는 /memos/delete/{id} 처럼 경로에 행위(action) 를 명시했는데,
요즘 예제나 실무 코드를 보면 /memos/{id} 하나로 처리한다.경로만 봐도 어떤 동작인지 바로 알 수 있는 게 더 좋은 설계 아닌가?
이 글에서는 두 방식의 차이, 그리고 협업·유지보수 관점에서 왜 REST 방식이 선호되는지를 정리한다.
1. 두 가지 API 설계 방식 비교
1) 행위를 경로에 포함하는 방식
POST /memos/create
GET /memos/list
PUT /memos/update/{id}
DELETE /memos/delete/{id}
특징
- URL만 봐도 어떤 동작인지 직관적
- 초보자에게 이해하기 쉬움
- Controller 메서드 이름과 1:1로 대응됨
하지만 이 방식에는 구조적인 한계가 있다.
2) REST 방식 (리소스 중심 설계)
POST /memos → 메모 생성
GET /memos → 메모 전체 조회
PUT /memos/{id} → 메모 수정
DELETE /memos/{id} → 메모 삭제
핵심 개념
- URL는 리소스(명사) 만 표현한다
- 행위는 HTTP Method가 표현한다
즉,
- DELETE /memos/{id} 자체가 이미
→ “id에 해당하는 memo 리소스를 삭제한다”는 의미를 가진다.
2. 왜 REST 방식이 더 좋은가?
1) 역할 분리가 명확하다
요소책임
| URL | 무엇(Resource) |
| HTTP Method | 어떻게(Action) |
행위를 URL에 넣기 시작하면 이 경계가 무너진다.
/memos/delete/{id} → URL과 Method가 같은 일을 설명
이는 중복 표현이며, API가 커질수록 일관성을 해친다.
2) 협업 시 규칙이 단순해진다
REST 규칙이 정해지면 팀원들은 경로를 외울 필요가 없다.
"메모 삭제 API 뭐지?"
→ DELETE /memos/{id}
반면 action 기반 URL은 프로젝트마다 다르다.
/memos/delete/{id}
/memo/remove/{id}
/memos/{id}/delete
이 차이는 협업 규모가 커질수록 유지보수 비용으로 이어진다.
3) API 확장에 유리하다
REST 방식은 리소스 단위로 확장이 쉽다.
GET /memos/{id} → 단건 조회
PATCH /memos/{id} → 일부 수정
GET /memos/{id}/likes → 메모의 좋아요 조회
만약 action 중심이라면
/memos/get/{id}
/memos/partial-update/{id}
/memos/get-like/{id}
처럼 규칙이 계속 흔들릴 가능성이 높다.
4) 프레임워크·표준과 잘 맞는다
- Spring MVC
- Swagger / OpenAPI
- REST Client, API Gateway
이런 도구들은 REST 규칙을 전제로 설계되어 있다.
REST 방식으로 API를 만들면
- 문서 자동화가 쉬워지고
- 외부 시스템 연동도 자연스럽다.
3. "경로만 봐도 알 수 있어야 하지 않나?"에 대한 답
이 말 자체는 틀리지 않다.
하지만 REST에서는
경로 + HTTP Method를 함께 보는 것이 기본 전제다.
DELETE /memos/3
이 한 줄만 봐도 개발자는 즉시 이해한다.
- 삭제
- 대상은 memos 리소스
- id = 3
오히려 /memos/delete/3 은
- HTTP Method를 무시해도 동작할 것 같은 API가 되고
- REST 규칙을 아는 개발자에게는 오히려 낯설다.
4. 언제 action 기반 URL이 쓰이기도 하나?
완전히 잘못된 것은 아니다.
예외적으로 허용되는 경우
- 로그인, 로그아웃
- 결제 승인, 취소
- 리소스로 표현하기 애매한 도메인 동작
POST /auth/login
POST /payments/confirm
이런 경우는 명확한 동작 자체가 도메인이기 때문에 action이 들어가기도 한다.
하지만 CRUD 리소스 API에서는 REST 방식이 정답에 가깝다.
5. 결론
- /memos/delete/{id} 가 직관적으로 보일 수는 있다
- 하지만 협업, 유지보수, 확장성 관점에서는
리소스 중심 REST 설계가 더 우수하다
추천 기준
- CRUD → REST 방식
- 도메인 액션 → action 기반 URL 허용
지금 작성한 MemoController는
실무 기준에서도 잘 설계된 REST API에 가깝다.
결국 RESTful한 개발 방식은 강의에서 작성한 것과 같은 방식인 것으로 기억하고 이후 개발에서도 적용해야겠다.
'BackEnd > 내일배움캠프' 카테고리의 다른 글
| 15. SQL (0) | 2026.02.11 |
|---|---|
| 14. Database (0) | 2026.02.10 |
| 13-1. Create, Read 구현하기 (0) | 2026.02.10 |
| 13. 메모장 프로젝트 설계 (0) | 2026.02.10 |
| 12. HTTP 데이터를 객체로 처리하는 방법 (0) | 2026.02.10 |