Prepare to support API versioning for fn
Add default method to resolve, parse, and validate version Simplify tests
This commit is contained in:
parent
d045f44693
commit
224f1af08e
|
@ -62,6 +62,27 @@ public interface ApiVersionStrategy {
|
|||
*/
|
||||
@Nullable Comparable<?> getDefaultVersion();
|
||||
|
||||
/**
|
||||
* Convenience method to return the parsed and validated request version,
|
||||
* or the default version if configured.
|
||||
* @param request the current request
|
||||
* @return the parsed request version, or the default version
|
||||
*/
|
||||
default @Nullable Comparable<?> resolveParseAndValidateVersion(HttpServletRequest request) {
|
||||
String value = resolveVersion(request);
|
||||
if (value == null) {
|
||||
return getDefaultVersion();
|
||||
}
|
||||
try {
|
||||
Comparable<?> version = parseVersion(value);
|
||||
validateVersion(version, request);
|
||||
return version;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new InvalidApiVersionException(value, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the requested API version is deprecated, and if so handle it
|
||||
* accordingly, e.g. by setting response headers to signal the deprecation,
|
||||
|
|
|
@ -64,6 +64,27 @@ public interface ApiVersionStrategy {
|
|||
*/
|
||||
@Nullable Comparable<?> getDefaultVersion();
|
||||
|
||||
/**
|
||||
* Convenience method to return the parsed and validated request version,
|
||||
* or the default version if configured.
|
||||
* @param exchange the current exchange
|
||||
* @return the parsed request version, or the default version
|
||||
*/
|
||||
default @Nullable Comparable<?> resolveParseAndValidateVersion(ServerWebExchange exchange) {
|
||||
String value = resolveVersion(exchange);
|
||||
if (value == null) {
|
||||
return getDefaultVersion();
|
||||
}
|
||||
try {
|
||||
Comparable<?> version = parseVersion(value);
|
||||
validateVersion(version, exchange);
|
||||
return version;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new InvalidApiVersionException(value, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the requested API version is deprecated, and if so handle it
|
||||
* accordingly, e.g. by setting response headers to signal the deprecation,
|
||||
|
|
|
@ -93,6 +93,16 @@ public class DefaultApiVersionStrategy implements ApiVersionStrategy {
|
|||
return this.defaultVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the strategy is configured to detect supported versions.
|
||||
* If this is set to {@code false} then {@link #addMappedVersion} is ignored
|
||||
* and the list of supported versions can be built explicitly through calls
|
||||
* to {@link #addSupportedVersion}.
|
||||
*/
|
||||
public boolean detectSupportedVersions() {
|
||||
return this.detectSupportedVersions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add to the list of supported versions to check against in
|
||||
* {@link ApiVersionStrategy#validateVersion} before raising
|
||||
|
|
|
@ -42,7 +42,6 @@ import org.springframework.util.Assert;
|
|||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.StringValueResolver;
|
||||
import org.springframework.web.accept.InvalidApiVersionException;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
@ -180,7 +179,7 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
|||
if (this.apiVersionStrategy != null) {
|
||||
Comparable<?> version = exchange.getAttribute(API_VERSION_ATTRIBUTE);
|
||||
if (version == null) {
|
||||
version = getApiVersion(exchange, this.apiVersionStrategy);
|
||||
version = this.apiVersionStrategy.resolveParseAndValidateVersion(exchange);
|
||||
if (version != null) {
|
||||
exchange.getAttributes().put(API_VERSION_ATTRIBUTE, version);
|
||||
}
|
||||
|
@ -189,21 +188,6 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
|||
return super.getHandlerInternal(exchange);
|
||||
}
|
||||
|
||||
private static @Nullable Comparable<?> getApiVersion(ServerWebExchange exchange, ApiVersionStrategy strategy) {
|
||||
String value = strategy.resolveVersion(exchange);
|
||||
if (value == null) {
|
||||
return strategy.getDefaultVersion();
|
||||
}
|
||||
try {
|
||||
Comparable<?> version = strategy.parseVersion(value);
|
||||
strategy.validateVersion(version, exchange);
|
||||
return version;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new InvalidApiVersionException(value, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses type-level and method-level {@link RequestMapping @RequestMapping}
|
||||
* and {@link HttpExchange @HttpExchange} annotations to create the
|
||||
|
|
|
@ -50,29 +50,24 @@ public class RequestMappingVersionIntegrationTests extends AbstractRequestMappin
|
|||
|
||||
|
||||
@ParameterizedHttpServerTest
|
||||
void initialVersion(HttpServer httpServer) throws Exception {
|
||||
void mapVersion(HttpServer httpServer) throws Exception {
|
||||
startServer(httpServer);
|
||||
|
||||
assertThat(exchangeWithVersion("1.0").getBody()).isEqualTo("none");
|
||||
assertThat(exchangeWithVersion("1.1").getBody()).isEqualTo("none");
|
||||
}
|
||||
|
||||
@ParameterizedHttpServerTest
|
||||
void baselineVersion(HttpServer httpServer) throws Exception {
|
||||
startServer(httpServer);
|
||||
assertThat(exchangeWithVersion("1.2").getBody()).isEqualTo("1.2");
|
||||
assertThat(exchangeWithVersion("1.3").getBody()).isEqualTo("1.2");
|
||||
}
|
||||
|
||||
@ParameterizedHttpServerTest
|
||||
void fixedVersion(HttpServer httpServer) throws Exception {
|
||||
startServer(httpServer);
|
||||
assertThat(exchangeWithVersion("1.5").getBody()).isEqualTo("1.5");
|
||||
assertThatThrownBy(() -> exchangeWithVersion("1.6")).isInstanceOf(HttpClientErrorException.BadRequest.class);
|
||||
|
||||
assertThatThrownBy(() -> exchangeWithVersion("1.6"))
|
||||
.as("Should reject if highest supported below request version is fixed")
|
||||
.isInstanceOf(HttpClientErrorException.BadRequest.class);
|
||||
}
|
||||
|
||||
@ParameterizedHttpServerTest
|
||||
void deprecation(HttpServer httpServer) throws Exception {
|
||||
startServer(httpServer);
|
||||
|
||||
assertThat(exchangeWithVersion("1").getHeaders().getFirst("Link"))
|
||||
.isEqualTo("<https://example.org/deprecation>; rel=\"deprecation\"; type=\"text/html\"");
|
||||
}
|
||||
|
|
|
@ -46,7 +46,6 @@ import org.springframework.util.StringValueResolver;
|
|||
import org.springframework.web.accept.ApiVersionStrategy;
|
||||
import org.springframework.web.accept.ContentNegotiationManager;
|
||||
import org.springframework.web.accept.DefaultApiVersionStrategy;
|
||||
import org.springframework.web.accept.InvalidApiVersionException;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
@ -207,7 +206,7 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
|||
if (this.apiVersionStrategy != null) {
|
||||
Comparable<?> version = (Comparable<?>) request.getAttribute(API_VERSION_ATTRIBUTE);
|
||||
if (version == null) {
|
||||
version = getApiVersion(request, this.apiVersionStrategy);
|
||||
version = this.apiVersionStrategy.resolveParseAndValidateVersion(request);
|
||||
if (version != null) {
|
||||
request.setAttribute(API_VERSION_ATTRIBUTE, version);
|
||||
}
|
||||
|
@ -216,21 +215,6 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
|||
return super.getHandlerInternal(request);
|
||||
}
|
||||
|
||||
private static @Nullable Comparable<?> getApiVersion(HttpServletRequest request, ApiVersionStrategy strategy) {
|
||||
String value = strategy.resolveVersion(request);
|
||||
if (value == null) {
|
||||
return strategy.getDefaultVersion();
|
||||
}
|
||||
try {
|
||||
Comparable<?> version = strategy.parseVersion(value);
|
||||
strategy.validateVersion(version, request);
|
||||
return version;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new InvalidApiVersionException(value, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses type-level and method-level {@link RequestMapping @RequestMapping}
|
||||
* and {@link HttpExchange @HttpExchange} annotations to create the
|
||||
|
|
|
@ -59,23 +59,17 @@ public class RequestMappingVersionHandlerMethodTests {
|
|||
|
||||
|
||||
@Test
|
||||
void initialVersion() throws Exception {
|
||||
void mapVersion() throws Exception {
|
||||
assertThat(requestWithVersion("1.0").getContentAsString()).isEqualTo("none");
|
||||
assertThat(requestWithVersion("1.1").getContentAsString()).isEqualTo("none");
|
||||
}
|
||||
|
||||
@Test
|
||||
void baselineVersion() throws Exception {
|
||||
assertThat(requestWithVersion("1.2").getContentAsString()).isEqualTo("1.2");
|
||||
assertThat(requestWithVersion("1.3").getContentAsString()).isEqualTo("1.2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fixedVersion() throws Exception {
|
||||
assertThat(requestWithVersion("1.5").getContentAsString()).isEqualTo("1.5");
|
||||
|
||||
MockHttpServletResponse response = requestWithVersion("1.6");
|
||||
assertThat(response.getStatus()).isEqualTo(400);
|
||||
assertThat(response.getStatus())
|
||||
.as("Should reject if highest supported below request version is fixed")
|
||||
.isEqualTo(400);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue