구리

[SpringBoot] REST API - Spring BOOT API 사용 본문

SPRING BOOT

[SpringBoot] REST API - Spring BOOT API 사용

guriguriguri 2021. 10. 10. 16:13

Rest API가 대충 어떤건지만 알고 정확한 개념이나 설계하는 법을 자세히 몰랐기에 인프런에서 들은 강의를 토대로 배운 내용을 정리한 것입니다. 참고로 강의는 Dowon Lee 님의 Spring Boot를 이용한 RESTful Web Services 개발 입니다.

 

<목차>

더보기

[Level3 단계의 REST API 구현을 위한 HATEOAS 적용]

[REST API Documentation을 위한 Swagger 사용]

[Swagger Documentation 구현 방법]

[REST API Monitoring을 위한 Actuator 설정]

[HAL Browser를 이용한 HATEOAS 기능 구현]

[Spring Security를 이용한 인증 처리]

[Configuration 클래스를 이용한 사용자 인증 처리]

 

[Level3 단계의 REST API 구현을 위한 HATEOAS 적용]

  • HATEOAS란?
    • Hypermedia As The Engine Of Application State의 약자로 기본적인 아이디어는 
    • 하이퍼미디어를 애플리케이션의 상태를 관리하기 위한 메커니즘으로 사용한다는 것
    • REST Api를 사용하는 클라이언트가 전적으로 서버와 동적인 상호작용이 가능하도록 하는 것을 의미
    • 클라이언트가 서버로부터 어떤 요청시, 요청에 필요한 URI를 응답에 포함시켜 반환하는 것으로 가능하게 할 수 있음
    • 현재 리소스 & 연관된 (호출 가능한)자원 상태 정보를 제공 -> 결국 하이퍼미디어 mapping

 

      • HATEOAS 장점
        • 요청 URI가 변경되더라도 클라이언트에서 동적으로 생성된 URI를 사용함으로써, 클라이언트가 URI 수정에 따른 코드를 변경하지 않아도 되는 편리함을 제공한다.
        • URI 정보를 통해 들어오는 요청을 예측할 수 있게 된다.
        • Resource가 포함된 URI를 보여주기 때문에, Resource에 대한 확신을 얻을 수 있다.

  • HATEOAS 구현 방법

(1) pom.xml에 디펜던시 추가

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>

(2) Controller 아래와 같이 코드 추가

//UserController
@GetMapping("/users/{id}")
    public Resource<User> retrieveUser(@PathVariable int id){
        User user = service.findOne(id);

        if(user == null){
            throw new UserNotFoundException(String.format("ID[%s] not found", id));
        }

        // HATEOAS
        Resource<User> resource = new Resource<>(user);
        
        // user 객체가 추가적으로 사용할 수 있는 정보(링크)를 하이퍼미디어 타입으로 넣기
        //import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; 
        //import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
        ControllerLinkBuilder linkTo = linkTo(methodOn(this.getClass()).retrieveAllUsers());
        
        // 특정 이름으로 링크에 설정
        resource.add(linkTo.withRel("all-user"));
        return resource;
    }

linkTo에 설정한 모든 사용자 조회 맵핑값, 설정된 이름으로 link와 특정 사용자가 같이 반환된 것을 볼 수 있다

 

 

[REST API Documentation을 위한 Swagger 사용]

  • Swagger란?
    • 개발자 도움말 페이지 생성 역할
  • Swagger 사용 방법

(1) pom.xml에 dependency 추가

<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger2</artifactId>
			<version>2.9.2</version>
		</dependency>

		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger-ui</artifactId>
			<version>2.9.2</version>
		</dependency>

스프링 부트 버전이 2.1.X가 아닌 2.4.X일 경우

더보기
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
    <version>3.0.0</version>
</dependency>

// 새로운 swagger 버전에서는 URI가 swagger-ui.html에서 swagger-ui/index.html로 변경 되었습니다.

(2) Swagger를 용도로 사용하는 Config class 생성

package com.example.restful.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
// 스웨거 용도로 사용하겠다는 어노테이션
public class SwaggerConfig {

    @Bean
    public Docket api(){
        return new Docket(DocumentationType.SWAGGER_2);
    }
}

아래의 링크로 확인해본다

  • http://localhost:8088/v2/api-docs
  • http://localhost:8088/swagger-ui.html

 

 

 

[Swagger Documentation Customizing]

  • SwaggerConfig 코드 수정
package com.example.restful.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    // 사용자 정보
    private static final Contact DEFALUT_CONTACT = new Contact(
            "Raccoon Baek", "http://www.raccoon96.co.kr","raccoon96@naver.com");

    // API 정보
    private static final ApiInfo DEFAULT_API_INFO = new ApiInfo(
            "Awesome API Title", "My User mamagement REST API service", "1.0", "urn:tos",
            DEFALUT_CONTACT, "Apache 2.0", "http://www.apache.org/licences/LICENCES-2.0", new ArrayList<>());
    
    // 문서 타입 지정
    private static final Set<String> DEFAULT_PRODUCES_AND_CONSUMES =
            new HashSet<>(Arrays.asList("application/json", "application/xml"));

    @Bean
    public Docket api(){
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(DEFAULT_API_INFO)
                .produces(DEFAULT_PRODUCES_AND_CONSUMES)
                .consumes(DEFAULT_PRODUCES_AND_CONSUMES);
    }
}

    User 코드 수정
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "사용자 상세 정보를 위한 도메인 객체")
public class User {
    private Integer id;

    @Size(min=2, message = "Name은 2글자 이상 입력해주세요.")
    @ApiModelProperty(notes = "사용자 이름을 입력해주세요")
    private String name;

    @Past
    @ApiModelProperty(notes = "사용자의 등록일을 입력해주세요")
    private Date joinDate;

    @ApiModelProperty(notes = "사용자의 패스워드를 입력해주세요")
    private String password;

    @ApiModelProperty(notes = "사용자의 주민번호를 입력해주세요")
    private String ssn;
}

 

 

[REST API Monitoring을 위한 Actuator 설정]

  • Actuator란?
    • 어플리케이션의 상태를 종합적으로 정리해 제공해주는 모듈로 SpringBoot 어플리케이션의 상태를 관리
  • 설정 방법

(1) pom.xml dependency 추가

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>

(2) http://localhost:8088/actuator 확인

 

서버 상태 작동중

(3) application.yml 코드 작성 -> 더 많은 정보를 얻고 싶을 때

# Actuator 설정 -> 더 많은 정보 보기 
# health와 metrics 정보만 노출할 때에는 
# management.endpoints.web.exposure.include=health,metrics 

management: 
	endpoints: 
    	web: 
        	exposure: 
            	include: "*"

 

 

[HAL Browser를 이용한 HATEOAS 기능 구현]

  • HAL(Hypertext Application Language) Browser란?
    • REST API 설계시 Response 메시지에 부가 정보들을 담아서 함께 제공하는 방식
    • 즉, HAL을 API Response 메시지에 적용하면 그 메시지가 JSON 포맷이건 XML 포맷이건 API를 쉽게 찾을 수 있는 메타 정보들을 포함시킬 수 있다는 것

(1) pom.xml에 dependency 추가

<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-rest-hal-browser</artifactId>
</dependency>

(2) http://localhost:8088/

HAL Browser에서 위 링크로 테스트
http://localhost:8088/actuator/metrics 검색시 결과

 

 

 

[Spring Security를 이용한 인증 처리]

  • Spring Security를 통해 자동으로 생성되는 password로 간단한 인증처리 구현

(1) pom.xml에 dependency 추가

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
</dependency>

(2) 웹 서비스 호출을 위해 자동으로 생성된 password 복사

(3) 웹 브라우저 요청시 오류 발생 -> 인증되지 않은 사용자 (401 unauthorized)

(4) 발급받은 비밀번호, id 입력후 재요청시 정상 결과 출력 (200 status)

 

 

 

[Configuration 클래스를 이용한 사용자 인증 처리]

  • 개발자가 지정한 id, password로 간단한 인증처리 구현 방법 2가지

1. application.yml 파일에 고정적인 id, password 부여

  • 가변적이지 않기에 정보가 바뀔 때마다 수정해야 하는 번거로움이 있음
spring:
  security:
    user:
      name: username
      password: password12

2. Configuration class 생성하여 id, password 부여

package com.example.restful.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth)
        throws Exception {
        auth.inMemoryAuthentication()
                .withUser("raccoon")
                .password("{noop}test12")   // noop : 어떤 인코딩도 없이 사용할 수 있는 no operation
                .roles("USER");
    }
}

위와 같이 configuration class 생성하여 지정하게 되면 appilcation.yml에 설정한 id, password로는 인증할 수 없음