완벽 하게 처리하는 솔루션을 구현했습니다.나머지 버전 관리 문제를 .
일반 말하기 나머지 버전 관리에는 세 가지 주요 접근 방식이 있습니다.
클라이언트가 URL에서 버전을 정의하는 경로 기반 접근 방식 :
http://localhost:9001/api/v1/user
http://localhost:9001/api/v2/user
클라이언트가 Accept 헤더 의 버전을 정의하는 Content-Type 헤더 :
http://localhost:9001/api/v1/user with
Accept: application/vnd.app-1.0+json OR application/vnd.app-2.0+json
사용자 지정 헤더 클라이언트가 사용자 정의 헤더의 버전을 정의하는.
문제 와 첫 번째 방법은 당신이 버전을 변경하는 경우의가 V1에서 생각한 것입니다 -> V2, 아마 당신은 v2의 경로로 변경되지 않은 V1 자원을 복사하여 붙여 넣어야
문제 와 두 번째 방법은 같은 몇 가지 도구입니다 http://swagger.io/ 동일한 경로하지만 서로 다른 내용 유형 (체크 문제와 작업 사이 수 구별하지 https://github.com/OAI/OpenAPI-Specification/issues/ 146 )
해결책
나머지 문서화 도구를 많이 사용하고 있으므로 첫 번째 접근 방식을 선호합니다. 내 솔루션 은 첫 번째 접근 방식으로 문제 를 처리 하므로 엔드 포인트를 새 버전에 복사하여 붙여 넣을 필요가 없습니다.
사용자 컨트롤러 용 v1 및 v2 버전이 있다고 가정 해 보겠습니다.
package com.mspapant.example.restVersion.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* The user controller.
*
* @author : Manos Papantonakos on 19/8/2016.
*/
@Controller
@Api(value = "user", description = "Operations about users")
public class UserController {
/**
* Return the user.
*
* @return the user
*/
@ResponseBody
@RequestMapping(method = RequestMethod.GET, value = "/api/v1/user")
@ApiOperation(value = "Returns user", notes = "Returns the user", tags = {"GET", "User"})
public String getUserV1() {
return "User V1";
}
/**
* Return the user.
*
* @return the user
*/
@ResponseBody
@RequestMapping(method = RequestMethod.GET, value = "/api/v2/user")
@ApiOperation(value = "Returns user", notes = "Returns the user", tags = {"GET", "User"})
public String getUserV2() {
return "User V2";
}
}
요구 사항은 내가 요청하는 경우이다 V1 내가 가지고 가야 사용자 리소스에 대해 "사용자 V1" 내가 요청 그렇지 않은 경우, repsonse을 V2 , V3를 그래서 내가 가지고 가야에서 "사용자 V2" 응답을.
이를 봄에 구현하려면 기본 RequestMappingHandlerMapping 동작 을 재정의해야합니다 .
package com.mspapant.example.restVersion.conf.mapping;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class VersionRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
@Value("${server.apiContext}")
private String apiContext;
@Value("${server.versionContext}")
private String versionContext;
@Override
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
HandlerMethod method = super.lookupHandlerMethod(lookupPath, request);
if (method == null && lookupPath.contains(getApiAndVersionContext())) {
String afterAPIURL = lookupPath.substring(lookupPath.indexOf(getApiAndVersionContext()) + getApiAndVersionContext().length());
String version = afterAPIURL.substring(0, afterAPIURL.indexOf("/"));
String path = afterAPIURL.substring(version.length() + 1);
int previousVersion = getPreviousVersion(version);
if (previousVersion != 0) {
lookupPath = getApiAndVersionContext() + previousVersion + "/" + path;
final String lookupFinal = lookupPath;
return lookupHandlerMethod(lookupPath, new HttpServletRequestWrapper(request) {
@Override
public String getRequestURI() {
return lookupFinal;
}
@Override
public String getServletPath() {
return lookupFinal;
}});
}
}
return method;
}
private String getApiAndVersionContext() {
return "/" + apiContext + "/" + versionContext;
}
private int getPreviousVersion(final String version) {
return new Integer(version) - 1 ;
}
}
구현은 URL에서 버전을 읽고 URL을 확인하기 위해 봄부터 요청합니다.이 URL이 존재하지 않는 경우 (예 : 클라이언트가 v3 요청 ) v2로 시도 하고 리소스에 대한 최신 버전 을 찾을 때까지 하나를 시도 합니다. .
이 구현의 이점을 확인하기 위해 사용자와 회사의 두 가지 리소스가 있다고 가정 해 보겠습니다.
http://localhost:9001/api/v{version}/user
http://localhost:9001/api/v{version}/company
고객을 파기하는 회사 "계약"을 변경했다고 가정 해 보겠습니다. 그래서 우리는를 구현하고 http://localhost:9001/api/v2/company
클라이언트에서 v1 대신 v2로 변경하도록 요청합니다.
따라서 클라이언트의 새로운 요청은 다음과 같습니다.
http://localhost:9001/api/v2/user
http://localhost:9001/api/v2/company
대신에:
http://localhost:9001/api/v1/user
http://localhost:9001/api/v1/company
여기서 가장 좋은 점은이 솔루션을 사용하면 클라이언트가 사용자 v2에서 새 (동일한) 엔드 포인트를 만들 필요없이 v1에서 사용자 정보를 가져오고 v2에서 회사 정보를 얻을 수 있다는 것입니다 !
나머지 문서화
내가 URL 기반 버전 관리 방식을 선택한 이유 전에 말했듯이 swagger와 같은 일부 도구는 동일한 URL을 사용하지만 콘텐츠 유형이 다른 엔드 포인트를 다르게 문서화하지 않기 때문입니다. 이 솔루션을 사용하면 URL이 다르기 때문에 두 끝 점이 표시됩니다.
GIT
솔루션 구현 :
https://github.com/mspapant/restVersioningExample/