Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Easyrdf On Guzzle Laravel Package

madbob/easyrdf-on-guzzle

Provides a Guzzle-backed HTTP client adapter for EasyRdf, acting as a drop-in replacement for its default client so you can fetch and parse RDF resources through Guzzle's request handling, middleware, authentication, proxies, and timeout configuration while keeping EasyRdf's familiar API.

View on GitHub
Deep Wiki
Context7

Getting Started

What it is. EasyRdf is the de-facto PHP library for RDF/JSON-LD/Turtle parsing, SPARQL, and Linked Data fetching. It ships its own tiny HTTP layer (curl/stream adapters) that is functional but primitive. madbob/easyrdf-on-guzzle replaces that HTTP layer with Guzzle, so all requests EasyRdf makes — Graph::load(), Sparql\Client, content negotiation, redirects — go through a Guzzle client you control.

Why a Laravel dev cares. You almost certainly already have Guzzle configured in the app (proxies, TLS, OAuth middleware, logging, retry, cache, MockHandler in tests). This package lets you reuse that instead of maintaining a second, parallel HTTP stack just for RDF.

Install.

composer require madbob/easyrdf-on-guzzle

This pulls in easyrdf/easyrdf and guzzlehttp/guzzle. Check composer.lock afterwards — EasyRdf 1.1.x is effectively frozen upstream, and Guzzle 6 vs 7 matters (see Gotchas).

Where to look first. Open vendor/madbob/easyrdf-on-guzzle/src and the README before writing anything. The package is small; the entire surface is one or two classes. Confirm two things:

  1. The exact FQCN of the client/adapter (e.g. MadBob\EasyRdfOnGuzzle\Client).
  2. Its constructor signature — whether it takes a GuzzleHttp\ClientInterface, a handler stack, or config array.

First use case. Register it as EasyRdf's global default client, then load a document:

use EasyRdf\Http;
use EasyRdf\Graph;
// use MadBob\EasyRdfOnGuzzle\Client as GuzzleHttpClient; // confirm FQCN from vendor/src

$guzzle = new \GuzzleHttp\Client([
    'timeout'         => 10,
    'connect_timeout' => 3,
    'headers'         => ['Accept' => 'text/turtle, application/ld+json;q=0.9, */*;q=0.1'],
    'http_errors'     => false, // EasyRdf wants a response object, not an exception
]);

Http::setDefaultHttpClient(new GuzzleHttpClient($guzzle));

$graph = Graph::newAndLoad('https://example.org/resource.ttl');
echo $graph->dump();

That single setDefaultHttpClient() call is the whole integration. Everything downstream — Graph::load(), EasyRdf\Sparql\Client, EasyRdf\Serialiser fetches — inherits it.

Implementation Patterns

Bind one configured client in a service provider. Don't construct Guzzle ad hoc. Put it in AppServiceProvider::boot() (or a dedicated RdfServiceProvider) so there is exactly one default EasyRdf client for the request lifecycle:

$this->app->singleton(\EasyRdf\Http\Client::class, function ($app) {
    $guzzle = $app->make(\GuzzleHttp\ClientInterface::class); // your app-configured client
    return new \MadBob\EasyRdfOnGuzzle\Client($guzzle);
});

// after the binding, push it into EasyRdf's static default
\EasyRdf\Http::setDefaultHttpClient($this->app->make(\EasyRdf\Http\Client::class));

Wrap RDF access in a repository, not in controllers. EasyRdf's global default client is process-wide static state; hiding it behind App\Services\Rdf\LinkedDataRepository keeps the surface small and makes testing sane.

Middleware is the main reason to do this. Attach to the handler stack:

  • Cache middleware backed by Laravel's cache store — RDF documents rarely change, and this is a huge win on fan-out over vocabularies (rdfs:label lookups, FOAF crawling). Use GuzzleHttp\Middleware::cache() (Guzzle 6) or kevinrob/guzzle-cache-middleware (Guzzle 7), with a PSR-6 adapter over Illuminate\Cache\Repository.
  • Retry middleware (\GuzzleHttp\Middleware::retry()) for flaky endpoints — SPARQL endpoints and vocabulary hosts are notoriously unavailable.
  • Logging with \GuzzleHttp\Middleware::log() into a dedicated channel, so you can see exactly which URIs EasyRdf reached out for.

Auth against protected SPARQL endpoints. EasyRdf's SPARQL client accepts a graph/endpoint URI; the credentials live on the Guzzle client (headers, auth middleware, OAuth subscriber). This is much cleaner than EasyRdf's own setCredentials()-style plumbing.

Concurrent fan-out. EasyRdf's API is synchronous, but Guzzle is not. For "fetch N URIs and merge", use a Guzzle Pool, get raw bodies asynchronously, then parse each with Graph::parse($data, $format, $baseUri). This routinely turns a minute-long crawl into a few seconds.

$pool = new \GuzzleHttp\Pool($guzzle, $requests, [
    'fulfilled' => function ($response, $index) use (&$graph) {
        $graph->parse((string) $response->getBody(), 'text/turtle', $index);
    },
    'rejected' => fn ($reason, $index) => Log::warning("RDF fetch failed: $index", ['reason' => (string) $reason]),
]);
$pool->promise()->wait();

Content negotiation is your responsibility. EasyRdf does not always set a rich Accept header. If a server serves HTML to */*, EasyRdf will fail to parse it as RDF. Set Accept on the Guzzle client per format.

Testing. Replace the client in tests with a Guzzle MockHandler + history middleware, and remember to reset EasyRdf's static state (see Gotchas):

public function setUp(): void
{
    parent::setUp();
    \EasyRdf\Graph::reset();
    $mock = new \GuzzleHttp\Handler\MockHandler([
        new \GuzzleHttp\Psr7\Response(200, ['Content-Type' => 'text/turtle'], $this->turtleFixture),
    ]);
    \EasyRdf\Http::setDefaultHttpClient(
        new \MadBob\EasyRdfOnGuzzle\Client(new \GuzzleHttp\Client(['handler' => \GuzzleHttp\HandlerStack::create($mock)]))
    );
}

Gotchas and Tips

  • setDefaultHttpClient() is global static state. Any other package, or EasyRdf\Http::getDefaultHttpClient(), will see the change. Register it once at boot, and be aware that long-running workers (Octane, queue workers) keep it across requests — that's fine if configured once, disastrous if you re-bind per request with request-scoped credentials.
  • Set http_errors => false. Guzzle throws RequestException on 4xx/5xx by default; EasyRdf's client contract expects a response object it can inspect for status. Without this you get confusing exceptions from deep inside EasyRdf.
  • Redirects. Guzzle follows redirects by default (up to 5). EasyRdf's own adapters also handle them, and some code paths inspect the final URI for base resolution. Prefer Guzzle doing the following and verify that $graph->getUri() is the final, post-redirect URI — otherwise relative IRIs resolve against the wrong base.
  • EasyRdf caches loaded graphs in a static registry keyed by URI. Two calls to Graph::newAndLoad($uri) in one process return the same graph object. In tests and in queue loops this leaks state; call \EasyRdf\Graph::reset() (or $graph->reset()) between iterations.
  • No async in EasyRdf. The Guzzle adapter still satisfies a synchronous interface, so you gain middleware, not concurrency, from Graph::load() alone. Use Pool explicitly if you need parallelism.
  • Version skew. Guzzle 6 and Guzzle 7 have different middleware signatures (Middleware::retry exists in both, but kevinrob/guzzle-cache-middleware majors differ). Confirm which the package permits in its composer.json before designing around it.
  • Char/gzip handling. Ensure decode_content is on (default) and that the response body is read with (string) $response->getBody() before handing it to Graph::parse(); EasyRdf will not rewind a stream.
  • TLS/proxies in corporate environments are the classic reason this package gets adopted; a single Guzzle config (verify, proxy, cert) fixes vocabulary fetching app-wide. Keep a local file-based fallback for the handful of vocabularies you depend on.
  • Maturity risk. Zero dependents, zero stars, single maintainer, and EasyRdf is essentially unmaintained. Read the source (it's small) and be prepared to fork or replace it with a ~50-line adapter implementing EasyRdf\Http\Client\Adapter\AdapterInterface (or subclassing EasyRdf\Http\Client and overriding request()). Budget for that as an exit path.
  • Debugging. 'debug' => true on the Guzzle client dumps the wire; combined with Graph::dump() and the history middleware you can trace any Graph::newAndLoad() failure end to end. Also check $httpClient->getLastResponse()->getStatus() — the most common failure is a 406 from aggressive content negotiation.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin