@Inject
private HttpService httpService;
HttpClient client = httpService.client(configurer -> configurer
.setName("client-name")
// other setters...
);
HTTP-Based Connectors
There is a special set of considerations for connectors that access a remote system by either issuing HTTP requests or exposing HTTP endpoints.
Use the Mule HTTP Client
The Mule HTTP Client must be used for making HTTP requests. Other HTTP clients (such as the Jersey client, Apache HTTP Client, Jetty, Netty, and so on) should not be used in favor of the Mule HTTP client.
The only exception to this rule is when the remote system vendor already provides a client library that has some level of added value that would be too difficult to replicate with the use of the Mule HTTP Client.
For example, the Amazon AWS connectors work by consuming an HTTP API that requires custom message signing. Amazon provides a client library that encapsulates the logic necessary to make such signing.
However, a client library that does nothing but wrap an HTTP client for convenience (like the Google clients) is not a valid exception to this rule.
Create the HTTP Client
There are two APIs for creating a Mule HttpClient:
-
The
org.mule.sdk.api.httpAPI (recommended). Its entry point isHttpService.client(Consumer<HttpClientConfigurer>). Becausemule-sdk-apiis bundled with your connector and isn’t coupled to the Mule Runtime lifecycle, a connector can use this API to consume newer HTTP features without raising its Minimum Mule Version. Use this API for new connectors and when migrating an existing connector that needs newer HTTP capabilities. See SDK Forward Compatibility for more about forward compatibility. -
The legacy
org.mule.runtime.http.apiAPI, whoseHttpClientis created from anHttpClientConfigurationbuilder throughhttpService.getClientFactory().create(…). This API remains fully supported and is a valid choice when your connector’s Minimum Mule Version already permits it. See Use the Legacy org.mule.runtime.http.api HTTP Client.
Use the org.mule.sdk.api HTTP Client
Inject the org.mule.sdk.api.http.HttpService and call client(…) with a callback that configures the client through an HttpClientConfigurer:
The HttpService.client(…) method returns an org.mule.sdk.api.http.client.HttpClient and throws a ClientCreationException if the client can’t be created.
Configure the Client
The HttpClientConfigurer passed to the callback exposes these methods. Each one returns the same configurer, so you can chain the calls:
| Method | Description |
|---|---|
|
Sets the name of the |
|
Required for HTTPS. Provides the TLS data used to establish secure connections. |
|
Maximum number of outbound connections kept open at the same time. Unlimited by default. |
|
Whether connections are kept open after a request completes. |
|
Number of milliseconds a connection can remain idle before being closed. |
|
Size, in bytes, of the buffer used to store the HTTP response. Defaults to 10 KB. |
|
Whether the HTTP response is streamed, so processing continues as the body arrives. |
|
Whether responses are decompressed automatically. |
|
Configures a proxy for the client. See [provide-http-proxy-configuration]. |
|
Enables, disables, and configures HTTP/1-specific parameters. |
|
Enables, disables, and configures HTTP/2-specific parameters. |
|
Configures TCP-specific properties, such as the socket connection timeout. |
For the complete reference, see the HttpClientConfigurer interface (package org.mule.sdk.api.http.client) in the mule-sdk-api javadoc.
Send a Request
The HttpClient implements Startable and Stoppable, so it must be started before use and stopped when you no longer need it. Build requests with HttpService.requestBuilder() and send them without blocking through sendAsync(…), which returns a CompletableFuture<HttpResponse>:
client.start();
HttpRequest request = httpService.requestBuilder()
.method(GET)
.uri("https://api.example.com/resource")
.build();
CompletableFuture<HttpResponse> future = client.sendAsync(request, options -> options
.setResponseTimeout(5000)
.setFollowsRedirect(true));
// ... use the response, then stop the client during the stop() phase
client.stop();
Because sendAsync(…) defers response body processing, handle the response on a different thread when you need the full body right away. For example, with CompletableFuture.whenCompleteAsync(…). This avoids blocking the client’s I/O threads.
Migrate from the Legacy HTTP Client
If your connector currently creates its client with the legacy org.mule.runtime.http.api.client.HttpClient and the HttpClientConfiguration builder, you can move to the configurer-based API as follows:
-
Replace the injected
org.mule.runtime.http.api.HttpServicewithorg.mule.sdk.api.http.HttpService. -
Replace
httpService.getClientFactory().create(new HttpClientConfiguration.Builder()…build())withhttpService.client(configurer → …), mapping each builder setter to the equivalent configurer method (for example,.setName(…)). -
Update the imports of
HttpClient,HttpRequest,HttpResponse, and related types to theirorg.mule.sdk.api.httpcounterparts.
|
Because the new HTTP types come from org.mule.sdk.api, follow the guidance in Forward Compatibility Patterns when you need to call newer methods conditionally and provide fallback behavior for older runtimes.
Use the Legacy org.mule.runtime.http.api HTTP Client
The legacy API creates the HttpClient from an HttpClientConfiguration builder:
httpClient = httpService.getClientFactory()
.create(new HttpClientConfiguration.Builder()
.setName(configName)
.build());
httpClient.start();
This API is still fully supported. Use it when your connector’s Minimum Mule Version already covers it and you don’t need the newer HTTP features exposed by org.mule.sdk.api.http.
Manage the Client in a Connection Provider
Regardless of which API creates the HttpClient, the connector’s ConnectionProvider is responsible for managing it according to these rules.
-
Handle the HTTP Client Lifecycle
The ConnectionProvider that creates the HttpClient is responsible for managing its lifecycle.
-
Use Cached Connection Providers
Every ConnectionProvider that creates an HttpClient must implement the CachedConnectionProvider interface.
Notice that this rule has implications on the connection object that the Connection Provider can yield. Because of the previously discussed Connection Object must not expose (nor be) the inner client rule, this means that the provided connection object needs to contain the HTTP client as part of its state and must be thread safe.
-
Use Startable and Stoppable Connection Providers
The Connection Provider must also implement the Startable and Stoppable interfaces. The HttpClient must be created and started during the start() phase and must be stopped during the stop() phase.
Lifecycle example:
public class HttpConnectionProvider implements CachedConnectionProvider<HttpConnection>, Startable, Stoppable { @Inject private HttpService httpService; @Parameter private TlsContextFactory tlsContext; @RefName private String configName; @Override public void start() throws MuleException { initialiseIfNeeded(tlsContext); httpClient = httpService.client(configurer -> configurer .setName(configName) .setTlsContextFactory(tlsContext)); httpClient.start(); } @Override public void stop() throws MuleException { if (httpClient != null) { httpClient.stop(); } } // rest of the implementation removed for example simplicity } -
The HttpClient created by each ConnectionProvider must have a name which is based on (or simply matches) the name of the configuration that owns that ConnectionProvider.
This is very important for performance troubleshooting. Each HttpClient creates a set of selector threads that it uses for I/O. Those threads are named after the client’s name. Giving those threads a meaningful name is key for diagnosing performance problems.
The name of the owning config can be obtained using the @RefName annotation.
Here’s an example of how to do this:
public class HttpConnectionProvider implements CachedConnectionProvider<HttpConnection>, Startable, Stoppable { @Inject private HttpService httpService; @RefName private String configName; @Override public void start() throws MuleException { httpClient = httpService.client(configurer -> configurer.setName(configName)); httpClient.start(); } // rest of implementation removed for example simplicity } -
Leverage Non-Blocking I/O in Operations
The HttpClient is capable of using non-blocking I/O to make the requests. Operations must leverage this capability and also be defined as non-blocking.
-
Do not reference <http:requester-config> Elements
The HttpService allows you to obtain the HttpClient associated with a separate <http:requester-config> element. Although this capability exists, it is not meant to be used by connectors. Connectors must not use this feature.
All connectors in need of a HttpClient instance, must create and manage their own.
-
Provide HTTP Proxy Configuration
Connectors using HTTP Client instances must provide the ability to configure a proxy, similar to HTTP Connector. Common reasons to use proxy configuration include security, maintenance, and proxy caching. Many organizations also require proxy configuration when working behind firewalls.
The following code snippets show how to configure proxy, for example, for the OAuth endpoint in HTTP Request Connector:
Use this global proxy configuration as a reference:
<http:proxy name="proxyConfig" host="localhost" port="3128" username="yourProxyUsername" password="yourProxyPassword" />
When configuring for the Client Credentials grant type, use the following snippet:
<http:request-config name="HTTP_Request_Configuration" host="api.github.com" port="443" doc:name="HTTP Request Configuration"> <oauth2:client-credentials-grant-type clientId="111" clientSecret="222" > <oauth2:token-request tokenUrl="https://github.com/login/oauth/authorize"" /> <spring:property name="proxyConfig" ref="proxyConfig"/> </oauth2:client-credentials-grant-type> </http:request-config>When configuring for the Authorization Code grant type, use the following snippet:
<http:request-config name="HTTP_Request_Configuration" host="api.github.com" protocol="HTTPS" port="443" usePersistentConnections="false" doc:name="HTTP Request Configuration"> <oauth2:authorization-code-grant-type clientId="00a3d08a823faf378568" clientSecret="19c09306adbb84c2d4bc99c585df51d49fe858cf" redirectionUrl="http://localhost:8082/callback">; <oauth2:authorization-request authorizationUrl="https://github.com/login/oauth/authorize"" localAuthorizationUrl="http://localhost:8082/login"/>; <oauth2:token-request tokenUrl="https://github.com/login/oauth/access_token">; <oauth2:token-response accessToken="#[payload.'access_token']" refreshToken="#[payload['access_token']]"/> </oauth2:token-request> <spring:property name="proxyConfig" ref="proxyConfig"/> </oauth2:authorization-code-grant-type> </http:request-config>When using the
proxyConfigtype, the connection provider must include a@Parameterannotation so that the connection refers to the proxy, for example:@Parameter @Optional @Placement(tab = "Proxy", order = 1) private MyConnectorProxyConfiguration proxyConfig;You must also set the proxy configuration in the HTTP Client:
.setProxyConfig(connectionParams.getProxyConfig())For more information, refer to the Java code for how HTTP Connector handles the proxy.
Exposing HTTP Inbound Endpoints
Some connectors need to expose their own HTTP inbound endpoints.
To achieve this, connectors must reference an external <http:listener-config> element to obtain an HttpServer instance. Connectors must not create their own servers.
This must be achieved as follows:
-
Correctly reference the listener config
The connection provider must expose a String parameter called listenerConfig. This parameter must be of type String, not accept expressions, and use the @ConfigReference annotation to indicate that it points to an <http:listener-config> element.
For example:
@Parameter @Expression(NOT_SUPPORTED) @ConfigReference(name = "LISTENER_CONFIG", namespace = "HTTP") private String listenerConfig; -
Add a RequestHandler
Using the listenerConfig parameter added above, a matching HttpServer instance can be obtained like this:
HttpServer httpServer; try { httpServer = httpService.getServerFactory().lookup(listenerConfig); } catch (ServerNotFoundException e) { throw new IllegalArgumentException( format("Connector configuration '%s' refers to an <http:listener-config> with name '%s', " + "but such element doesn't exist", configName, listenerConfigName), e); }With the obtained HttpServer, a new RequestHandler can be added using the org.mule.runtime.http.api.server.HttpServer#addRequestHandler(java.lang.String, org.mule.runtime.http.api.server.RequestHandler) method.
The connector must carefully follow the contract defined in the Javadocs for that method. Most importantly, invoking that method will return a RequestHandlerManager instance. Those instances must be kept by the connector as they expose two important methods: start() and stop().
The inbound endpoint will not be actually functioning until the start() method is invoked on the RequestHandlerManager. At the same time, the endpoint does not go away until the stop() method is invoked on the RequestHandlerManager.
That means that when the component owning the custom endpoint is stopped, so must the RequestHandlerManager be stopped. Otherwise, your connector will generate a memory leak.
HTTPS Security
The connector must support the HTTPS scheme whenever possible and must consider it as the recommended option:
-
If the remote system supports only HTTPS, then the connector must have a required TlsContextFactory parameter.
-
If the remote system supports both HTTP and HTTPS schemes, then the connector must support both options but log a warning when HTTP is used.



