Chapter 6. Transforming 3scale API Management message content using policy extensions in Fuse You can use Red Hat Fuse to create highly flexible policy extensions for Red Hat 3scale API Management. You can do this by creating policy extensions in Fuse on OpenShift and then configuring them as policies in the 3scale Admin Portal. Using an APIcast Camel proxy policy, you can perform complex transformations on request and response message content, for example, XML to JSON, which are implemented in the Apache Camel integration framework. In addition, you can add or modify custom policy extensions dynamically in Camel, instead of rebuilding and redeploying a static APIcast container image. You can use any Camel Enterprise Integration Pattern (EIP) written in Camel Domain Specific Language (DSL) to implement an APIcast policy extension. This enables you to write policy extensions using a familiar programming language such as Java or XML. The example in this topic uses the Camel Netty4 HTTP component to implement the HTTP proxy in Java. Note This feature is not required if you are already using a Fuse Camel application in your 3scale API backend. In this case, you can use your existing Fuse Camel application to perform transformations. Required software components You must have the following Red Hat Integration components deployed on the same OpenShift cluster: Fuse on OpenShift 7.10. 3scale On-premises 2.15. APIcast embedded (default Staging and Production), or APIcast self-managed. You can deploy the custom Fuse policy in a different OpenShift project than 3scale, but this is not required. However, you must ensure that communication between both projects is possible. For details, see Configuring network policy with OpenShift SDN . Additional resources Fuse on OpenShift Guide 6.1. Integrating APIcast with Apache Camel transformations in Fuse You can integrate APIcast with a transformation written as an Apache Camel application in Fuse on OpenShift. When the policy extension transformation is configured and deployed in 3scale, the 3scale traffic goes through the Camel policy extension, which transforms the message content. In this case, Camel works as a reverse HTTP proxy, where APIcast sends the 3scale traffic to Camel, and Camel then sends the traffic on to the API backend. The example in this topic creates the HTTP proxy using the Camel Netty4 HTTP component: The request received over the HTTP proxy protocol is forwarded to the target service with the HTTP body converted to uppercase. The response from the target service is processed by converting it to uppercase and then returned to the client. This example shows the configuration required for HTTP and HTTPS use cases. Prerequisites You must have Fuse on OpenShift 7.10 and 3scale 2.15 deployed on the same OpenShift cluster. For installation details, see: Fuse on OpenShift Guide . Installing 3scale API Management . You must have cluster administrator privileges to install Fuse on OpenShift and 3scale and to create projects. However, you can create deployment configurations, deploy pods, or create services with edit access privileges per project. Procedure Write an Apache Camel application in Java using the Camel netty4-http component to implement the HTTP proxy. You can then use any Camel component to transform the message. The following simple example performs an uppercase transformation of the request and response from the service: import java.nio.file.Files; import java.nio.file.Path; import java.util.Locale; import org.apache.camel.Exchange; import org.apache.camel.Message; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.model.RouteDefinition; public class ProxyRoute extends RouteBuilder { @Override public void configure() throws Exception { final RouteDefinition from; if (Files.exists(keystorePath())) { from = from("netty4-http:proxy://0.0.0.0:8443?ssl=true&keyStoreFile=/tls/keystore.jks&passphrase=changeit&trustStoreFile=/tls/keystore.jks"); 1 } else { from = from("netty4-http:proxy://0.0.0.0:8080"); } from .process(ProxyRoute::uppercase) .toD("netty4-http:" + "USD{headers." + Exchange.HTTP_SCHEME + "}://" 2 + "USD{headers." + Exchange.HTTP_HOST + "}:" + "USD{headers." + Exchange.HTTP_PORT + "}" + "USD{headers." + Exchange.HTTP_PATH + "}") .process(ProxyRoute::uppercase); } Path keystorePath() { return Path.of("/tls", "keystore.jks"); } public static void uppercase(final Exchange exchange) { 3 final Message message = exchange.getIn(); final String body = message.getBody(String.class); message.setBody(body.toUpperCase(Locale.US)); } } 1 In this simple example, if your Java keystore file is mounted at /tls/keystore.jks , the listening port is set to 8443 . 2 When the Camel proxy policy is invoked by 3scale, the values for the HTTP_SCHEME , HTTP_HOST , HTTP_PORT , and HTTP_PATH headers are automatically set based on the values configured for the backend API in 3scale. 3 This simple example converts the message content to uppercase. You can perform more complex transformations on request and response message content, for example, XML to JSON, using Camel Enterprise Integration Patterns. Deploy your Camel application on OpenShift and expose it as a service. For more details, see Creating and Deploying Applications on Fuse on OpenShift . Additional resources Apache Camel Component Reference - Netty4 HTTP component 6.2. Configuring an APIcast policy extension created using Apache Camel in Fuse on OpenShift After you have implemented the Apache Camel transformation using Fuse on OpenShift, you can use the 3scale Admin Portal to configure it as a policy extension in the APIcast policy chain. The policy extension enables you to configure a 3scale product to use a Camel HTTP proxy. This service is used to send the 3scale traffic over the HTTP proxy to perform request-response modifications in a third-party proxy. In this case, the third-party proxy is Apache Camel implemented using Fuse on OpenShift. You can also configure APIcast to connect to the Camel HTTP proxy service securely using TLS. Note The policy extension code is implemented in an Apache Camel application in Fuse on OpenShift and cannot be modified or deleted from 3scale. Prerequisites You must have Fuse on OpenShift 7.10 and 3scale 2.15 deployed on the same OpenShift cluster. For installation details, see: Fuse on OpenShift Guide Installing 3scale API Management You must have implemented an APIcast policy extension using an Apache Camel application in Fuse on OpenShift. See Section 6.1, "Integrating APIcast with Apache Camel transformations in Fuse" You must have deployed the Apache Camel application in an OpenShift pod and exposed it as a service. For details, see Creating and Deploying Applications on Fuse on OpenShift . Procedure In the 3scale Admin Portal, select Integration > Policies . Select POLICIES > Add policy > Camel Service . Enter the OpenShift routes used to connect to the Camel HTTP proxy service in the appropriate fields: https_proxy : Connect to the Camel HTTP proxy using the http protocol and TLS port, for example: http_proxy : Connect to the Camel HTTP proxy using the http protocol and port, for example: all_proxy : Connect to the Camel HTTP proxy using the http protocol and port when the protocol is not specified, for example: Promote the updated policy configuration to your staging or production environment. For example, click Promote v. 3 to Staging APIcast . Test the APIcast policy configuration using a 3scale curl command, for example: curl "https://testapi-3scale-apicast-staging.myuser.app.dev.3sca.net:443/?user_key=MY_USER_KEY" -k APIcast establishes a new TLS session for the connection to the Camel HTTP proxy. Confirm that the message content has been transformed, which in this example means converted to uppercase. If you wish to bypass APIcast and test the Camel HTTP proxy directly using TLS, you must use a custom HTTP client. For example, you can use the netcat command: USD print "GET https://mybackend.example.com HTTP/1.1\nHost: mybackend.example.com\nAccept: */*\n\n" | ncat --no-shutdown --ssl my-camel-proxy 8443 This example creates an HTTP proxy request using the full URL after GET , and uses the ncat --ssl parameter to specify a TLS connection to the my-camel-proxy host on port 8443 . Note You cannot use curl or other common HTTP clients to test the Camel HTTP proxy directly because the proxy does not support HTTP tunneling using the CONNECT method. When using HTTP tunneling with CONNECT , the transport is end-to-end encrypted, which does not allow the Camel HTTP proxy to mediate the payload. Additional resources Section 4.1.6, "Camel Service"

Commands:
import java.nio.file.Files; import java.nio.file.Path; import java.util.Locale; import org.apache.camel.Exchange; import org.apache.camel.Message; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.model.RouteDefinition; public class ProxyRoute extends RouteBuilder { @Override public void configure() throws Exception { final RouteDefinition from; if (Files.exists(keystorePath())) { from = from("netty4-http:proxy://0.0.0.0:8443?ssl=true&keyStoreFile=/tls/keystore.jks&passphrase=changeit&trustStoreFile=/tls/keystore.jks"); 1 } else { from = from("netty4-http:proxy://0.0.0.0:8080"); } from .process(ProxyRoute::uppercase) .toD("netty4-http:" + "USD{headers." + Exchange.HTTP_SCHEME + "}://" 2 + "USD{headers." + Exchange.HTTP_HOST + "}:" + "USD{headers." + Exchange.HTTP_PORT + "}" + "USD{headers." + Exchange.HTTP_PATH + "}") .process(ProxyRoute::uppercase); } Path keystorePath() { return Path.of("/tls", "keystore.jks"); } public static void uppercase(final Exchange exchange) { 3 final Message message = exchange.getIn(); final String body = message.getBody(String.class); message.setBody(body.toUpperCase(Locale.US)); } }
http://camel-proxy.my-3scale-management-project.svc:8443
http://camel-proxy.my-3scale-management-project.svc:8080
http://camel-proxy.my-3scale-management-project.svc:8080
curl "https://testapi-3scale-apicast-staging.myuser.app.dev.3sca.net:443/?user_key=MY_USER_KEY" -k
print "GET https://mybackend.example.com HTTP/1.1\nHost: mybackend.example.com\nAccept: */*\n\n" | ncat --no-shutdown --ssl my-camel-proxy 8443