[์คํ๋ง with AWS] CRU ๊ธฐ๋ฅ - RestTemplate์ผ๋ก API ํ ์คํธ
๐ CH.03 ๐
3์ฅ๋ถํฐ๋ ํ๋์ ๊ฒ์ํ ํ์ด์ง๋ฅผ ๋ง๋ค์ด๋ณด๊ณ ,
7์ฅ์์ 10์ฅ๊น์ง๋ ์ด ์๋น์ค๋ฅผ AWS ๋ฌด์ค๋จ ๋ฐฐํฌํ๋ ๊ฒ๊น์ง ์งํํ๋ค.
๐ Role #1
๊ธฐ๋ณธ์ ์ผ๋ก Builder ํจํด์ ์ฌ์ฉํ๋ค.
๐ Role #2
Setter๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ,
๊ธฐ๋ณธ์ ์ผ๋ก ์์ฑ์๋ฅผ ํตํด ๊ฐ์ ์ฑ์ฐ๊ณ ,
๊ฐ ๋ณ๊ฒฝ์ด ํ์ํ ๊ฒฝ์ฐ์ ๋ช ํํ๊ฒ ๊ทธ ๋ชฉ์ ๊ณผ ์๋๋ฅผ ๋ํ๋ผ ์ ์๋ ๋ฉ์๋๋ฅผ ์ถ๊ฐํ๋ค.
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Posts {
//id,title.content,author ์๋ต
...
@Builder
public Posts(String title, String content, String author) {
this.title = title;
this.content = content;
this.author = author;
}
}
๐ ์์ฑ์ ๋์ ๋น๋ ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ ์ด์ ๋,
์ด๋ ํ๋์ ์ด๋ค ๊ฐ์ ์ฑ์์ผํ ์ง ๋ช ํํ๊ฒ ์ธ์งํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
Example.builder()
.a(a)
.b(b)
.build();
JpaRepository๋ ์์ฑํด์ฃผ์๋๋ฐ,
์ด๋ Entity ํด๋์ค๋ ๊ธฐ๋ณธ Repository์ ํจ๊ป ์์นํด์ผํ๋ค๋ ์ ์ด ์๋ก์ ๋ค.
์ด๋๊น์ง repository๋ง ํ ๊ณณ์ ๋ชจ์๋์๋๋ฐ, ๋์ค์ ํ๋ก์ ํธ๊ฐ ์ปค์ ธ์ ๋๋ฉ์ธ๋ณ๋ก ํ๋ก์ ํธ๋ฅผ ๋ถ๋ฆฌํ๋ ์ํฉ์ด ์จ๋ค๋ฉด ํจ๊ป ์์ง์ฌ์ผํ๋ฏ๋ก ๊ฐ์ด ๋๋ฉ์ธ ํจํค์ง์์ ๊ด๋ฆฌํ๋ค๊ณ ํ๋ค.
๐ JPA ๊ธฐ๋ณธ ํ ์คํธ ์ฝ๋
@RunWith(SpringRunner.class)
@SpringBootTest
public class PostsRepositoryTest {
@Autowired
PostsRepository postsRepository;
@After
public void clenup()
{
postsRepository.deleteAll();
}
@Test
public void ๊ฒ์๊ธ์ ์ฅ_๋ถ๋ฌ์ค๊ธฐ() throws Exception{
//given
String title="๊ฒ์๊ธ ์ ๋ชฉ";
String content="๊ฒ์๊ธ ๋ณธ๋ฌธ";
postsRepository.save(Posts.builder()
.title(title)
.content(content)
.author("abc@gmail.com")
.build());
//when
List<Posts> postsList = postsRepository.findAll();
//then
Posts posts = postsList.get(0);
assertThat(posts.getTitle()).isEqualTo(title);
assertThat(posts.getContent()).isEqualTo(content);
}
}
H2 ์ฟผ๋ฆฌ ๋์ SQL ์ฟผ๋ฆฌ ๋ก๊ทธ๋ก ๋จ๊ธฐ๊ธฐ ์ํด ์๋ ์ถ๊ฐ
spring.jpa.properties.hibernate.format_sql=true
๐ ๋ฑ๋ก,์์ ,์กฐํ API ๋ง๋ค๊ธฐ ๐
- Request ๋ฐ์ดํฐ ๋ฐ์ DTO
- API ์์ฒญ์ ๋ฐ์ Controller
- ํธ๋์ญ์ ,๋๋ฉ์ธ ๊ธฐ๋ฅ ๊ฐ์ ์์๋ฅผ ๋ณด์ฅํ๋ Service
Service๋ ๋น์ฆ๋์ค๋ก์ง์ ์ฒ๋ฆฌํ๋ ๊ณณ์ด ์๋๋ค.
ํธ๋์ญ์ , ๋๋ฉ์ธ ๊ฐ ์์๋ฅผ ๋ณด์ฅํ๋ ์ญํ ๋ง ํ๋ค.
๋น์ฆ๋์ค ๋ก์ง์ ์ฒ๋ฆฌํด์ผํ๋ ๊ณณ์ ๋ฐ๋ก Domain์ด๋ค.
* ๋๋ฉ์ธ ๋ชจ๋ธ ํจํด *
์ํฐํฐ๊ฐ ๋น์ฆ๋์ค ๋ก์ง์ ๊ฐ์ง๊ณ , ๊ฐ์ฒด์งํฅ์ ํน์ฑ์ ์ ๊ทน ํ์ฉํ๋ ํจํด
โ ํธ๋์ญ์
์คํฌ๋ฆฝํธ (Service์์ ๋๋ถ๋ถ์ ๋น์ฆ๋์ค ๋ก์ง์ ์ฒ๋ฆฌํ๋ ๊ฒ
๐ ๋ฑ๋ก Controller
@RequiredArgsConstructor
@RestController
public class PostApiController {
private final PostsService postsService;
@PostMapping("/api/v1/posts")
public Long save(@RequestBody PostSaveRequestDto requestDto)
{
return postsService.save(requestDto);
}
}
๐ ๋ฑ๋ก Service
@RequiredArgsConstructor
@Service
public class PostsService {
private final PostsRepository postsRepository;
@Transactional
public Long save(PostSaveRequestDto requestDto) {
return postsRepository.save(requestDto.toEntity()).getId();
}
}
๐ ๋ฑ๋ก RequestDto
@Getter
@NoArgsConstructor
public class PostSaveRequestDto {
private String title;
private String content;
private String author;
@Builder
public PostSaveRequestDto(String title, String content, String author) {
this.title = title;
this.content = content;
this.author = author;
}
//DTO -> Posts Entity๋ก
public Posts toEntity()
{
return Posts.builder()
.title(title)
.content(content)
.author(author)
.build();
}
}
๐ ๋ฑ๋ก ํ ์คํธ
JPA ๊ธฐ๋ฅ๊น์ง ํ๋ฒ์ ํ ์คํธํ ๋์๋ @SpringBootTest ์ @TestRestTemplate๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค๊ณ ํ๋ค.
Random port๋ฅผ ์์ฑํ์ฌ ๋ด์ฅ ํฐ์บฃ์ ์ฌ์ฉํ์ฌ ํ ์คํธ๋ฅผ ์งํ
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class PostApiControllerTest {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate testRestTemplate;
@Autowired
private PostsRepository postsRepository;
@After
public void teardown() throws Exception{
postsRepository.deleteAll();
}
@Test
public void Posts_๋ฑ๋ก๋๋ค() throws Exception{
//given
String title ="title";
String content ="content";
PostSaveRequestDto postSaveRequestDto= PostSaveRequestDto.builder()
.title(title)
.content(content)
.author("author")
.build();
String url="http://localhost:" + port + "/api/v1/posts";
//when
ResponseEntity<Long> responseEntity = testRestTemplate.postForEntity(url, postSaveRequestDto, Long.class);
//then
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(responseEntity.getBody()).isGreaterThan(0L);
List<Posts> postsList = postsRepository.findAll();
assertThat(postsList.get(0).getTitle()).isEqualTo(title);
assertThat(postsList.get(0).getContent()).isEqualTo(content);
}
}
๐ @SpringBootTest(webEnvironment=SpringBootTest.webEnvironment.RANDOM_PORT)
๐ @LocalServerPort
๐ @TestRestTemplate
๐ restTemplate.postForEntity( ์์ฒญ ๋ณด๋ผ url, ๋ณด๋ผ ๊ฐ์ฒด, ๋ฐ์์ฌ ํ์ ์ class)
๐ responseEntity.getBody()
์์ ๊ณผ ์กฐํ์ ๋ํ ๋ถ๋ถ์
update ๋ถ๋ถ ํ ์คํธ ์ฝ๋ ์์ฑํ ๋ถ๋ถ์์ ๋ณด๊ณ ๋์ด๊ฐ์ผ ํ ๋ถ๋ถ์ด ์์ด์ ๊ทธ ๋ถ๋ถ๋ง ์ ๋ฆฌํด๋๋ ค๊ณ ํ๋ค.
๐์์ ํ ์คํธ ์ฝ๋
@Test
public void Posts_์์ ๋๋ค() throws Exception{
//given
Posts posts= postsRepository.save(Posts.builder()
.title("title")
.content("content")
.author("author")
.build());
Long updateId=posts.getId();
PostsUpdateRequestDto requestDto =PostsUpdateRequestDto.builder()
.title("fixed_title")
.content("fixed_content")
.build();
String url="http://localhost:"+ port +"/api/v1/posts/"+ updateId;
HttpEntity<PostsUpdateRequestDto> requestEntity = new HttpEntity<>(requestDto);
//when
ResponseEntity<Long> responseEntity = testRestTemplate.exchange(url, HttpMethod.PUT, requestEntity, Long.class);
//then
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(responseEntity.getBody()).isGreaterThan(0L);
List<Posts> postsList = postsRepository.findAll();
assertThat(postsList.get(0).getTitle()).isEqualTo(requestDto.getTitle());
assertThat(postsList.get(0).getContent()).isEqualTo(requestDto.getContent());
}
๐ new HttpEntity<>( )
๐ restTemplate.exchange(url, HttpMethod.PUT, HttpEntity๋ก ๊ฐ์ธ์ง ๊ฐ์ฒด, ๋ฐํํ์ )