Weave Code
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

Laravel Apiable Laravel Package

open-southeners/laravel-apiable

View on GitHub
Deep Wiki
Context7

description: Scope API queries by user access using viewable query scopes on your models.

Viewable Queries

Viewable queries let you automatically restrict which resources a request returns based on who is making it. When enabled, JsonApiResponse calls a scope on your model or query builder before executing the query — so unauthenticated users or users without access simply never see those records.

How it works

After the request pipeline (filters, sorts, includes, fields) runs, JsonApiResponse checks:

  1. Whether apiable.responses.viewable is true (the default).
  2. Whether the model implements ViewQueryable or the query builder implements ViewableBuilder.

If both conditions are true the scope is applied with the currently authenticated user, which may be null for unauthenticated requests.

ViewQueryable — model-level scope

Implement ViewQueryable on your Eloquent model and add a scopeViewable method. The method receives the builder and the optional authenticated user.

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use OpenSoutheners\LaravelApiable\Contracts\JsonApiable;
use OpenSoutheners\LaravelApiable\Contracts\ViewQueryable;

class Film extends Model implements JsonApiable, ViewQueryable
{
    /**
     * Scope applied to the query for show/hide items.
     */
    public function scopeViewable(Builder $query, ?Authenticatable $user = null): void
    {
        if ($user === null) {
            // Unauthenticated: only show publicly available films
            $query->where('public', true);

            return;
        }

        // Authenticated: show films the user owns or that are public
        $query->where(function (Builder $q) use ($user) {
            $q->where('public', true)
              ->orWhereHas('author', fn (Builder $q) => $q->whereKey($user->getKey()));
        });
    }
}

Laravel calls scopeViewable as a local query scope, so the method name must be prefixed with scope.

ViewableBuilder — custom builder scope

If your model uses a custom Eloquent builder, implement ViewableBuilder on that builder class instead. The viewable() method receives the optional authenticated user and must return the builder for chaining.

<?php

namespace App\Builders;

use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Builder;
use OpenSoutheners\LaravelApiable\Contracts\ViewableBuilder;

/**
 * [@template](https://github.com/template) TModelClass of \Illuminate\Database\Eloquent\Model
 *
 * [@extends](https://github.com/extends) Builder<TModelClass>
 */
class FilmBuilder extends Builder implements ViewableBuilder
{
    /**
     * Scope applied to the query for show/hide items.
     *
     * [@return](https://github.com/return) \Illuminate\Database\Eloquent\Builder<TModelClass>
     */
    public function viewable(?Authenticatable $user = null): static
    {
        if ($user === null) {
            return $this->where('public', true);
        }

        return $this->where(function (Builder $q) use ($user) {
            $q->where('public', true)
              ->orWhereHas('author', fn (Builder $q) => $q->whereKey($user->getKey()));
        });
    }
}

Then tell your model to use this builder:

class Film extends Model implements JsonApiable
{
    public function newEloquentBuilder($query): FilmBuilder
    {
        return new FilmBuilder($query);
    }
}

JsonApiResponse detects ViewableBuilder on the query instance automatically — no additional interface on the model is needed.

Global configuration

The viewable feature is enabled by default. To disable it globally, set the config option to false:

// config/apiable.php
'responses' => [
    'viewable' => false,
],

Per-request toggle

conditionallyLoadResults()

Override the global setting for a single response using conditionallyLoadResults():

// Disable viewable scoping for an admin-only endpoint
JsonApiResponse::from(Film::class)
    ->conditionallyLoadResults(false);

// Re-enable if you have disabled it globally but need it for one endpoint
JsonApiResponse::from(Film::class)
    ->conditionallyLoadResults(true);

This is particularly useful for admin controllers where authenticated staff should see all records:

class AdminFilmController extends Controller
{
    public function index(): JsonApiResponse
    {
        return JsonApiResponse::from(Film::class)
            ->allowing([
                AllowedFilter::exact('active'),
            ])
            ->conditionallyLoadResults(false); // admins see everything
    }
}

{% hint style="warning" %} conditionallyLoadResults() modifies the apiable.responses.viewable config value in-place for the duration of the current request. If you run multiple responses in a single request lifecycle (uncommon) ensure each one sets its own value. {% endhint %}

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.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle