Building a HTTP Proxy flow in Mule 3.6+
Using a ESB to proxy incoming HTTP (and HTTPS) calls to an internal service, adding cross cutting concerns such as logging and authentication, is not uncommon. This blog will describe how to build such a proxy flow using Mule ESB 3.6.1 Community Edition.
What does the official documentation say ?
The official MuleSoft documentation includes a description on how to Proxying Your API how ever this guide is based on the assumption that you are using the Anypoint API Gateway which is part of MuleSofts AnypointPlatform offering.
Thus this guide is not applicable when working with the community edition of Mule ESB. Luckily we can still use much of this guide to build our own proxy flow.
The use case
The use case for this blow is very simple. We want to forward all incoming HTTP request that come in on port 8081 to an internal service running on the same machine. This service is listening on port 8888. The internal service is also using the same context path. Also we do not want to expose any APIKit console or RAML for this service.
Building our proxy flow for Mule ESB 3.6
Since we, want a clean HTTP proxy we will not use any APIKit message processors and instead just rely on a HTTP listener (on port 8081) and a HTTP request connector (to port 8888 on localhost. So this is pretty straight forward.
<http:listener-config name="http-lc-0.0.0.0-8081" host="0.0.0.0" port="8081" /> <http:request-config name="http-request-config" host="localhost" port="8888"/>
The main flow of the proxy is also very simple. It takes the incoming request, copies and filters the incoming headers and sends the request on to the inner service. The response headers from the inner service is also sanitized before returning them to the calling client.
Also we do not want the HTTP Request connector to parse the response so we disable it by setting the parseResponse="false" attribute on the http:request element.
The response status code should also be send back to the client without being changed by the proxy so we add a http:success-status-code-validator element to the http:request where we define that all (0-599) responses are to be handles as success (thus not changed).
<flow name="proxy" doc:name="HTTP Proxy" doc:description="Proxy flow will forward all incoming requests on port 8081 to localhost:8888."> <http:listener path="/*" config-ref="http-lc-0.0.0.0-8081" /> <flow-ref name="copyRequestHeaders" doc:name="Copy and sanitize request headers" /> <http:request config-ref="http-request-config" method="#[message.inboundProperties['http.method']]" path="#[message.inboundProperties['http.request.path'].substring(message.inboundProperties['http.listener.path'].length()-2)]" parseResponse="false"> <http:request-builder> <http:query-params expression="#[message.inboundProperties['http.query.params']]"/> </http:request-builder> <http:success-status-code-validator values="0..599" /> </http:request> <flow-ref name="copyResponseHeaders" doc:name="Copy and sanitize response headers" /> </flow>
The flows to copy and sanitize the headers are a bit different since for the response we do not want to remove the http.* headers (since the http.status header is used to propagate the status code).
The full code for this blog are available as a bitbucket snippet.