Skip to content

Commit

Permalink
feat: modify the request method in v4
Browse files Browse the repository at this point in the history
This policy has been migrated for V4 engine but remains backward
compatible with V3 engine.

BREAKING CHANGE:
Requires APIM 3.20 minimum because it requires RxJava3.
With V4 Api definition, the request's method is directly overridden.
  • Loading branch information
ytvnr committed Jan 13, 2023
1 parent 7e63724 commit e80114a
Show file tree
Hide file tree
Showing 12 changed files with 354 additions and 50 deletions.
18 changes: 18 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ endif::[]

== Phase

=== V3 engine

[cols="2*", options="header"]
|===
^|onRequest
Expand All @@ -19,6 +21,21 @@ endif::[]

|===

=== V4 engine

[cols="4*", options="header"]
|===
^|onRequest
^|onResponse
^|onMessageRequest
^|onMessageResponse

^.^| X
^.^|
^.^|
^.^|
|===

== Description

You can use the `override-http-method` policy to override the HTTP method provided by the initial consumer with a new
Expand All @@ -30,6 +47,7 @@ configured value when the inbound request is sent to the backend API.
|Plugin version | APIM version

| Up to 1.x | All
| Up to 2.x | 3.21+
|===

== Configuration
Expand Down
30 changes: 24 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@
<parent>
<groupId>io.gravitee</groupId>
<artifactId>gravitee-parent</artifactId>
<version>20.2</version>
<version>20.5</version>
</parent>

<properties>
<gravitee-apim-gateway-tests-sdk.version>3.18.0-SNAPSHOT</gravitee-apim-gateway-tests-sdk.version>
<gravitee-bom.version>2.5</gravitee-bom.version>
<gravitee-gateway-api.version>1.32.2</gravitee-gateway-api.version>
<gravitee-apim-gateway-tests-sdk.version>3.21.0-SNAPSHOT</gravitee-apim-gateway-tests-sdk.version>
<gravitee-bom.version>3.0.0</gravitee-bom.version>
<gravitee-gateway-api.version>2.1.0-alpha.6</gravitee-gateway-api.version>
<gravitee-policy-api.version>1.11.0</gravitee-policy-api.version>
<json-schema-generator-maven-plugin.version>1.1.0</json-schema-generator-maven-plugin.version>
<json-schema-generator-maven-plugin.outputDirectory>${project.build.directory}/schemas</json-schema-generator-maven-plugin.outputDirectory>
Expand Down Expand Up @@ -98,8 +98,14 @@

<!-- Test scope -->
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>

Expand All @@ -115,6 +121,18 @@
<version>${gravitee-apim-gateway-tests-sdk.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.gravitee.apim.plugin.entrypoint</groupId>
<artifactId>gravitee-apim-plugin-entrypoint-http-proxy</artifactId>
<version>${gravitee-apim-gateway-tests-sdk.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.gravitee.apim.plugin.endpoint</groupId>
<artifactId>gravitee-apim-plugin-endpoint-http-proxy</artifactId>
<version>${gravitee-apim-gateway-tests-sdk.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,36 +15,43 @@
*/
package io.gravitee.policy.overriderequestmethod;

import io.gravitee.common.http.HttpMethod;
import io.gravitee.gateway.api.ExecutionContext;
import io.gravitee.gateway.api.Request;
import io.gravitee.gateway.api.Response;
import io.gravitee.policy.api.PolicyChain;
import io.gravitee.policy.api.annotations.OnRequest;
import io.gravitee.gateway.jupiter.api.context.ContextAttributes;
import io.gravitee.gateway.jupiter.api.context.HttpExecutionContext;
import io.gravitee.gateway.jupiter.api.policy.Policy;
import io.gravitee.policy.overriderequestmethod.configuration.OverrideRequestMethodPolicyConfiguration;
import io.gravitee.policy.v3.overriderequestmethod.OverrideRequestMethodPolicyV3;
import io.reactivex.rxjava3.core.Completable;

/**
* @author David BRASSELY (david.brassely at graviteesource.com)
* @author Yann TAVERNIER (yann.tavernier at graviteesource.com)
* @author GraviteeSource Team
*/
public class OverrideRequestMethodPolicy {
public class OverrideRequestMethodPolicy extends OverrideRequestMethodPolicyV3 implements Policy {

/**
* The associated configuration to this Policy
*/
private OverrideRequestMethodPolicyConfiguration configuration;
private final HttpMethod configuredMethod;

/**
* Create a new policy instance based on its associated configuration
*
* @param configuration the associated configuration to the new policy instance
*/
public OverrideRequestMethodPolicy(OverrideRequestMethodPolicyConfiguration configuration) {
this.configuration = configuration;
super(configuration);
configuredMethod = configuration.getMethod();
}

@Override
public String id() {
return "policy-override-request-method";
}

@OnRequest
public void onRequest(Request request, Response response, ExecutionContext executionContext, PolicyChain policyChain) {
executionContext.setAttribute(ExecutionContext.ATTR_REQUEST_METHOD, configuration.getMethod());
policyChain.doNext(request, response);
@Override
public Completable onRequest(HttpExecutionContext ctx) {
return Completable.fromRunnable(() -> {
ctx.setAttribute(ContextAttributes.ATTR_REQUEST_METHOD, configuredMethod);
ctx.request().method(configuredMethod);
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* Copyright (C) 2015 The Gravitee team (http://gravitee.io)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.gravitee.policy.v3.overriderequestmethod;

import io.gravitee.gateway.api.ExecutionContext;
import io.gravitee.gateway.api.Request;
import io.gravitee.gateway.api.Response;
import io.gravitee.policy.api.PolicyChain;
import io.gravitee.policy.api.annotations.OnRequest;
import io.gravitee.policy.overriderequestmethod.configuration.OverrideRequestMethodPolicyConfiguration;

/**
* @author David BRASSELY (david.brassely at graviteesource.com)
* @author GraviteeSource Team
*/
public class OverrideRequestMethodPolicyV3 {

/**
* The associated configuration to this Policy
*/
protected OverrideRequestMethodPolicyConfiguration configuration;

/**
* Create a new policy instance based on its associated configuration
*
* @param configuration the associated configuration to the new policy instance
*/
public OverrideRequestMethodPolicyV3(OverrideRequestMethodPolicyConfiguration configuration) {
this.configuration = configuration;
}

@OnRequest
public void onRequest(Request request, Response response, ExecutionContext executionContext, PolicyChain policyChain) {
executionContext.setAttribute(ExecutionContext.ATTR_REQUEST_METHOD, configuration.getMethod());
policyChain.doNext(request, response);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@
import io.gravitee.apim.gateway.tests.sdk.AbstractPolicyTest;
import io.gravitee.apim.gateway.tests.sdk.annotations.DeployApi;
import io.gravitee.apim.gateway.tests.sdk.annotations.GatewayTest;
import io.gravitee.apim.gateway.tests.sdk.configuration.GatewayConfigurationBuilder;
import io.gravitee.policy.overriderequestmethod.configuration.OverrideRequestMethodPolicyConfiguration;
import io.reactivex.observers.TestObserver;
import io.gravitee.policy.v3.overriderequestmethod.OverrideRequestMethodPolicyV3;
import io.vertx.core.http.HttpMethod;
import io.vertx.reactivex.core.buffer.Buffer;
import io.vertx.reactivex.ext.web.client.HttpResponse;
import io.vertx.reactivex.ext.web.client.WebClient;
import io.vertx.rxjava3.core.http.HttpClient;
import io.vertx.rxjava3.core.http.HttpClientRequest;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

Expand All @@ -39,24 +40,32 @@
* @author GraviteeSource Team
*/
@GatewayTest
@DeployApi("/apis/override-http-method.json")
class OverrideRequestMethodPolicyIntegrationTest
extends AbstractPolicyTest<OverrideRequestMethodPolicy, OverrideRequestMethodPolicyConfiguration> {
@DeployApi("/apis/v3_definition/override-http-method.json")
public class OverrideRequestMethodPolicyIntegrationTest
extends AbstractPolicyTest<OverrideRequestMethodPolicyV3, OverrideRequestMethodPolicyConfiguration> {

@Override
protected void configureGateway(GatewayConfigurationBuilder gatewayConfigurationBuilder) {
super.configureGateway(gatewayConfigurationBuilder);
gatewayConfigurationBuilder.set("api.jupiterMode.enabled", "true");
gatewayConfigurationBuilder.set("api.jupiterMode.default", "always");
}

@ParameterizedTest(name = "Should change method {0} to GET")
@ValueSource(strings = { "POST", "DELETE", "PATCH", "HEAD" })
void shouldChangeMethod(String method, WebClient client) {
void shouldChangeMethod(String method, HttpClient client) throws InterruptedException {
wiremock.stubFor(get("/endpoint").willReturn(ok()));

TestObserver<HttpResponse<Buffer>> obs = client.request(HttpMethod.valueOf(method), "/test").rxSend().test();

awaitTerminalEvent(obs);
obs
.assertComplete()
client
.rxRequest(HttpMethod.valueOf(method), "/test")
.flatMap(HttpClientRequest::rxSend)
.test()
.await()
.assertValue(response -> {
assertThat(response.statusCode()).isEqualTo(200);
return true;
})
.assertComplete()
.assertNoErrors();

wiremock.verify(exactly(1), getRequestedFor(urlEqualTo("/endpoint")));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Copyright (C) 2015 The Gravitee team (http://gravitee.io)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.gravitee.policy.overriderequestmethod;

import io.gravitee.apim.gateway.tests.sdk.configuration.GatewayConfigurationBuilder;
import io.gravitee.definition.model.Api;
import io.gravitee.definition.model.ExecutionMode;

/**
* @author Yann TAVERNIER (yann.tavernier at graviteesource.com)
* @author GraviteeSource Team
*/
public class OverrideRequestMethodPolicyV3CompatibilityIntegrationTest extends OverrideRequestMethodPolicyIntegrationTest {

@Override
protected void configureGateway(GatewayConfigurationBuilder gatewayConfigurationBuilder) {
super.configureGateway(gatewayConfigurationBuilder);
gatewayConfigurationBuilder.set("api.jupiterMode.enabled", "true");
gatewayConfigurationBuilder.set("api.jupiterMode.default", "always");
}

@Override
public void configureApi(Api api) {
super.configureApi(api);
api.setExecutionMode(ExecutionMode.V3);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* Copyright (C) 2015 The Gravitee team (http://gravitee.io)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.gravitee.policy.overriderequestmethod;

import io.gravitee.apim.gateway.tests.sdk.annotations.DeployApi;
import io.gravitee.apim.gateway.tests.sdk.configuration.GatewayConfigurationBuilder;
import io.gravitee.apim.gateway.tests.sdk.connector.EndpointBuilder;
import io.gravitee.apim.gateway.tests.sdk.connector.EntrypointBuilder;
import io.gravitee.definition.model.ExecutionMode;
import io.gravitee.definition.model.v4.Api;
import io.gravitee.gateway.reactor.ReactableApi;
import io.gravitee.plugin.endpoint.EndpointConnectorPlugin;
import io.gravitee.plugin.endpoint.http.proxy.HttpProxyEndpointConnectorFactory;
import io.gravitee.plugin.entrypoint.EntrypointConnectorPlugin;
import io.gravitee.plugin.entrypoint.http.proxy.HttpProxyEntrypointConnectorFactory;
import java.util.Map;

/**
* @author Yann TAVERNIER (yann.tavernier at graviteesource.com)
* @author GraviteeSource Team
*/
@DeployApi("/apis/v4_definition/override-http-method.json")
public class OverrideRequestMethodPolicyV4IntegrationTest extends OverrideRequestMethodPolicyIntegrationTest {

@Override
protected void configureGateway(GatewayConfigurationBuilder gatewayConfigurationBuilder) {
super.configureGateway(gatewayConfigurationBuilder);
gatewayConfigurationBuilder.set("api.jupiterMode.enabled", "true");
gatewayConfigurationBuilder.set("api.jupiterMode.default", "always");
}

@Override
public void configureEntrypoints(Map<String, EntrypointConnectorPlugin<?, ?>> entrypoints) {
entrypoints.putIfAbsent("http-proxy", EntrypointBuilder.build("http-proxy", HttpProxyEntrypointConnectorFactory.class));
}

@Override
public void configureEndpoints(Map<String, EndpointConnectorPlugin<?, ?>> endpoints) {
endpoints.putIfAbsent("http-proxy", EndpointBuilder.build("http-proxy", HttpProxyEndpointConnectorFactory.class));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
import io.gravitee.common.http.HttpMethod;
import java.io.IOException;
import java.net.URL;
import org.junit.Assert;
import org.junit.Test;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;

/**
* @author David BRASSELY (david.brassely at graviteesource.com)
Expand All @@ -29,14 +29,14 @@
public class OverrideRequestMethodPolicyConfigurationTest {

@Test
public void test_resourceFiltering01() throws IOException {
public void shouldOverrideRequestMethod() throws IOException {
OverrideRequestMethodPolicyConfiguration configuration = load(
"/io/gravitee/policy/overriderequestmethod/configuration/overriderequestmethod01.json",
OverrideRequestMethodPolicyConfiguration.class
);

Assert.assertNotNull(configuration);
Assert.assertEquals(HttpMethod.PUT, configuration.getMethod());
Assertions.assertThat(configuration).isNotNull();
Assertions.assertThat(configuration.getMethod()).isEqualTo(HttpMethod.PUT);
}

private <T> T load(String resource, Class<T> type) throws IOException {
Expand Down
Loading

0 comments on commit e80114a

Please sign in to comment.