baconfy/variants

Composable API resources for Laravel via server-side variants

Maintainers

Package info

github.com/baconfy/variants

pkg:composer/baconfy/variants

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-05-20 07:49 UTC

This package is auto-updated.

Last update: 2026-05-20 10:11:09 UTC


README

Prompt

Tests Latest Version License Total Downloads PHP Version

baconfy/variants

Composable API resources for Laravel. Define named blocks, group them into variants, and select the right shape per endpoint — all in one class, no controllers bloated with conditional fields.

Installation

composer require baconfy/variants

Requires PHP 8.2+ and Laravel 12+.

Minimal example

1. Define a resource

use Baconfy\Variants\ComposableResource;
use Illuminate\Http\Request;

final class ProductResource extends ComposableResource
{
    protected function core(): array
    {
        return [
            'id'   => $this->resource->id,
            'name' => $this->resource->name,
        ];
    }

    protected function pricing(): array
    {
        return ['price' => $this->resource->price];
    }

    protected function full(): array
    {
        return ['description' => $this->resource->description];
    }

    protected function locale(Request $request): array
    {
        return ['locale' => $request->header('Accept-Language', 'en')];
    }

    protected function variants(): array
    {
        return [
            'list' => ['core', 'pricing'],
            'show' => ['core', 'pricing', 'full'],
            'i18n' => ['core', 'locale'],
        ];
    }

    protected function default(): string
    {
        return 'list';
    }
}

2. Use it

// Default variant (list → core + pricing)
ProductResource::make($product);

// Named variant
ProductResource::make($product)->as('show');

// Variant + extra block
ProductResource::make($product)->as('list')->with('full');

// Ad-hoc selection — no variant, just the blocks you name
ProductResource::make($product)->only('core', 'full');

// Collection — variant propagates to every item
ProductResource::collection($products)->as('list');

// Collection — variant + extra blocks
ProductResource::collection($products)->as('list')->with('full');

3. Resolve in a controller

public function index(): JsonResponse
{
    return ProductResource::collection(Product::paginate())
        ->as('list')
        ->response();
}

public function show(Product $product): JsonResponse
{
    return ProductResource::make($product)
        ->as('show')
        ->response();
}

API reference

Method Description
::make($model) Single resource, default variant
::collection($items) Collection, default variant
->as(string $variant) Switch to a named variant
->with(string ...$blocks) Append extra blocks (additive, chainable)
->only(string ...$blocks) Replace selection with exactly these blocks, no variant
->resolve($request?) Resolve to plain array
->response($request?) Return JsonResponse

How blocks work

A block is any protected method on your resource class that:

  • returns array
  • is listed in at least one variant inside variants()
  • optionally accepts Illuminate\Http\Request as its first (and only) parameter

Helper methods on the resource class that are not listed in variants() cannot be called via with() or only() — this is intentional. The variants() array is the single source of truth for what is a block.

Exceptions

All exceptions extend \RuntimeException.

UnknownVariantException

Thrown by ->as() when the variant name is not a key in variants(). Also thrown at first instantiation if default() returns a name not in variants().

Unknown variant [xyz] on [App\Http\Resources\ProductResource]. Available: [list, show, i18n].

UnknownBlockException

Thrown by ->with() and ->only() immediately (not at resolve time) when a block name is not referenced in any variant. Also thrown at first instantiation if a variant references a method that does not exist on the class.

Unknown block [xyz] on [App\Http\Resources\ProductResource]. Available: [core, pricing, full, locale].

DuplicateBlockKeyException

Thrown at resolve time when two blocks in the active selection return the same top-level key.

Duplicate key [name] in [App\Http\Resources\ProductResource]: produced by both [core] and [alias].

Notes on with() and PHP compatibility

JsonResource::with($request) is an existing method used internally by Laravel's resource response layer. PHP's method compatibility rules prevent overriding it with with(string ...$blocks): static, so the parameter type is declared mixed. The method body validates string types and guards against the internal Request call. Runtime behaviour is identical to what the spec describes.

License

AGPL-3.0-only — see LICENSE.