본문 바로가기
개발/Spring

[Spring] 간단한 Rest API 만들어보기

by tempus 2021. 9. 27.
반응형

최근에 업무상 필요한 API를 만들게 되었습니다. API 자체는 간단히 조회를 통해서 특정 주문 데이터를 가져오는 것인데 문제는 Spring에 대해서는 완전 기초적인 것만 알고 있는 상태였습니다. 이번에 API를 만들면서 배웠던 것들을 정리하려고 합니다.

 

개발 환경은 다음과 같았습니다.

  • Spring Boot
  • Hibernate
  • Swagger
  • PostgreSQL
  • AWS

 

저는 Spring MVC Architecture에 맞게 Controller, Service, Repository 작업만 하면 되었습니다. API 동작 여부는 Swagger가 있어서 Swagger를 통해서 데이터가 제대로 들어오는지 확인하였습니다.

 

🔰 ApiController.java

@RequestMapping(value = "/getOneItem", method = RequestMethod.POST)
public ResponseEntity getOneItem(@RequestHeader(name = "param1", defaultValue = "") String param1,    
                                 @RequestHeader(name = "param2", defaultValue = "") String param2,     
                                 @RequestHeader(name = "param3", defaultValue = "") String param3){
    logger.info("param1 : " + param1 + "....");
    return ResponseEntity.ok(ApiService.getOneItem(param1, param2, param3));
}

일단 ResponseEntity는 처음 보기에 무엇인지 찾아보았습니다.

 

ResponseEntity는 Spring Framework에서 제공하는 클래스 중 HttpEntity를 상속받아 구현한 클래스입니다. 해당 객체는 HTTP 응답을 빠르게 만들어주기 위해 사용한다고 합니다. 이 객체를 사용하면 응답으로 변환될 정보를 모두 담은 요소들을 객체로 만들어 반환해준다고 합니다. 그리고 ResponseEntity를 사용 시, 숫자로 된 상태 코드를 넣을 때 실수를 할 수 있기 때문에 Constructor 보다는 Builder를 활용하기를 권장하고 있습니다.

 

log4j를 통해서 로그를 남기게 하였습니다.

 

🔰 ApiService.java

@Transactional
public Item getOneItem(String param1, String param2, String param3){

    List<Item> items = ApiRepository.findAllByParam1AndParam2(param1, param2);

    SimpleDateFormat dateForm = new SimpleDateFormat("yyMMdd");
    Date now = new Date();

    return items.stream()
         	.filter(s -> s.getDate().contains(dateForm.format(now)))
            .filter(s-> s.getNum().substring(0,s.getNum().length() - 16).substring(6).equals(param3))
            .findFirst()
            .orElse(null);
}

@Transactional은 Spring에서 JPA기술을 쓸 때 다음과 같은 이점이 있어 사용한다고 합니다.

 

  • transaction begin, commit을 자동 수행
  • 예외를 발생시키면, rollback처리를 자동 수행

 

이를 통해 많은 보일러 코드를 줄일 수 있다고 합니다.

 

Query에서 like 구문을 사용하면 느려지는 경우가 있다고 하여 데이터를 가져오고 filter를 통해 원하는 데이터를 가져오는 방식을 사용했습니다.

 

Debug 시 filter 후 중간 값을 확인할 수가 없어서 아래와 같이 peek() 함수를 사용해서 확인했습니다.

return items.stream()
            .filter(s -> s.getDate().contains(dateForm.format(now)))
            .peek(s -> System.out.println(s.getNum() + " " + s.getParam()))

 

🔰 ApiRepository.java

@Query(value="SELECT " +
        "\"I\".* " +
        "FROM " +
        "\"default$default\".\"Items\" AS \"I\" " +
        "WHERE \"I\".\"param1\" = ?1 " +
        "AND \"I\".\"param2\" = ?2 ", nativeQuery = true)
List<Item> findAllByParam1AndParam2(String param1, String param2);

일단 Repository를 통해 DB에 접근하여 데이터를 가져오는 것은 알고 있었지만 정확히 사용법을 몰랐는데 이번 기회에 어떤 방식으로 데이터를 조회하고 가져오는지 알게 되었습니다.

 

@Query annotation을 통해서 쿼리문을 작성하고 return 값으로 List<Item>을 받습니다. 처음에 매개변수를 어떻게 사용할까? 고민을 했는데 ? + 순번으로 사용한다는 것을 알았습니다. 예를 들어 첫 번째 파라미터를 쿼리문에 사용하겠다고 하면 ?1라고 쓰면 됩니다. 여기서는 ?1 => param1이 될 것입니다.

 

그리고 Native Query를 사용하기 위해 nativeQuery = true를 사용해야 합니다. 일반적으로 대용량 데이터를 처리할 때 Native Query를 사용하는 게 더 좋다고 합니다. Native Query는 사용하는 DB engine에 맞는 SQL문으로 작성을 하면 됩니다.

 

반응형

댓글


loading