0129

Call a REST API (Mocked)

httpclient
rest
json
interface
mocking

Call a REST API (Mocked)

Your company subscribes to a currency-rate service, and the finance team wants those rates inside Business Central. Real services misbehave — they go down, answer with error statuses, and ship bodies you did not expect — so your client codeunit has to survive all of that without ever crashing the code that calls it.

There is a house rule, too: no codeunit talks to the network directly. Every HTTP call travels through the System Application's Interface "Http Client Handler" — production code passes the standard Codeunit "Http Client Handler", which really goes on the wire, while automated tests pass a mock of the service. Your client receives the handler as a parameter and must route its request through it; that seam is exactly how the grading tests watch your request and script the service's answers.

The service

One endpoint matters here: GET https://rates.example.com/v1/latest?symbol=<currency code> — the currency you are asking about travels as the symbol query parameter.

On success the service answers 200 with a JSON body like:

{ "symbol": "EUR", "rate": 0.13123, "asOf": "2026-07-15" }

When something is wrong the service answers with a non-success status such as 404 or 500 — and, like many real APIs, the error response can still carry a JSON body, sometimes even one containing a rate property. Only a success status makes the body trustworthy.

Requirements

Create a codeunit named "Exchange Rate Client" with one public procedure:

procedure GetRate(CurrencyCode: Text; HttpClientHandler: Interface "Http Client Handler"; var Rate: Decimal): Boolean

Rules:

  1. Each call sends exactly one HTTP GET request through HttpClientHandler, and the full request URL must be exactly https://rates.example.com/v1/latest?symbol=<CurrencyCode>.
  2. If the handler cannot send the request at all (a transport failure), return false.
  3. If the response has a success status code and the body is valid JSON with a rate property, set Rate to that number and return true.
  4. If the response status is not a success, return false — no matter what the body contains.
  5. If the status is a success but the body is not valid JSON, or the JSON has no rate property, return false.
  6. Whenever the procedure returns false, Rate must end up 0 — callers must never see a stale or half-parsed value.
  7. The procedure never raises an error, whatever the service does.

You may rely on two guarantees: CurrencyCode is always plain letters, and when a rate property is present it is always a JSON number.

What the tests check

The grading tests implement "Http Client Handler" with a mock of the rate service — no real network is involved (the grading container has none anyway), so write your request as if the endpoint were real and let the mock do the answering. The mock records every request your code sends through the handler: the method must be GET, the full URL must match the documented endpoint character for character — one test generates a random currency code and expects it unchanged in the symbol parameter — and exactly one request per call may arrive. A success test injects 200 with a randomly generated rate and expects that exact number back. One test makes the handler report a transport failure and expects false. The 404 and 500 tests inject bodies that still contain a tempting rate value — an implementation that parses the body before checking the status returns that value and fails. The malformed-body and missing-property tests expect false, and every failure test presets Rate to -1 before calling, so leaving it untouched fails too.

Learn More

Hint 1
Everything you need ships in the System Application's Rest Client module. Start from Interface "Http Client Handler": its single Send method names the two codeunits you'll work with — one you fill with your request, one the handler fills with the service's answer.
Hint 2
Build a "Http Request Message" (set the method and the request URI), hand it to the handler's Send, and use Send's Boolean return as your transport-failure signal. Codeunit "Rest Client" (Initialize with the handler, then Get) also works — but it raises an error on transport failure, which your contract forbids, so you'd have to catch it.
Hint 3
Ask the response codeunit whether the status counts as a success BEFORE touching the body — the error responses in the tests deliberately parse fine. GetContent().AsText() yields the body; JsonObject.ReadFrom returns false on malformed text; JsonObject.Get returns false when rate is missing; a found token yields its number via AsValue().AsDecimal(). And set Rate to zero on every failure path.
ALBusiness Central 28.5
Press Compile to check your code compiles — Submit runs the tests.
The code editor is desktop-only
Open this problem on a computer to write and run code. Reading the description, tests and discussion works fine here.