sigedi/jasper-rest-client
Lightweight PHP/Laravel client for the JasperReports Server REST API. Run reports, pass parameters, select export formats such as PDF, XLSX, and CSV, and handle authentication through a simple, framework-friendly interface. A convenient way to embed JasperReports output in your Laravel applications.
This is a bare PHP client for the JasperReports Server REST API (a fork of jaspersoft/jrs-rest-php-client), not a Laravel package. There is no service provider, facade, config file, or auto-discovery — expect to wire it into Laravel yourself in about 15 minutes.
Install
composer require sigedi/jasper-rest-client:^2.0
Pin the constraint. 2.0.0 is a major bump from 1.0.0, so treat the upgrade as potentially breaking: diff 1.0.0...2.0.0 on GitHub (and src/ against jaspersoft/jrs-rest-php-client) before swapping it under existing code. The release is small and reviewable — one PR, one contributor — so this is a 15-minute read, not a leap of faith.
What 2.0.0 actually changes (from the release notes):
^2.0 no longer risks a dependency conflict with a modern Laravel app. If you previously pinned Symfony 6 or ran an older Laravel, this is your reason to upgrade.Where to look first
vendor/sigedi/jasper-rest-client/src/ — the entry point is Jaspersoft\Client\Client.Client constructor signature. Auth mode and org ID handling vary between forks, and a major bump is exactly when that signature moves.composer.json for the PHP floor. Symfony 7 implies PHP 8.2+; if you're on 8.1 or below, stay on 1.x.Minimal wiring
config/services.php:'jasper' => [
'host' => env('JASPER_HOST'), // e.g. https://jasperserver.example.com:8443/jasperserver
'username' => env('JASPER_USER'),
'password' => env('JASPER_PASSWORD'),
'org_id' => env('JASPER_ORG_ID'), // null for root org
],
AppServiceProvider:use Jaspersoft\Client\Client;
$this->app->singleton(Client::class, function ($app) {
$c = $app['config']['services.jasper'];
return new Client($c['host'], $c['username'], $c['password'], $c['org_id']);
});
Check the argument order against the 2.0.0 constructor before copying this verbatim.
public function show(Client $jasper)
{
$pdf = $jasper->reportService()->runReport('/reports/sales/summary', 'pdf', null, null, [
'year' => 2024,
]);
return response($pdf, 200, ['Content-Type' => 'application/pdf']);
}
That single flow (reportService()->runReport() → binary → response) covers 80% of real-world use.
Wrap the client in your own service. Don't inject Jaspersoft\Client\Client into controllers — wrap it so you can mock, normalize params, centralize error handling, and absorb breaking changes from a major bump in one place.
class JasperReportService
{
public function __construct(private Client $client) {}
public function pdf(string $uri, array $params = []): string
{
return $this->client->reportService()->runReport($uri, 'pdf', null, null, $params);
}
}
Stream large reports instead of buffering. runReport() returns the whole body as a string; for 50MB+ XLSX exports use response()->streamDownload(), or better — use the job service for anything that takes more than a few seconds:
$job = $this->client->jobService()->createJob('/reports/heavy','xlsx');
// poll jobService()->getJobState($job->id) from a queued job
$output = $this->client->jobService()->fetchNextOutput($job->id);
Drive async jobs from a Laravel ShouldQueue job, not a controller.
Multi-tenant orgs. The client is bound to one org at construction time. If you're multi-tenant, don't use a singleton — instantiate per-request with the tenant's org ID (or maintain a keyed singleton per org).
Caching the resource tree. resourceService()->getResourceList() hits the server on every call. Cache the report catalog with Cache::remember('jasper:catalog', 3600, fn () => $this->client->resourceService()->getResourceList('/')). Bust the cache when you deploy or via a scheduled command.
Testing. The Client wraps GuzzleHttp\Client internally in most forks. In tests, mock Client itself (cleanest) rather than fighting the internal HTTP layer. Assert your JasperReportService calls the right runReport URI and params. After a major bump, re-run these tests against real Jasper — typed return values and stricter signatures are the kind of change mocks happily hide.
Facade optional. If you want Jasper::reportService()... syntax, register a facade pointing at the singleton — but for a single integration point a typed service is clearer.
Parameter conventions. Pass params as a flat associative array. Multi-select values go as arrays — the client serializes them, but check whether the fork uses PLURAL-style naming or plain arrays. Dates should be ISO 8601 strings; the server expects YYYY-MM-DD or full timestamps. If you use multi-selects or params with spaces/#, smoke-test them specifically on 2.0.0 — the encoding fix is the one behavioral change in this release.
JasperReportService test suite, and exercise one real report of each output type before merging.extra.laravel in composer.json — no auto-discovery, no config publish, no facade. Everything above is manual, and that's fine.rawurlencode() per path segment — spaces and # silently break requests, and a partial fix is worse than a known bug because it stops being reproducible..ticket cookie) requires a different constructor or header injection. A major version is exactly when this moves — re-read the constructor signature in vendor code, not the docs.ConnectException. For heavy reports, use jobService() — do not just bump the timeout; you'll tie up PHP-FPM workers.runReport() returns raw bytes. When returning to a browser, always set Content-Type (application/pdf, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet) and Content-Disposition — the client does not set these.\Exception (or Guzzle exception, depending on fork). 2.0.0's quality pass may have changed which type surfaces; re-verify your catch blocks. Wrap and translate to Laravel-friendly errors — the raw exception message often contains Jasper's XML error body, which is not user-safe.Jaspersoft\Client\Client → service objects (reportService(), jobService(), resourceService(), userService(), permissionService(), administrationService()). If you need custom behavior (retry, logging, header injection), decorate the Client rather than patch vendor — subclass and override, or wrap with your JasperReportService.How can I help you explore Laravel packages today?