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

Symfony Drupal Jsonapi Laravel Package

roensby/symfony-drupal-jsonapi

A Symfony integration for Drupal's JSON:API, providing services and tools to query and consume Drupal content endpoints cleanly. Simplifies fetching, mapping, and working with JSON:API resources in Symfony applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Start by reading composer.json and the src/ directory before installing — with zero dependents and no stars, the source is the only reliable documentation. Check the package's Symfony version constraint and whether it registers a bundle (*Bundle class under src/), a service definition, or is purely a set of plain classes you wire yourself.

Minimal setup:

  1. composer require roensby/symfony-drupal-jsonapi
  2. If a bundle exists, register it in config/bundles.php; otherwise define the client service in config/services.yaml.
  3. Configure the Drupal base URL (e.g. https://example.drupal.site) so the client can build /jsonapi/{entity_type}/{bundle} paths.
  4. Confirm your Drupal side is actually ready: the JSON:API module must be enabled, and permissions granted for anonymous/authenticated users on the resources you want to read (admin/people/permissions → JSON:API). If authentication is required, add a Authorization: Basic ... header (HTTP Basic Auth via the basic_auth Drupal module is the common path) or an OAuth2 bearer token.

Your first use case: fetch a list of published articles.

// Pseudocode — verify method names against the package source.
$client = $container->get(JsonApiClient::class);

$result = $client->getCollection('node', 'article', [
    'filter[published]' => 1,
    'sort'              => '-created',
    'page[limit]'       => 10,
]);

foreach ($result->getData() as $article) {
    dump($article->getAttributes()['title']);
}

The single most important thing to understand before writing any code: Drupal's JSON:API returns JSON:API documents, not flat arrays. Expect data, included, relationships, links, and meta. The package's value-add is turning that verbose structure into something resembling Drupal entity objects — so lean on its entity/attribute helpers rather than manually digging through the response.

Implementation Patterns

Wrap the client in a repository per entity type. Don't scatter getCollection('node', 'article', ...) calls across controllers. Create an ArticleRepository that injects the client, owns the field/filter names, and returns typed domain objects. This gives you exactly one place to change when the Drupal field names or JSON:API quirks bite you.

Resolve relationships deliberately. JSON:API returns relationships as {data: {type, id}} references. Use include= to pull related resources into the top-level included array in one request rather than N+1 round trips:

$client->getCollection('node', 'article', [
    'include' => 'field_tags,uid',
]);

Then resolve references against included. The package may expose helpers for this; if not, build a small $includedIndex[strType][$id] map once per response.

Use typed wrappers for entities. If the package ships entity classes (Node, User, Term, etc.), subclass them or write thin decorators adding getTitle(), getPath(), getBody() accessors. Attribute keys are Drupal machine names (field_hero_image, body), and centralising that mapping makes future field renames trivial.

Pagination via links.next. Drupal's JSON:API paginates with page[offset] / page[limit] and returns a links.next href. Build a generator that follows next until absent, rather than guessing total counts:

$offset = 0;
$limit  = 50;
do {
    $page = $client->getCollection('node', 'article', [
        'page[offset]' => $offset,
        'page[limit]'  => $limit,
    ]);
    yield from $page->getData();
    $offset += $limit;
} while ($page->hasNextPage());

Integration tips:

  • Configure timeouts and retries on the underlying Symfony HttpClient. Drupal sites can be slow under uncached JSON:API requests; a 30s timeout with one retry is reasonable.
  • Respect Drupal's cache tags. If you cache responses yourself, key them by JSON:API's meta (or the X-Drupal-Cache-Tags header, if exposed by your proxy). Better yet: proxy through Drupal's own cache and don't double-cache.
  • Use the client for reads, not writes, in day-to-day use. JSON:API supports POST/PATCH but write permissions are fiddly. For writes, prefer a Drupal-side REST resource or a thin custom endpoint.
  • Register it as a named HttpClient in framework.http_client.scoped_clients and pass that to the package if it accepts a client — this avoids the package forcing its own transport config.
  • Test against a real Drupal. Mocks of JSON:API documents are brittle; spin up Drupal in DDEV or use a fixture site. Integration tests catch relationship-include edge cases that unit tests miss.

Gotchas and Tips

This package has an extremely low signal footprint. Zero stars, zero dependents, a low opportunity score. Do not assume the README is accurate or that the API is stable. Before committing, read the source and add a composer.lock pin to a specific tag/commit. Vendor it or fork it if you rely on it long-term — expect no upstream support.

included is deduplicated and not guaranteed. When you include multiple relationships, a single entity may appear once in included but be referenced from many relationships. Always build an index by (type, id); never assume order.

Empty relationships look like data: null or data: []. A single-valued relationship (e.g. uid) returns data: {type: "user--user", id: "5"}; multi-valued (tags) returns an array; empty returns null or [] depending on cardinality. Guard both.

Filter operators are a string DSL. filter[title][operator]=CONTAINS and filter[title][value]=foo are different shapes — mistakes here silently return unfiltered or empty results. Verify by echoing the built URL before sending.

Attribute types don't round-trip cleanly. Drupal JSON:API returns dates as ISO-8601 strings, booleans as true/false, and some fields (text with format) as nested objects {value, format, processed}. If the package's entity classes cast lazily, confirm the cast for each field you actually consume.

403 vs 401 vs 404 are meaningful and distinct. A resource that exists but you can't read returns 403; a bundle with JSON:API disabled returns 404. Wrap calls so you can distinguish these in logs — "not found" in a client often means "permission denied" in Drupal.

links.self includes the full base URL as Drupal sees it. Behind a reverse proxy with a misconfigured trusted host, this can be an internal hostname. If the package follows links.next blindly, requests may break in production. Sanity-check the base URL config.

Extension points to look for in src/: a serializer/normalizer for entity hydration, an interface for custom entity classes, and a client/factory that accepts an injected HttpClientInterface. These are your realistic hooks for adapting Drupal-specific field handling without patching the package.

Debugging: log the fully constructed request URL and the raw response body at debug level. JSON:API errors come back as {errors: [{status, title, detail, source: {pointer}}]} — surface detail and source.pointer in exceptions; they usually name the exact invalid filter path or field.

If the package proves unmaintained, the fallback is short. Symfony HttpClient plus a small JSON:API normalizer is ~150 lines and removes a dependency risk. Given the package's maturity level, budget for that possibility from day one.

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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect