Spring boot JPA 등록/수정/조회 API 제작
등록/수정/조회 API 만들기
사용자 (User) 관련 로직
- 사용자 회원가입 (Insert)
- 사용자 탈퇴 (Delete)
- 사용자 조회 (Selete)
- 사용자 정보 변경 (Update)
- 사용자는 ID는 중복되지 않는다.
- 사용자 이름, 전화번호, 주민등록번호, 비밀번호를 가진다.
- 이름, 전화번호, 주민등록번호, 비밀 번호는 필수 입력 사항이다.
1. Spring Web Layer
사용자 (User) 관련 로직
- 사용자 회원가입 (Insert)
- 사용자 탈퇴 (Delete)
- 사용자 조회 (Selete)
- 사용자 정보 변경 (Update)
- 사용자는 ID는 중복되지 않는다.
- 사용자 이름, 전화번호, 주민등록번호, 비밀번호를 가진다.
- 이름, 전화번호, 주민등록번호, 비밀 번호는 필수 입력 사항이다.
1-1. Web Layer
- @Controller와 JSP 등의 뷰 템플릿 영역
- 이외에도 필터(@Filter), 인터셉터, 컨트롤러 어드바이스(@ControllerAdvice)등 외부 요청과 응답에 대한 전반적인 영역을 얘기한다.
1-2. Service Layer
- @Service에 사용되는 서비스 영역
- 일반적으로 Controller와 DAO의 중간 영역에서 사용된다.
- @Transactional이 사용되어야 하는 영역이기도 하다.
1-3. Repository Layer
- DB와 같이 데이터 저장소에 접근하는 영역
- DAO(Data Access Object) 영역
1-4. Dtos
- DTO(Data Transfer Object) : 계층간에 데이터 교환을 위한 객체
1-5. Domain Model
- 도메인이라 불리는 개발 대상을 모든 사람들이 동일한 관점에서 이해하고, 공유 할 수 있도록 단순화 시킨것.
- 택시 앱을 예로 들면 배차, 탑승, 요금 등이 모두 도메인이 될 수 있다.
- @Entity가 사용된 영역이 도메인 모델이다.
2. 트랜잭션 스크립트 패턴과 도메인 모델 패턴
2-1. 트랜잭션이란?
- 데이터베이스의 상태를 변경시키기 위해 수행하는 작업 단위.
- SELECT, UPDATE, INSERT, DELETE와 같은 작업들이 포함되어있다.
- 트랜잭션은 상황에 따라 여러개가 만들어질 수 있다.
- 하나의 트랜잭션은 commit(저장)되거나 rollback(철회) 될 수 있다.
- A, B, C, D 가 문제를 풀어 각각 100 Point 씩 얻었고 이를 DB에 저장하려 한다.
- A 저장 완료, B 저장 완료, C 저장 완료, D 저장 실패
- 이런 상황이 오게 된다면 잘못된 처리이므로 다시 저장을 수행해야 하는데, A, B, C는 그 전에 이미 저장이 완료되었기 때문에 다시 저장을 시작하면 200점이 저장된다.
- 이런 문제점들을 위해서 트랜잭션은 Commit 과 Rollback 을 이용한다.
- commit : 하나의 트랜잭션이 성공적으로 끝나서 데이터베이스가 일관성 있는 상태에 있음.
- rollback : 트랜잭션의 원자성이 깨질 때(하나의 트랜잭션 처리가 비정상적으로 종료 되었을 때)의 상태. Rollback이 이루어 진다면 트랜잭션을 다시 실행하거나 부분적으로 변경된 결과를 취소할 수 있다.
- 트랜젝션에는 4가지 특징이 존재한다.
- 원자성 : 트랜잭션이 모두 DB에 반영되거나, 전혀 반영되지 않거나해야한다.
- 일관성 : 작업 처리 결과가 항상 일관되어야 한다. 데이터 타입이 반환 전/후가 항상 동일해야한다.
- 독립성 : 하나의 트랜잭션은 다른 트랜잭션이 끼어들 수 없고, 마찬가지로 독립적임. 각각의 트랜잭션은 서로 간섭이 불가능함
- 지속성 : 트랜잭션이 성공적으로 완료되면 영구적으로 결과에 반영되어야함. 보통 commit이 되면 지속성은 만족 시킬 수 있다.
2-2. 트랜잭션 스크립트 정의
-
은행 계좌 이체 서비스의 경우 다음의 순서를 가진다.
- 잔고 확인 -> 받는 사람 확인 -> 이체 실행 -> 잔고 감소
- 이 순서가 하나의 로직으로 처리되어야 하고, 한번이라도 오류가 발생하면 모든 처리가 취소되고 모든 과정이 성공해야 처리가 완료된다. (All-or-Nothing)
- 트랜젝션 스크립트 패턴은 이렇게 하나의 트랜잭션으로 구성된 로직을 단일 함수 또는 단일 스크립트에서 처리하는 구조를 가진다.
2-3. 도메인 모델 정의
- 객체 지향 분석 설계에 기반해 구현하고자 하는 도메인(비즈니스 영역)의 모델을 생성하는 패턴.
- 도메인 모델은 비즈니스 영역에서 사용되는 객체를 판별하고, 객체가 제공해야 할 목록을 추출하며 각 객체관의 관계를 정립하는 과정을 거친다.
- 명사와 동사를 구분해서 명사로 객체를 추출해내고, 동사로부터 객체의 기능 및 객체 사이의 관계를 유추해낸다.
- 해당 글에서는 최대한 도메인 모델 패턴으로 코드를 작성할 것입니다.
3. User 등록
- 패키지는 다음과 같이 구성되어있다.
3-1. UserDTO 구현
package com.test.blog.user.dto;
import com.test.blog.user.entity.User;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
public class UserDTO {
private String id;
private String phoneNumber;
private String socialSecurityNumber;
private String password;
@Builder
public UserDTO(String id, String phoneNumber, String socialSecurityNumber, String password){
this.id = id;
this.phoneNumber = phoneNumber;
this.socialSecurityNumber =socialSecurityNumber;
this.password = password;
}
public User toEntity(){
return User.builder()
.id(id)
.phoneNumber(phoneNumber)
.socialSecurityNumber(socialSecurityNumber)
.password(password)
.build();
}
}
- DTO를 구현한 이유
- 절대로 Entity 클래스를 Request/Response에서 사용하면 안된다.
- Entity 클래스는 DB와 맞닿은 핵심 클래스이기 때문.
3-2. UserService 구현
package com.test.blog.user.service;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.test.blog.user.entity.UserRepository;
import com.test.blog.user.dto.UserDTO;
import org.springframework.transaction.annotation.Transactional;
/**
* 서비스는 실제 비즈니스 로직을 구현하는 단이다.
*/
@RequiredArgsConstructor
@Service
public class UserService {
private final UserRepository userRepository;
@Transactional
public String save(UserDTO userDTO){
return userRepository.save(userDTO.toEntity()).getId();
}
}
3-3. UserController 구현
package com.test.blog.user.controller;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import com.test.blog.user.dto.UserDTO;
import com.test.blog.user.service.UserService;
/**
* Bean을 주입 받을 때 방법은 3가지가 있다.
* @Autowired
* setter
* 생성자
*
* 이중 가장 권장되는 방법은 생성자로 주입받는것이다.
* @RequiredArgsConstructor로 final이 선언된 모든 필드에 Bean을 주입받는다.
*/
@RequiredArgsConstructor
@Controller
public class UserController {
private final UserService userService;
@PostMapping("/api/user")
public String save(@RequestBody UserDTO userDTO){
return userService.save(userDTO);
}
}
- Bean을 주입받는 방법 3가지
- @Autowired
- setter
- 생성자
- Bean을 주입받을 때 가장 권장되는 방법은 생성자로 주입받는 방법이 있다. 생성자로 Bean 객체를 받도록 하면 @Autowired와 동일한 효과를 볼 수 있다.
- @RequiredArgsConstructor로 final이 선언된 모든 필드를 생성자로 받게 한다.
- Spring Bean이란?
- IoC(제어의 역전, Inversion Of Control)특징 에 대해
- 일반적인 자바 프로그래밍 방식은 각 객체들이 프로그램의 흐름을 결정하고 각 객체를 직접 생성 (new)및 조작하는 작업을 했다.
- IoC가 적용될 경우에는 객체의 생성을 특별한 관리 위임 주체에게 맡긴다. 사용자는 객체를 직접 생성하지 않고 객체의 생명주기를 컨트롤하는 주체는 다른 주체가 된다.
- 사용자의 제어권을 다른 주체에게 넘기는것을 IoC라고 부른다.
- Spring에서는 new를 이요하여 생성한 객체가 아닌, Spring에 의해서 관리(IoC)당하는 자바 객체를 사용한다. 이렇게 스프링에서 생성되고 관리되는 자바 객체를 Bean이라고 부른다.
- IoC(제어의 역전, Inversion Of Control)특징 에 대해
3-4. UserControllerTest 구현
package com.test.blog.user.controller;
import com.test.blog.user.entity.User;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;
import com.test.blog.user.entity.UserRepository;
import com.test.blog.user.dto.UserDTO;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UserControllerTest {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Autowired
private UserRepository userRepository;
@After
public void end() throws Exception{
userRepository.deleteAll();
}
@Test
public void save() throws Exception{
String id = "JJStone";
UserDTO userDTO = UserDTO.builder()
.id(id)
.password("1234")
.phoneNumber("000-0000-0000")
.socialSecurityNumber("000000-0000000")
.build();
String url = "http://localhost:" + port + "/api/user";
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, userDTO, String.class);
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(responseEntity.getBody()).isEqualTo(id);
Optional<User> user_ = userRepository.findById(id);
assertThat(user_).isNotEmpty();
User user = user_.get();
assertThat(user.getId()).isEqualTo(id);
}
}
- @WebMvcTest의 경우 JPA 기능이 작동하지 않기 때문에 사용하지 않음
- @SpringBootTest와 TestRestTemplate 사용
- 포트는
SpringBootTest.WebEnvironment.RANDOM_PORT
사용
4. User 수정/조회
4-1. User 수정
-
User
package com.test.blog.user.entity; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; @Getter @Entity @NoArgsConstructor public class User { ... public void update(String phoneNumber, String socialSecurityNumber, String password){ this.phoneNumber = phoneNumber; this.socialSecurityNumber = socialSecurityNumber; this.password = password; } }
-
UserService
package com.test.blog.user.service; import com.test.blog.user.entity.User; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import com.test.blog.user.entity.UserRepository; import com.test.blog.user.dto.UserDTO; import org.springframework.transaction.annotation.Transactional; import java.util.Optional; /** * 서비스는 실제 비즈니스 로직을 구현하는 단이다. */ @RequiredArgsConstructor @Service public class UserService { private final UserRepository userRepository; ... @Transactional public String update(String id, UserDTO userDTO){ User user = userRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("해당 아이디가 없습니다.")); user.update(userDTO.getPhoneNumber(), userDTO.getSocialSecurityNumber(), userDTO.getPassword()); return id; } }
-
UserController
package com.test.blog.user.controller; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; import com.test.blog.user.dto.UserDTO; import com.test.blog.user.service.UserService; @RequiredArgsConstructor @RestController public class UserController { private final UserService userService; ... @PutMapping("/api/v1/user/{id}") public String update(@PathVariable String id, @RequestBody UserDTO userDTO){ return userService.update(id, userDTO); } }
-
DB에 UPDATE 쿼리를 날리는 부분이 존재하지 않음.
-
이유는 JPA 영속성 컨텍스트 때문.
-
영속성 컨텍스트란 엔티티를 영구 저장하는 환경이다. 일종의 논리적 개념이며 JPA의 핵심 내용은 엔티티가 영속성 컨텍스트에 포함되어있는지 아닌지로 갈린다.
-
JPA 엔티티 매니저 (EntityManager)가 활성화된 상태로(Spring Data Jpa를 쓰면 기본 옵션이다.) 트랜잭션 안에서 DB 데이터를 가져올때 이 데이터는 영속성 컨텍스트가 유지된 상태가 된다.
-
이 상태에서 데이터 값을 변경하면 트랜잭션이 끝나는 시점에 해당 테이블 변경분을 반영한다. 즉, Entity 객체의 값만 변경하면 별도의 UPDATE 쿼리를 날릴 필요가 없다.
더티체킹
이라고도 한다.- UserControllerTest (업데이트 테스트)
package com.test.blog.user.controller; import com.test.blog.user.entity.User; import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.http.HttpEntity; import org.springframework.http.HttpMethod; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.http.ResponseEntity; import org.springframework.http.HttpStatus; import com.test.blog.user.entity.UserRepository; import com.test.blog.user.dto.UserDTO; import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class UserControllerTest { @LocalServerPort private int port; @Autowired private TestRestTemplate restTemplate; @Autowired private UserRepository userRepository; @After public void end() throws Exception{ userRepository.deleteAll(); } ... @Test public void update() throws Exception{ String id = "user1"; User saveUser = userRepository.save(User.builder() .id(id) .password("1234") .socialSecurityNumber("000000-0000000") .phoneNumber("000-0000-0000") .build()); String updateId = saveUser.getId(); String password = "5678"; String socialSecurityNumber = "111111-1111111"; String phoneNumber = "111-1111-1111"; UserDTO userDTO = UserDTO.builder() .password(password) .socialSecurityNumber(socialSecurityNumber) .phoneNumber(phoneNumber) .build(); String url = "http://localhost:" + port + "/api/v1/user/" + updateId; HttpEntity<UserDTO> requestEntity = new HttpEntity<>(userDTO); ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.PUT, requestEntity, String.class); assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(responseEntity.getBody()).isEqualTo(id); Optional<User> user_ = userRepository.findById(updateId); assertThat(user_).isNotEmpty(); User user = user_.get(); assertThat(user.getPassword()).isEqualTo(password); assertThat(user.getPhoneNumber()).isEqualTo(phoneNumber); assertThat(user.getSocialSecurityNumber()).isEqualTo(socialSecurityNumber); } }
4-2. User 조회
-
UserDTO
package com.test.blog.user.dto; import com.test.blog.user.entity.User; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @Getter @NoArgsConstructor public class UserDTO { private String id; private String phoneNumber; private String socialSecurityNumber; private String password; ... public UserDTO(User user){ this.id = user.getId(); this.password = user.getPassword(); this.socialSecurityNumber = user.getSocialSecurityNumber(); this.phoneNumber = user.getPhoneNumber(); } }
-
UserService
package com.test.blog.user.service; import com.test.blog.user.entity.User; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import com.test.blog.user.entity.UserRepository; import com.test.blog.user.dto.UserDTO; import org.springframework.transaction.annotation.Transactional; import java.util.Optional; /** * 서비스는 실제 비즈니스 로직을 구현하는 단이다. */ @RequiredArgsConstructor @Service public class UserService { private final UserRepository userRepository; ... public UserDTO findById(String id){ User user = userRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("해당 아이디가 없습니다.")); return new UserDTO(user); } }
-
UserController
package com.test.blog.user.controller; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; import com.test.blog.user.dto.UserDTO; import com.test.blog.user.service.UserService; @RequiredArgsConstructor @RestController public class UserController { private final UserService userService; ... @GetMapping("/api/v1/user/{id}") public UserDTO findById(@PathVariable String id){ return userService.findById(id); } }
부록 - REST API
-
REST란?
-
정의
REpresentational State Transfer
의 약자- 웹에 존재하는 모든 자원(이미지, 동영상, DB)에 고유한 URL을 부여하여 활용하는것을 의미
- 자원을 정의하고 자원에 대한 주소를 지정하는 방법론.
-
구성요소
- 자원(Resource), URL : 모든 자원은 고유한 ID를 가지며 ID는 서버에 존재하고 클라이언트는 각 자원의 상태를 조작하기 위해 요청을 보낸다. HTTP에서 이러한 자원을 구별하는 ID는 strudent/1과 같은 HTTP URL이다.
- 행위(Verb), Method : 클라이언트는 URL을 이용해 자원을 지정하고 자원을 조작하기 위해 Method를 사용한다. HTTP 프로토콜에서는 GET, POST, DELETE와 같은 Method를 제공한다.
- 표현(Representation) : 클라이언트가 서버로 요청을 보냈을 때 응답 자원의 상태를 Representation이라고 한다. REST에서 하나의 자원은 JSON, XML, RSS등 여러 형태의 표현으로 나타낼 수 있다.
-
필요성
- 이해하기 쉽고 사용하기 쉬운 API를 제작하는데에 있다.
-
특징
- Unifrom (유니폼 인터페이스)
- URI로 지정한 리소스에 대한 조작을 통일되고 한정적인 인터페이스로 수행하는 아키텍처 스타일을 의미
- URL: 자원이 실재로 존재하는 위치를 가르킴
- URI: 자원의 위치뿐만이 아니라 자원에 대한 고유 식별자로써 URL 의미를 포함한다.
- URI로 지정한 리소스에 대한 조작을 통일되고 한정적인 인터페이스로 수행하는 아키텍처 스타일을 의미
- Stateless (무상태성)
- 작업을 위한 상태정보를 따로 저장하고 관리하지 않는다. 세션 정보나 쿠키 정보를 별도로 저장/관리 하지 않기 때문에 API 서버는 들어오는 요청만을 단순히 처리하면 된다.
- 서비스의 자유도가 높아지고, 서버에서 불필요한 정보를 관리하지 않음으로써 구현이 단순해진다.
- Cacheable (캐시 가능)
- HTTP라는 기존 웹 표준을 그대로 사용하기에 웹에서 사용하는 기존 인프라를 그대로 활용하는것이 가능하다. 따라서 HTTP가 가진 캐싱 기능이 적용 가능하다. HTTP 프로토콜 표준에서 사용하는 Last-Modified 태그나 E-Tag를 이용하면 캐싱 구현이 가능하다.
- Self-descriptiveness (자체 표현 구조)
- REST API 메세지만 보고도 이를 쉽게 이해 할 수 있는 자체 표현 구조로 되어있다.
- client-server 구조
- REST 서버는 API 제공, 클라이언트는 사용자 인증 혹은 컨텍스트(세션, 로그인 정보)등을 직접 관리하는 구조로 각각의 역할이 확실히 구분되기에 클라이언트와 서버에서 개발해야 할 내용이 명확해지고 서로간 의존성이 줄어들게 된다.
- 계층형 구조
- REST 서버는 다중 계층으로 구성될 수 있으며, 보안, 로드 밸런싱, 암호화 계층을 추가해 구조상의 유연성을 둘 수 있고 Proxy, 게이트웨이와 같은 네트워크 기반의 중간매체를 사용할 수 있게 한다.
- Unifrom (유니폼 인터페이스)
-
-
RESTful 이란?
-
정의
- REST 아키텍처를 구현하는 웹 서비스를 나타내기 위해서 사용되는 용어.
- REST 원리를 따르는 시스템을 RESTful이라는 용어로 지칭
-
Restful 디자인 가이드
- URI는 정보의 자원을 표현해야한다.
GET /members/1 # 리소스는 동사보다 명사를, 대문자보다 소문자를 사용 # 리소스는 도큐먼트 이름일때 단수 명사를 사용. # 리소스가 컬렉션일때 복수 명사를 사용. # 리소스가 스토어일때 복수 명사를 사용.
- 자원에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE)로 표현
- URI에 HTTP 메소드가 들어가면 안된다.
GET /books/delete/1 -> DELETE /books/1
- URI 행위에 대한 동사 표현이 들어가면 안된다. (CRUD 기능을 나타내는것은 URI에 사용하지 않는다.)
GET /books/show/1 -> GET /books/1 GET /books/insert/2 -> POST /books/2
- 경로 중 변하는 부분은 Unique 값으로 대체한다. (ID는 하나의 특정 resource를 나타내는 고유값을 의미한다.)
id = 10인 book을 삭제 -> DELETE /books/10
- / (슬래시 구분자)는 계층관계를 나타낸다.
http://edwith.org/courses/java
- URI 마지막 문자로 /를 포함하지 않는다.
- URI에 포함되는 모든 문자는 리소스 유일한 식별자로 사용되어야 하며, URI가 다르다는것은 리소스가 다르다는 뜻이고, 역으로 리소스가 다르면 URI도 달라져야 한다.
- 하이픈(-)은 URI 가독성을 높이는데 사용 가능하다.
- 밑줄(_)은 URI에서 사용하지 않는다.
- URI 경로는 소문자가 적합하다.
URI 경로에 대문자 사용은 피하도록 한다. RFC 3986(URI 문법 형식)은 URI 스키마와 호스트를 제외하고는 대소문자를 구별하도록 규정하기 때문이다. - 파일 확장자는 URI에 포함하지 않는다. Accept header를 사용하도록 한다.
http://edwith.org/files/java.jpg (X) GET /files/jdk18.exe HTTP/1.1 Host: edwith.org Accept: image/jpg (O)
- 리소스 간에 연관 관계가 있는 경우 다음과 같은 방법으로 표현한다.
/리소스명/리소스 ID/관계가 있는 다른 리소스명
GET : /books/{bookid}/viewers (일반적으로 소유 ‘has’의 관계를 표현할 때)
-
자원을 표현하는 컬렉션(Collection)과 도큐먼트(Document)
컬렉션은 객체의 집합, 도큐먼트는 객체라고 생각하면 된다. 컬렉션과 도큐먼트 모두 리소스로 표현할 수 있으며 URI로 표현할 수 있다.
http://edwith.org/courses/1 # courses는 컬렉션을 나타내므로 복수로 표현해야 한다. courses/1 은 courses중에서 id가 1인 도큐먼트를 의미한다.
-
RESTful API를 위한 HTTP Methods
- GET : 자원을 받아오기만 할 때 사용
- 어떤 방식으로도 자원을 변경시키지 않기 때문에
safe-method
라고도 불린다. - 멱등성의 성질을 가지고 있다. 멱등성이란 여러번의 동일한 API를 호출함에도 동일한 결과값을 받음을 의미한다.
(POST, PUT을 통해 데이터가 변경되지 않는다면)
- 어떤 방식으로도 자원을 변경시키지 않기 때문에
- POST : 새로운 자원이 추가될 때 사용
- 서버의 상태를 변경시키므로 비멱등성의 성질을 가지고 있다. 성공적으로 추가시
201 (created)
를 받는다.
- 서버의 상태를 변경시키므로 비멱등성의 성질을 가지고 있다. 성공적으로 추가시
- PUT : 존재하는 자원을 변경할 때 사용
- 존재하는 자원이 없으면 새로운 자원을 만들어 내고 응답 코드
201 (created)
을 받음. - 존재하는 자원이 있으면
200(OK)
또는204(No Content)
를 받음
- 존재하는 자원이 없으면 새로운 자원을 만들어 내고 응답 코드
- DELETE : 자원을 삭제할 때 사용
- 지속 삭제 시 서버 상태 변경 X, 하지만 이미 제거되었으므로 응답 코드
404(Not Found)
를 반환 받는다.
- 지속 삭제 시 서버 상태 변경 X, 하지만 이미 제거되었으므로 응답 코드
- PATCH : 한 자원의 데이터를 부분적으로 변경할 때 사용
- 조금더 명확하게는 존재하는 자원에 대해 부분적으로 업데이트를 위해서는 PATCH를 사용한다. PUT은 자원을 완전히 대체하는 경우 사용한다.
PATCH의 경우 모든 브라우저, 서버, 앱 어플리케이션 프레임워크에서 사용할 수 있는 것은 아니다.
- GET : 자원을 받아오기만 할 때 사용
-
Author And Source
이 문제에 관하여(Spring boot JPA 등록/수정/조회 API 제작), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@jiseok/Spring-boot-JPA-등록수정조회-API-제작저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)