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

Json Api Client Bundle Laravel Package

enm/json-api-client-bundle

Symfony integration for enm/json-api-client that lets you configure JSON:API clients in YAML and exposes each as a private service named enm.json_api_client.YOUR_CLIENT_NAME. Works with any PSR-18 HTTP client, such as Buzz with Nyholm PSR-7.

View on GitHub
Deep Wiki
Context7

Getting Started

This bundle is a thin Symfony DI wrapper around enm/json-api-client. Its only real job is to turn YAML client definitions into configured, injectable client services — so treat it as glue, not as a full-stack JSON:API toolkit.

Minimal setup:

composer require enm/json-api-client-bundle
# pick a PSR-18 client + PSR-7 factory (recommended by the README)
composer require kriswallsmith/buzz nyholm/psr7

Register the bundle in config/bundles.php:

return [
    // ...
    Enm\Bundle\JsonApi\Client\EnmJsonApiClientBundle::class => ['all' => true],
];

Declare at least one client in config/packages/enm_json_api_client.yaml (the bundle throws if clients is empty):

enm_json_api_client:
    clients:
        api: 'http://example.com/api'

Where to look first:

  • enm.json_api_client.api — the generated private service. Every configured key under clients becomes a service named enm.json_api_client.<name>.
  • The upstream enm/json-api-client docs — the bundle adds almost no API surface; nearly all behavior (resources, relationships, errors) lives upstream.

First use case: fetch a single resource and map it to a typed object. Inject the client into a service or controller action, call the client's request method for the resource type, and inspect the resulting document/resource object. Because the service is private, you must inject it — $container->get('enm.json_api_client.api') will fail.

final class ArticleFetcher
{
    public function __construct(
        private \Enm\JsonApi\Client\JsonApiClient $client,
    ) {}
}

…and wire the private service to that argument in config/services.yaml (see next section).

Implementation Patterns

Alias the generated client to a concrete type. Because the bundle only registers a private, string-named service, the idiomatic pattern is to alias it to an autowirable class name and — where you have multiple clients — use a named binding:

# config/services.yaml
services:
    _defaults:
        autowire: true
        autoconfigure: true

    Enm\JsonApi\Client\JsonApiClient:
        alias: enm.json_api_client.api

    # multiple clients: bind by argument name
    App\Api\CmsClient:
        arguments:
            $client: '@enm.json_api_client.cms'

Multi-client / multi-environment setups. Since the YAML key is the service suffix, use environment-specific config to point the same client name at different base URLs:

# config/packages/dev/enm_json_api_client.yaml
enm_json_api_client:
    clients:
        api: '%env(API_BASE_URI)%'

Keep a single logical name (api) per environment and swap only the URL. This avoids conditional service IDs in your code.

Wrap the client in a domain repository. The raw client is request-oriented; encapsulate your own methods so callers don't leak JSON:API vocabulary into application code:

final class ArticleRepository
{
    public function __construct(private JsonApiClient $client) {}

    public function get(string $id): Article
    {
        // Build the request for type=articles, id=$id, then map the
        // returned ResourceObject onto your Article DTO.
    }
}

Reuse a single HTTP stack. Register one PSR-18 client and one PSR-7 factory as services and let Symfony autowire them into the bundle's client factory. This gives you centralized timeout, retry, and logging middleware:

services:
    Psr\Http\Client\ClientInterface: '@Http\Client\Common\PluginClient'
    Psr\Http\Message\ResponseFactoryInterface: '@Nyholm\Psr7\Factory\Psr17Factory'

Add a logging plugin to the PSR-18 client rather than trying to log inside the bundle — it has no Symfony HTTP-client integration.

Testing. Because the bundle just injects a PSR-18 client, tests should replace the underlying HTTP client with a mock/stub PSR-18 implementation. Don't mock the bundle service; mock one layer lower so you exercise the actual JSON:API request building.

Gotchas and Tips

  • The package is archived and effectively unmaintained (0 stars, 0 dependents, README-only maturity). Treat it as a stable-but-frozen integration; audit the upstream enm/json-api-client before long-term adoption, and consider inlining the tiny Extension class yourself if you only need the DI wiring — it's a handful of lines and removes the abandoned dependency.
  • Services are private by convention. The README explicitly warns the generated services are for DI only. If you need runtime lookup, either define your own public alias or, preferably, refactor to injection.
  • Empty clients is a hard error. At least one key is required; there's no "no config" fallback. If you enable the bundle in an environment with no clients, the container build fails.
  • Naming collision risk. Service IDs follow enm.json_api_client.<key> literally — a client named api.v2 yields a dotted, awkward-looking ID, and the key is case-sensitive. Stick to snake_case keys.
  • No Symfony profiler/web-profiler bridge. You won't get a JSON:API panel; debug by logging at the PSR-18 layer (e.g., a Buzz LoggerMiddleware) instead.
  • PSR-18 + PSR-7 are runtime requirements, not enforced dependencies. Composer won't stop you from installing without an HTTP client; failures appear at container-wire or request time, not at composer require. Install both explicitly.
  • Error handling lives upstream. JSON:API error documents (errors[]) are surfaced by enm/json-api-client's exception types, not by the bundle. Catch the upstream exception and map it to your domain exceptions in a single place.
  • Extension point is narrow. There's no compiler pass documented for decorating the client factory; the clean extension point is a services.yaml decorator around the generated client or, better, the PSR-18 client itself (retries, auth headers, base-URI rewriting).
  • Version drift. Since the bundle is a thin wrapper, pin the upstream enm/json-api-client version explicitly in composer.json to avoid a silent major-version bump changing deserialization behavior under you.
  • Base URL trailing slash. http://example.com/api vs http://example.com/api/ can produce different relative request paths depending on the upstream URI resolver — keep it consistent across environments and add an integration test asserting the outbound URL.
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/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
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route