티스토리 뷰

Spring

Restful API 버전관리

SonSeungWoo 2019. 10. 25. 17:30

여태까지 버전관리를 할 일이 없었다. 외부에 api를 제공 할 일이 없고 회사내부에서만 작업을 하다보니...그런데 이번에 외부에 api를 제공하게 되면서 api 문서도 제공하였다. 근데 여러군데에 제공하다보니 version관리가 불가피 하게 되었다. 그래서 어떻게 할까 하다 좋은 예제가 있어 글로 작성해본다.

 

먼저 version어노테이션을 아래와 같이 작성한다. v1, v2등 여러 버전을 맵핑할 수있게 하기 위해서  value는 배열로선언했다.

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Version {
    double[] value();
}

 

Controller와 url을 매핑시켜주는 HandlerMapping의 구현클래스인 RequestMappingHandlerMapping를 재정의 한 코드이다. RequestMappingInfo는 @GetMapping 등 모든 컨트롤러의 mapping URI정보를 가지고 있다. 그리고 위에서 선언한 @Version 어노테이션이 있는지 여부를 판단하고 @Version value를 가져와 Version을 일반적인 요청 매핑과 연결해준다.

public class ApiVersionRequestMappingHandlerMapping extends RequestMappingHandlerMapping {

    private final String prefix;

    public ApiVersionRequestMappingHandlerMapping(String prefix) {
        this.prefix = prefix;
    }

    @Override
    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        RequestMappingInfo info = super.getMappingForMethod(method, handlerType);
        if (info == null) return null;

        Version methodAnnotation = AnnotationUtils.findAnnotation(method, Version.class);
        if (methodAnnotation != null) {
            RequestCondition<?> methodCondition = getCustomMethodCondition(method);
            // Concatenate our ApiVersion with the usual request mapping
            info = createApiVersionInfo(methodAnnotation, methodCondition).combine(info);
        } else {
            Version typeAnnotation = AnnotationUtils.findAnnotation(handlerType, Version.class);
            if (typeAnnotation != null) {
                RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType);
                // Concatenate our ApiVersion with the usual request mapping
                info = createApiVersionInfo(typeAnnotation, typeCondition).combine(info);
            }
        }

        return info;
    }

    private RequestMappingInfo createApiVersionInfo(Version annotation, RequestCondition<?> customCondition) {
        double[] values = annotation.value();
        String[] patterns = new String[values.length];
        for (int i = 0; i < values.length; i++) {
            // Build the URL prefix
            patterns[i] = prefix + values[i];
        }

        return new RequestMappingInfo(
                new PatternsRequestCondition(patterns, getUrlPathHelper(), getPathMatcher(), useSuffixPatternMatch(), useTrailingSlashMatch(), getFileExtensions()),
                new RequestMethodsRequestCondition(),
                new ParamsRequestCondition(),
                new HeadersRequestCondition(),
                new ConsumesRequestCondition(),
                new ProducesRequestCondition(),
                customCondition);
    }

}

 

Spring MVC가 제공하는 기본 컴포넌트 대신 WebMvcConfigurationSupport의 주요 컴포넌트를 등록하기위한 인터페이스 WebMvcRegistrations이다. Spring MVC가 제공하는 기본 컴포넌트 관한건 여기를 참고하면 될거 같다. WebMvcRegistrations빈으로 등록하고 커스텀 ApiVersionRequestMappingHandlerMapping를 리턴해주자.

@Configuration
public class CustomRequestMappingHandlerMapping {
    @Bean
    public WebMvcRegistrations webMvcRegistrations() {
        return new WebMvcRegistrations() {
            @Override
            public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
                return new ApiVersionRequestMappingHandlerMapping("v");
            }
        };
    }
}

 

간단한 테스트 controller이다. localhost:8080/v1/entity, localhost:8080/v1.1/entity 이 두개 요청모두를 잘 매핑한다.

    @Version({1,1.1})
    @GetMapping("/entity")
    public ResponseEntity findByVersion(HttpServletRequest request) {
        log.info("request URI {}:", request.getRequestURI());
        return ResponseEntity.ok(request.getRequestURI());
    }

 

출처

'Spring' 카테고리의 다른 글

Spring ApplicationEvent  (0) 2019.10.10
HandlerMethodArgumentResolver  (0) 2019.10.02
IoC란  (0) 2019.04.24
Spring Aop  (0) 2019.04.23
스프링에서 @Async로 비동기처리하기  (0) 2017.04.21
공지사항
최근에 올라온 글
최근에 달린 댓글
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함