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

Recommerce Laravel Package

splash/recommerce

splash/recommerce is a Laravel-native foundation for building recommerce and e-commerce flows, with models and services for products, carts, checkout, orders, and returns. It plugs into existing Laravel apps and keeps storefront business logic testable and configurable.

View on GitHub
Deep Wiki
Context7

Getting Started

Install

composer require splash/recommerce

The package is an OpenAPI-generated client, so there is no migrations, no publishable config file, and typically no service provider bindings beyond what splash/connector-utils provides. You wire it up yourself.

Where to look first

  1. vendor/splash/recommerce/src/Client.php — the generated client. Every endpoint on the ReCommerce API surfaces here as a method (getOrders(), createReturn(), getProduct() …). Skim it; it is the API documentation.
  2. vendor/splash/recommerce/src/Model/ — generated DTOs for requests and responses. Property names here map 1:1 to the JSON payloads.
  3. composer.json — check the required PHP version and whether it pins psr/http-client / jane-php/* versions you already have.
  4. The upstream OpenAPI spec on GitLab — the generated code is hard to read for request shapes until you cross-reference the spec.

First call in a Laravel app

use Splash\ReCommerce\Client;
use Splash\ConnectorUtils\Connector;

// In a service provider or a dedicated factory
$this->app->singleton(Client::class, function () {
    $client = new Client();
    $client->setBaseUrl(config('services.recommerce.base_url'));
    // Most Splash connectors accept either a bearer token or API key
    $client->setApiKey(config('services.recommerce.api_key'));

    return $client;
});
public function index(Client $client)
{
    $orders = $client->getOrders(['status' => 'open']);

    return view('orders.index', ['orders' => $orders]);
}

Configure services.recommerce.* in config/services.php and put values in .env. Then make one read-only endpoint call in a Tinker session to confirm the base URL and auth header format are correct before writing anything else.

Implementation Patterns

Wrap the client, don't inject it everywhere

The generated client leaks transport concerns and unstable generated model types through your codebase. Put a thin adapter around it:

final class ReCommerceGateway
{
    public function __construct(private Client $client) {}

    public function openOrders(): array
    {
        return $this->client->getOrders(['status' => 'open'])->getData();
    }
}

Bind ReCommerceGateway in the container, and mock the gateway in tests instead of the generated client.

Use a single configured instance

ReCommerce's generated clients are stateful — setBaseUrl, setApiKey, and the PSR-18 client all live on the instance. Register it as a singleton in a service provider so you're not re-running config on every request, and so retries/timeouts on the underlying HTTP client apply consistently.

Swap in the HTTP client for testing and observability

Splash connectors are built on psr/http-client (via HTTPlug/jane-php). That means you can pass a MockHttpClient in tests or a client decorated with logging middleware (e.g. Http\Client\Common\Plugin\LoggerPlugin) without touching package code:

$client = new Client();
$client->setHttpClient(new MockHttpClient([$response]));

This is the cleanest way to write tests against the connector — assert the request your code produced, not just the response you consumed.

Paginate by hand

Generated clients rarely expose a paginate() iterator. Look for page / perPage / offset parameters on the list methods and write a simple generator in your gateway:

public function allOrders(): \Generator
{
    $page = 1;
    do {
        $batch = $this->client->getOrders(['page' => $page, 'per_page' => 100])->getData();
        yield from $batch;
        $page++;
    } while (count($batch) === 100);
}

Integrate via queued jobs, not request cycle

ReCommerce calls are e-commerce-adjacent — order lookups, return creation, product fetches. Anything write-shaped (creating returns, updating fulfilment state) should live in a queued job with retry semantics. Read-shaped calls in the request path are fine for low-traffic admin screens, but cache product/lookup data with Cache::remember — these are slow, rate-limited external calls.

Treat responses as DTOs

Generated response models (Model\Order, Model\LineItem) are plain objects with getters. Convert them into your own domain models at the gateway boundary:

public function mapOrder(Model\Order $order): Order
{
    return new Order(
        id: $order->getId(),
        status: $order->getStatus(),
        total: $order->getTotal()->getAmount(),
    );
}

This means a splash/recommerce upgrade that renames a generated property doesn't ripple through your controllers.

Gotchas and Tips

Generated code has no semantic versioning safety

Because the client is generated from an OpenAPI spec, minor releases can break you silently — an endpoint may be regenerated with a different method signature or a model property may be renamed. Pin the version in composer.json with ~ and read the diff before bumping. There is no README guarantee that method names are stable.

Exception types are jane-php's, not Laravel's

Expect Http\Client\Exception\ClientException for 4xx and ServerException for 5xx. They do not extend Illuminate\... classes, so $e instanceof ModelNotFoundException checks will not fire. Centralise handling in a gateway decorator:

try {
    return $this->client->getOrder($id);
} catch (ClientException $e) {
    if ($e->getResponse()?->getStatusCode() === 404) {
        throw new OrderNotFound($id);
    }
    throw $e;
}

Auth header format is not obvious

Depending on which Splash connector variant this is derived from, auth is either Authorization: Bearer <token> or an X-Api-Key header. The setApiKey() method name suggests the latter, but verify against the spec — sending the wrong header usually produces a generic 401 and wastes an hour.

Base URL matters for sandbox vs. production

Splash connectors target an embedded/proxy environment, not api.recommerce.com directly. Confirm the base URL with the repo maintainers rather than guessing; the default in Client.php may point at a staging host.

No Laravel facade or auto-registration

Unlike first-party packages, this won't appear in config/app.php automatically and there's no ReCommerce:: facade. If you want that ergonomics, write your own service provider and facade around the singleton.

Rate limiting is your responsibility

Generated clients don't rate-limit. If you're syncing orders or products on a schedule, add a RateLimiter::for('recommerce', ...) in your job and throttle with ->middleware(['throttle:recommerce']). Hitting the provider's limit tends to surface as 429s that jane-php throws as generic ClientException.

Testing against generated models is brittle

Because the generated models often lack constructors with defaults, unit-testing a mapping function means constructing a Model\Order via setters rather than new Order(...). Prefer a fixture JSON file plus a real deserialisation via the generated serializer (jane-php's Serializer\ArrayTransformer) over hand-building models.

Extension points are limited

There's not much to override — extend the Client subclass if you need to inject default headers (e.g. an X-Request-Id for tracing), and use PSR-18 middleware for anything cross-cutting. There is no event/hook system.

Zero dependents, low score — treat as internal

With no dependents and no stars, this is effectively a privately consumed package. Expect to read the source to answer most questions, and be prepared to fork if you need a fix. Log a composer.json constraint and consider vendoring via a fork for stability.

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.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource