본문 바로가기
스프링 부트 3으로 백엔드 입문하기

6장 API 만들기

by hoshi03 2023. 11. 23.

• API와 REST API

API

 

식당을 예시로 들면

손님(클라인언트) - 점원(API) - 주방(서버)의 관계에서

클라이언트의 요청을 서버에 전달하고, 서버의 결과물을 클라이언트에게 돌려주는 역할을 한다

 

REST API

 

URL의 설계 방식이다

URL만 보고도 어떤 행동을 하는 api인지 알수 있게 한다

 

rest api 규칙

restful 한 api를 만들기 위해서 동사를 url에 쓰지 않는다

동사는 http의 post, get, put, delete 메서드로 사용한다

 

• 블로그 개발을 위한 엔티티 구성

id, title, content를 가지는 엔티티 만들기

 

생성자, 게터를 롬복을 사용하면 편리하다!

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Article {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", updatable = false)
    private Long id;

    @Column(name = "title", nullable = false)
    private  String title;

    @Column(name = "content", nullable = false)
    private  String content;

    @Builder
    public Article(String title, String content){
        this.title = title;
        this.content = content;
    }
}

 

 

• 빌더 패턴

 

@Builder 어노테이션은 빌더 패턴을 사용하는 어노테이션이다

빌더 패턴을 사용하면 어느 필드에 어떤 값이 들어가는지 명시할 수 있다

 

아래 코드는 어떤 필드에 어떤 값을 사용했는지 명시되어있지 않다

new Artice("abc","efg");

 

아래 코드는 어떤 필드에 어떤 값을 넣는지 명시적으로 작성해 이해하기가 훨씬 편하다

Article.builder()
    .title("abc")
    .content("def")
    .build();

 

리포지토리 만들기

public interface BlogRepository extends JpaRepository<Article, Long> {
}

 

Artitcle 엔티티와 pk 타입인 long을 넣어준 리포지토리를 작성한다

 

블로그 작성을 위한 api 구현하기

서비스 메서드 코드 작성하기

 

• dto 패키지에 컨트롤러에서 요청을 받을 AddArticleRequest 객체를 생성한다

 

dto란?

 

dto는 각 계층끼리 데이터를 교환하기 위해서 사용하는 객체다 앞에서 사용한 dao는 db와 직접 연결되고

데이터를 조회, 수정하기에 조회, 수정 로직이 있지만  dto는 별도의 비즈니스 로직이 없다

 

AddArticleRequest 클래스의 toEntitiy는 빌더 패턴을 사용해 dto를 엔티티로 만들어준다

@NoArgsConstructor
@AllArgsConstructor
@Getter
public class AddArticleRequest {
    private String title;
    private String content;

    public Article toEntity(){
        return Article.builder()
                .title(title)
                .content(content)
                .build();
    }
}

 

 

• service 패키지에 BlogService 클래스를 작성한다

@RequiredArgsConstructor // final 이나 널이 아닌 필드의 생성자를 추가한다
@Service
public class BlogService {

    private final BlogRepository blogRepository;

    // 블로그에 글 추가하기
    public Article save(AddArticleRequest request){
        return blogRepository.save(request.toEntity());
    }
}

 

컨트롤러 메서드 코드 작성하기

 

컨트롤러 메서드에서는 http 메서드에 대응하는 URL 매핑 어노테이션을(GetMapping , PostMapping등등)을 사용한다

BlogApiController는 요청을 매핑해서 글을 생성하고 생성된 글을 반환한다

@RequiredArgsConstructor
@RestController
public class BlogApiController {
    private final BlogService blogService;

    @PostMapping("/api/articles")
    public ResponseEntity<Article> addArticle(@RequestBody AddArticleRequest request){
        Article savedArticle = blogService.save(request);
        return ResponseEntity.status(HttpStatus.CREATED).body(savedArticle);
    }
}

 

@RequserBody 어노테이션은 응답으로 오는 값을 @RequestBody 어노테이션이 붙은 대상 객체에 매핑한다

여기서는 AddArticleRequest에 매핑해서 created 응답하고 테이블에 저장한 객체인 savedArticle을 반환한다

 

API 실행 확인하기

postman에서 실행해보자

응답은 잘 온거 같고 

 

h2에서 확인해보자

http://localhost:8080/h2-console 에 접속해 아래처럼 해서 connect 하면 db에 접속할 수 있다!

 

테스트 코드 작성

 

위에서 h2 콘솔에서 확인하는 방법을 매번 하는건 끔찍하다

테스트 코드를 작성해서 테스트하자

 

@SpringBootTest
@AutoConfigureMockMvc
class BlogApiControllerTest {

    @Autowired
    protected MockMvc mockMvc;

    @Autowired
    protected ObjectMapper objectMapper;

    @Autowired
    private WebApplicationContext context;

    @Autowired
    BlogRepository blogRepository;

    @BeforeEach
    public void mockMvcSetUp() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(context)
                .build();
        blogRepository.deleteAll();
    }


    @DisplayName("findArticle: 블로그 글 조회에 성공한다.")
    @Test
    public void findArticle() throws Exception {
        // given
        final String url = "/api/articles";
        final String title = "title";
        final String content = "content";
        final AddArticleRequest userRequest = new AddArticleRequest(title,content);

        //json 직력화
        final String requestBody = objectMapper.writeValueAsString(userRequest);

        // when
        ResultActions result = mockMvc.perform(post(url)
                .contentType(MediaType.APPLICATION_JSON_VALUE)
                        .content(requestBody));

        // then
        result.andExpect(status().isCreated());

        List<Article> articles = blogRepository.findAll();

        assertThat(articles.size()).isEqualTo(1);
        assertThat(articles.get(0).getTitle()).isEqualTo(title);
        assertThat(articles.get(0).getContent()).isEqualTo(content);
    }
}

 

 

writeValueAsString을 사용하면 객체를 json으로 직렬화해주고

그 다음부터는 MockMvc를 사용해 메서드, url, 본문, 타입을 설정해서 테스트한다

 

글 목록 조회 API 구현하기

147p부터 이어서 보고 작성하자