13-2. Update, Delete 구현하기

2026. 2. 10. 23:49·BackEnd/내일배움캠프

메모장 프로젝트 최종 완성본 코드이다.

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
'BackEnd/내일배움캠프' 카테고리의 다른 글
  • 15. SQL
  • 14. Database
  • 13-1. Create, Read 구현하기
  • 13. 메모장 프로젝트 설계
JK-LEE98
JK-LEE98
백엔드 개발자
  • JK-LEE98
    JK-LEE98
    JK-LEE98
  • 전체
    오늘
    어제
    • 분류 전체보기 (60)
      • 나의 지식 공유 (4)
      • SQL (4)
      • PS (10)
      • BackEnd (32)
        • Java (3)
        • Spring (4)
        • 내일배움캠프 (20)
        • 프로그래머스 데브코스 (5)
      • 건강한 나 되기🍀 (10)
  • 인기 글

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
JK-LEE98
13-2. Update, Delete 구현하기
상단으로

티스토리툴바