Add a way to signal that an endpoint request is invalid

This commit adds InvalidEndpointRequestException as a technology
agnostic way to signal that an endpoint request is invalid. When such
exception is thrown, the web layer translates that to a 400.

Rather than overriding the reason, this commit makes sure to reuse the
error infrastructure.

Closes gh-10618
This commit is contained in:
Stephane Nicoll
2018-01-23 14:57:13 +01:00
parent 55c8ceb440
commit 1f4a32f0ad
11 changed files with 126 additions and 32 deletions

View File

@@ -42,6 +42,7 @@ import org.springframework.context.annotation.Import;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.test.web.reactive.server.WebTestClient;
@@ -157,8 +158,13 @@ public abstract class AbstractWebEndpointIntegrationTests<T extends Configurable
@Test
public void readOperationWithMappingFailureProducesBadRequestResponse() {
load(QueryEndpointConfiguration.class, (client) -> client.get()
.uri("/query?two=two").exchange().expectStatus().isBadRequest());
load(QueryEndpointConfiguration.class, (client) -> {
WebTestClient.BodyContentSpec body = client.get()
.uri("/query?two=two").exchange().expectStatus().isBadRequest()
.expectBody();
validateErrorBody(body, HttpStatus.BAD_REQUEST, "/endpoints/query",
"Missing parameters: one");
});
}
@Test
@@ -275,8 +281,13 @@ public abstract class AbstractWebEndpointIntegrationTests<T extends Configurable
@Test
public void readOperationWithMissingRequiredParametersReturnsBadRequestResponse() {
load(RequiredParameterEndpointConfiguration.class, (client) -> client.get()
.uri("/requiredparameters").exchange().expectStatus().isBadRequest());
load(RequiredParameterEndpointConfiguration.class, (client) -> {
WebTestClient.BodyContentSpec body = client.get()
.uri("/requiredparameters").exchange().expectStatus().isBadRequest()
.expectBody();
validateErrorBody(body, HttpStatus.BAD_REQUEST,
"/endpoints/requiredparameters", "Missing parameters: foo");
});
}
@Test
@@ -321,6 +332,14 @@ public abstract class AbstractWebEndpointIntegrationTests<T extends Configurable
protected abstract int getPort(T context);
protected void validateErrorBody(WebTestClient.BodyContentSpec body,
HttpStatus status, String path, String message) {
body.jsonPath("status").isEqualTo(status.value())
.jsonPath("error").isEqualTo(status.getReasonPhrase())
.jsonPath("path").isEqualTo(path)
.jsonPath("message").isEqualTo(message);
}
private void load(Class<?> configuration,
BiConsumer<ApplicationContext, WebTestClient> consumer) {
load(configuration, "/endpoints", consumer);

View File

@@ -37,6 +37,8 @@ import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebSe
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus;
import org.springframework.test.web.reactive.server.WebTestClient;
/**
* Integration tests for web endpoints exposed using Jersey.
@@ -64,6 +66,12 @@ public class JerseyWebEndpointIntegrationTests extends
return context.getWebServer().getPort();
}
@Override
protected void validateErrorBody(WebTestClient.BodyContentSpec body,
HttpStatus status, String path, String message) {
// Jersey doesn't support the general error page handling
}
@Configuration
static class JerseyConfiguration {

View File

@@ -23,6 +23,8 @@ import org.junit.Test;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.annotation.AbstractWebEndpointIntegrationTests;
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration;
import org.springframework.boot.endpoint.web.EndpointMapping;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
@@ -95,6 +97,7 @@ public class WebFluxEndpointIntegrationTests
@Configuration
@EnableWebFlux
@ImportAutoConfiguration(ErrorWebFluxAutoConfiguration.class)
static class ReactiveConfiguration {
private int port;

View File

@@ -23,6 +23,13 @@ import org.junit.Test;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.annotation.AbstractWebEndpointIntegrationTests;
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration;
import org.springframework.boot.endpoint.web.EndpointMapping;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
@@ -32,8 +39,6 @@ import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import static org.assertj.core.api.Assertions.assertThat;
@@ -89,7 +94,10 @@ public class MvcWebEndpointIntegrationTests extends
}
@Configuration
@EnableWebMvc
@ImportAutoConfiguration({ JacksonAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
ServletWebServerFactoryAutoConfiguration.class, WebMvcAutoConfiguration.class,
DispatcherServletAutoConfiguration.class, ErrorMvcAutoConfiguration.class })
static class WebMvcConfiguration {
@Bean
@@ -97,11 +105,6 @@ public class MvcWebEndpointIntegrationTests extends
return new TomcatServletWebServerFactory(0);
}
@Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
@Bean
public WebMvcEndpointHandlerMapping webEndpointHandlerMapping(
Environment environment, WebEndpointDiscoverer endpointDiscoverer,