Course of Raku / Functional, concurrent, reactive, and web programming / Web programming / Cro 101

Using a client module

Cro is not only for building services — it also ships an HTTP client for making requests. The clearest way to meet it is to point it at the very server you built on the previous page. Here both halves run in one program: we start the service, then call it ourselves.

use Cro::HTTP::Router;
use Cro::HTTP::Server;
use Cro::HTTP::Client;

# the tiny service from the previous page
my $application = route {
    get -> 'hello' { content 'text/plain', 'Hello from Cro!'; }
}
my $server = Cro::HTTP::Server.new(
    :host('127.0.0.1'), :port(8080), :application($application),
);
$server.start;

# now be the client and call it
my $response = await Cro::HTTP::Client.get('http://127.0.0.1:8080/hello');
say await $response.body-text; # Hello from Cro!

$server.stop;

Cro::HTTP::Client.get returns a promise — fitting, since a network request finishes later — so you await it. The response object knows its status, headers, and body; await $response.body-text hands back the text the server sent, Hello from Cro!. Compare this with the raw socket of the connections section: there is no \r\n, no status line to parse, no reading in a loop — the client and the server speak to each other in a few plain lines.

This example needs Cro installed (zef install cro).

When the page is not there

What if you ask for a path the service does not have? The server side is easy: a request that matches no route gets a 404 Not Found from Cro automatically. On the client side, a failed request throws — the error travels with the promise and pops out at await, just as you saw with broken promises — so you handle it with the usual exception tools:

my $response = try await Cro::HTTP::Client.get('http://127.0.0.1:8080/goodbye');
if $! {
    say 'Request failed with status ', $!.response.status; # 404
}
else {
    say await $response.body-text;
}

Our service has a hello route but no goodbye, so this prints Request failed with status 404. The exception carries the full response in its .response, with the status code and headers there to inspect.

Your own service is just the nearest server there is, though. The next page points the same client at the wider web — public APIs that answer with JSON or terminal-ready text.

Course navigation

A route with a parameter   |   Fetching from a public API


💪 Or jump directly to the exercises in this section.