mesd/jasper-client
mesd/jasper-client is a Laravel/PHP client for JasperReports that lets you run reports, pass parameters, and export PDF, HTML, XLS, and other formats from your application through a simple, configurable API.
Install and inspect the source. composer require mesd/jasper-client (or add it to composer.json manually if Packagist metadata is stale). Because the package is small and sparsely documented, open src/ and read the client class first — that is your real README. Identify the client constructor signature (base URL + credentials), the transport (likely Guzzle 3/4-era), and the available methods (getReports, getReport, getReportOptions, resource helpers, etc.).
Confirm the server side. You need a running JasperReports Server with its REST API reachable, typically at http://host:8080/jasperserver/rest_v2. The account you authenticate with must have read access to the report URIs you will call. Verify with curl -u user:pass http://host:8080/jasperserver/rest_v2/serverInfo before blaming the client.
Wire it into the app config. Put the base URL and credentials in config/services.php / .env, never inline. Instantiate through a small service provider so you can swap the transport later.
First use case: run a parameterless report and save the bytes.
// Illustrative — confirm exact class/method names against src/
$client = new JasperClient(
'http://jasper.example.com:8080/jasperserver',
config('services.jasper.username'),
config('services.jasper.password')
);
$pdf = $client->getReport('/reports/samples/AllAccounts', ['format' => 'pdf']);
file_put_contents(storage_path('app/accounts.pdf'), $pdf);
If that returns a non-empty PDF, the auth + base URL + URI encoding are all correct. Everything else is parameter plumbing.
Two-step "options then render" workflow. This is the pattern you will use most. First, fetch the report's input controls (GET /rest_v2/reports/{uri}/options) to discover parameter names, types, defaults, and allowed values. Render a form from that metadata, then submit to your own controller, which calls the client to run the report with the mapped parameters. Cache the option metadata (minutes to hours) — it changes rarely and is a needless round-trip on every page view.
Wrap the client in a domain service. Do not let controllers call the client directly. A ReportService that exposes options(string $uri): array, run(string $uri, array $params, string $format): StreamedResponse, and listFor(string $folder): array gives you one place to handle errors, timeouts, caching, and format selection.
class JasperReportService
{
public function __construct(private JasperClient $client) {}
public function render(string $uri, array $params, string $format): StreamedResponse
{
$body = $this->client->getReport($uri, array_merge($params, ['format' => $format]));
return response()->streamDownload(
fn () => print($body),
basename($uri).'.'.$format,
['Content-Type' => $this->mime($format)]
);
}
}
Choose format by intent. PDF for printable output, xlsx for analyst handoff, csv for machine ingestion, html only for previews. Parameter names/values often need per-format coercion (e.g., a multi-select control wants repeated query keys, not a comma-joined string).
Long-running reports. Reports over a few seconds should not block a web request. Either raise the client/transport timeout and stream to disk, or move to Jasper's asynchronous /reportExecutions endpoints (the package may not cover these — you can add thin methods that reuse its HTTP transport). A queued job + signed URL to the generated file is the usual production shape.
Multi-tenant / per-org auth. Jasper scopes resources by organization. If you serve multiple tenants, keep separate credential sets and build the client per request (or per tenant key in a container binding), rather than reusing one authenticated instance.
Parameter mapping. Dates usually need the server's expected format (yyyy-MM-dd is common, but locale-sensitive controls differ). Booleans often want literal true/false. Preserve report URI slashes — encode the path segments, not the slashes.
Health check + circuit breaker. A cheap serverInfo call on a schedule makes Jasper outages obvious. Wrap report runs so a failed Jasper does not take down the page that hosts the form.
composer why-not mesd/jasper-client before assuming it installs cleanly alongside a modern Laravel HTTP stack.NOASSERTION. Read LICENSE / composer.json in the repo before shipping it commercially; if unclear, isolate or reimplement the few REST calls yourself — the API surface you actually need is small.<!DOCTYPE html>, you have an auth or path problem, not a report problem. Assert on Content-Type and status before writing bytes./rest_v2 path. Trailing slashes, a missing /rest_v2, or using the old /rest/ path produce confusing 404s. Test the raw curl URL first, then mirror it exactly in config."/reports/samples/AllAccounts" — do not URL-encode the slashes. This is the single most common cause of "report not found".set_time_limit(0) on the job; consider output compression on the server side./options metadata's type hints.JSESSIONID cookie rather than stateless Basic auth. If you see intermittent 401s after the first successful call, your transport is not preserving cookies across the client's requests.Http:: calls against rest_v2) is a one-file swap.How can I help you explore Laravel packages today?