Call a Service You Can Control
Load connection properties, start a supplied customer service and inspect an HTTP Request result.
Our order flow has only read its own request so far. It now needs the customer record that belongs to another service: a transform can construct the lookup, but an HTTP Request operation has to send it, wait for a response and report a failure if the exchange cannot complete. The companion supplies that service locally, so we can control what comes back — including the failures — while learning the operation.

Open this checkpoint in ACB
Stop the previous application. Open book/checkpoints/09-http-dependency from the companion as the project folder, then open src/main/mule/app.xml. Use Flow List to select the named example. Run Run Mule Application from Run and Debug; wait for deployment before sending requests. After a canvas edit, use Save and Hot-deploy to Local Runtime.
Start the controlled dependency with python3 book/stubs/server.py from the companion root in a separate terminal before calling these flows. It listens on port 18882.
The HTTP verification command, run from the companion root while this checkpoint is running, is python3 book/run.py verify 09. It checks the supplied baseline; restore exercise changes before using it.
Start the dependency you can inspect
From the companion root, run this command in another terminal:
python3 book/stubs/server.py
It listens on 127.0.0.1:18882. It provides a synthetic customer, a small catalogue, deliberately failed responses and request counters. The implementation is in book/stubs/server.py; you do not need to learn Python to use its documented endpoints.
Call the customer service directly before involving Mule:
curl --include http://127.0.0.1:18882/customers/C-42
{"id":"C-42","name":"Dana","status":"ACTIVE"}
That checks the dependency’s address and fixture. If this request fails, changing the Mule transform will not repair it. The controlled service also removes the need for an Anypoint account or a real customer database here, and it gives us the status codes, bodies and delays we want — a public demonstration endpoint can show a happy-path call, but it cannot reproduce the failure that matters to an application.
Give configuration values a home
Example 021 — Load local HTTP properties
The complete source is in checkpoints/09-http-dependency/src/main/resources/config-local.yaml.
http:
host: "127.0.0.1"
port: "18881"
dependency:
host: "127.0.0.1"
port: "18882"
Open Global Configurations on the canvas toolbar and inspect the Configuration properties entry: its File is config-local.yaml. That entry loads the resource. A reference such as ${dependency.port} asks for the corresponding property. This substitution is configuration loading, not the event expression syntax #[...] used to read a request.
The listener uses the http values and the Request configuration uses the dependency values. A port change belongs in the resource rather than in several scattered operations — if the customer service moves to another host while keeping the same endpoint contract, only this file changes. The configuration file has ordinary local addresses; a real password would need controlled secret delivery instead of a checked-in literal.
The first MUnit lesson used a named port to let the test select a free one. The same idea now groups the two connections’ settings in a file. A property name has no effect until a configuration actually references it.
Configure the outbound connection
Example 022 — Configure the customer connection
The complete source is in checkpoints/09-http-dependency/src/main/mule/app.xml.
Choose Flow List → lookup-customer, select Request, and open Edit Connection beside the connection selector. The reusable configuration is Dependency_HTTP.
| Connection setting | Value |
|---|---|
| Host | ${dependency.host} |
| Port | ${dependency.port} |
| Response timeout | 2000 milliseconds |
Keep property references as configuration text, not event expressions. Apply a connection edit before returning to the flow. Changing this named connection affects every Request that uses it.
Dependency_HTTP names the reusable outbound configuration. Its connection identifies the host and port. The operation supplies the method and path. The Response timeout of 2000 bounds how long this example waits for the response in milliseconds.
The Listener and Request belong to the same HTTP connector, but they do different jobs. The Listener accepts calls into this application; Request makes a call from this application to another service. Their paths, and later their authentication and status contracts, need not match — an integration is often useful precisely because it separates the two interfaces. A listener path does not configure where an outbound request goes.
Observe the returned payload
Example 023 — Look up the customer
The complete source is in checkpoints/09-http-dependency/src/main/mule/app.xml.
In lookup-customer, inspect Listener → Path, /customer. Select Request: Connection Config is Dependency_HTTP, Method is GET, and Path is /customers/C-42. Leave the target empty so the returned message becomes current.
Run the project from ACB after the controlled dependency is listening on 18882. Use a separate terminal for the inbound request:
curl --include http://127.0.0.1:18881/customer
After deploying checkpoint 09, request http://127.0.0.1:18881/customer. Mule calls the controlled service and returns its customer document. There is no response transform because this example is inspecting what the Request operation returns.
The current payload becomes the customer’s response body. The current attributes describe the outbound HTTP response, including its status. They no longer describe the original request’s method and path parameters. This is why the event table from chapter 2 must be read at a particular point in the flow.
Here the original body is unneeded, so nothing is lost by the replacement. It costs more as soon as the flow still needs its input: without a target, the current message becomes the response, and a later payload.orderId no longer names the order that arrived. The next chapter reproduces that loss deliberately and then gives the dependency result a place of its own.
Change one failure at a time
Stop the controlled service and send the request again. The connector cannot establish the same successful exchange. Restart it and confirm the ordinary call works before trying a different failure.
The service also supplies /slow, which waits longer than this request’s two-second timeout. A timeout is an observation about how long Mule waited — it is not evidence that a remote operation did nothing. Our first call is a read, which lets us explore timing without creating a reservation or payment that might need reconciliation.
An error handler should not retry every failure. A malformed customer identifier, an authorization rejection and an unavailable network need different remedies, and repeating an unauthorized call with the same credentials is usually just a slower failure with more noise. Give the call a bounded timeout and a clear response policy instead of adding retries to conceal a configuration error. Retry counts and duplicate behavior wait until the database transaction lesson gives us somewhere to record the outcome.

HTTP Request connection, GET method and customer path.
Try it
1. Point at an unused local port. Change only dependency.port, save and hot-deploy. Which connection has changed?
Show answer
The outbound Request connection changes. The application can still listen on 18881, so receiving a request and completing the dependency lookup are different checks. Restore 18882 before continuing.
2. Inspect the response attributes. Pause after Request in the debugger. Which attributes now contain the HTTP status?
Show answer
The current HTTP response attributes supplied by Request contain statusCode. They are the dependency response’s metadata. Save an incoming value before this operation if a later processor still needs it.
3. Choose a timeout experiment. Why use the controlled /slow read before testing a slow warehouse reservation?
Show answer
A delayed read makes the timeout visible without introducing uncertainty about a business side effect. A reservation can succeed remotely after the caller times out, which needs an idempotency and reconciliation design.
A successful outbound request is now something we can run and inspect. The next example combines its result with the order that arrived at the listener.
Comments