REST API는 stateless여야하기 때문에 데이터를 추가(create), 갱신(update), 삭제(delete)할 목적으로 POST
/PUT
/DELETE
메서드를 구성하기 위해선 persistence를 위한 (넓은 개념에서의) database는 필수적이다.
Spring boot에서는 Spring과 마찬가지로 다양한 persistence framework을 사용하여 database와의 커뮤니케이션이 가능하다.
그 중 간단한 형태로 설계된 RDB에 대해 최소한의 구현으로 최대한의 효과를 낼 수 있는 JPA를 사용하여 간단하게 CRUD를 구현해보자.
pom.xml
에 다음의 dependency를 추가하자.
Spring boot에서 JPA를 사용하기 위해서 spring-boot-stater-data-jpa
를 추가해주었다.
학습을 위해 MariaDB, PostgreSQL 등의 RDB 환경을 개별적으로 구성하는 것은 오버헤드가 커보인다. 때문에 여기서는 java 기반의 embedded DB인 h2를 사용한다.
<!-- spring boot jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency><!-- h2 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.194</version>
</dependency>
spring-boot-stater-data-jpa
와 h2
를 함께 사용하면 별다른 설정없이 사용이 가능하기 때문에 필요한 형태의 entity와 repository만 구현하면 데이터의 CRUD(create, read, update, delete)가 가능하다.
우선 id와 name으로 이루어진 간단한 entity를 만들어보자.
@Entity
public class User {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
private String name;
protected User() {}
public User(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return String.format("User[id='%d', name='%s']", id, name);
}
}
Spring Data JPA에서 entity임을 알 수 있도록 Entity
어노테이션을 붙여준다. ID 역할을 할 필드에 Id
, GeneratedValue
어노테이션을 붙여주면 해당 컬럼을 primary key로 인식하고 생성(create) 시점에서 database의 설정에 따라 자동적으로 값을 생성한다.
entity를 작성했으니, 이제 repository를 작성해 볼 차례다.
public interface UserRepository extends CrudRepository<User, Long> {}
왜 interface만 있고 구현체는 없을까?
Spring Data JPA에서는 위와같이 CrudRepository를 지원한다.
CrudRepository에는 아래와 같은 메서드들이 구현되어있기 때문에 단순한 CRUD만 사용한다면 추가적인 구현이 필요없다.
long count()
void delete(ID id)
void delete(Iterable<? extends T> entities)
void delete(T entity)
void deleteAll()
boolean exists(ID id)
Iterable<T> findAll()
Iterable<T> findAll(Iterable<ID> ids)
T findOne(ID id)
Iterable<S> save(Iterable<S> entities)
S save(S entity)
interface를 Spring Data JPA 덕분에 어물쩡 넘어갔으니 이제 controller를 구현할 차례다.
@RestController
@RequestMapping(value = "/users")
public class UserController {
private UserRepository userRepository;
@Autowired
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
// CREATE
// 사용자 이름을 입력받아 새로운 User를 생성하고 그 결과를 반환
@PostMapping
public User put(@RequestParam String name) {
return userRepository.save(new User(name));
}
// READ
// 모든 사용자 리스트를 반환
@GetMapping
public Iterable<User> list() {
return userRepository.findAll();
}
// READ
// 해당 ID의 사용자를 반환
@GetMapping(value = "/{id}")
public User findOne(@PathVariable Long id) {
return userRepository.findOne(id);
}
// UPDATE
// 해당 ID의 사용자 이름을 갱신한 뒤 그 결과를 반환
@PutMapping(value = "/{id}")
public User update(@PathVariable Long id, @RequestParam String name) {
User user = userRepository.findOne(id);
user.setName(name);
return userRepository.save(user);
}
// DELETE
// 해당 ID의 사용자를 삭제
@DeleteMapping
public void delete(@RequestParam Long id) {
userRepository.delete(id);
}
}
현재 단계에서는 request에 대한 validation이 없고 entity와 response의 형태가 동일하기 때문에 UserController가 위와같이 간결하게 작성되었다.
Spring Data JPA를 통해 데이터의 CRUD가 지원되면서 REST API Application의 구색을 맞춰가는 것처럼 보인다.
다음엔 Authorization 헤더를 통한 간단한 인증 과정을 구현해 볼 예정이다.