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

Recordsapi Laravel Package

laravel-liberu/recordsapi

A Laravel package that adds a records API layer for Liberu applications, exposing endpoints to browse, filter, create, and manage records consistently. It streamlines CRUD and data access for frontends and integrations.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require laravel-liberu/recordsapi
php artisan vendor:publish --tag=recordsapi-config   # if a config file ships with it

The package is part of the Laravel Liberu (ex-Enso) monorepo family, so treat package versions as a set — bump laravel-liberu/* together rather than pinning this one alone.

Where to look first, in this order:

  1. config/recordsapi.php — the knobs (pagination defaults, relation/include whitelists, middleware stack). If it does not exist after publishing, the package is probably convention-only and everything is configured per-controller.
  2. src/Http/Controllers/ — the base controller you are expected to extend.
  3. src/Resources/ (or src/Http/Resources/) — how models get transformed to JSON.
  4. tests/ — for an unstarred package this is the real documentation. Read the feature tests before the README; they show the exact request/response shape.

First use case — expose one existing Eloquent model as a read endpoint:

// app/Http/Controllers/Api/ProjectController.php
namespace App\Http\Controllers\Api;

use App\Models\Project;
use LaravelLiberu\RecordsApi\Http\Controllers\ApiController;

class ProjectController extends ApiController
{
    protected string $model = Project::class;
}
// routes/api.php
Route::apiResource('projects', ProjectController::class)
    ->only(['index', 'show'])
    ->middleware('auth:sanctum');

Then hit GET /api/projects?perPage=25&sort=name. If you get a 500 about a missing method, the base class is expecting properties under different names — check the abstract declaration in src/Http/Controllers/ApiController.php and match it exactly.

Implementation Patterns

Declarative whitelisting beats ad-hoc queries. The whole point of a package like this is that the client drives sort, filter, include, and paginate via query string, and the server only permits what the controller declares:

class ProjectController extends ApiController
{
    protected string $model = Project::class;

    protected array $allowedFilters = ['status', 'client_id', 'created_at'];
    protected array $allowedSorts   = ['name', 'created_at', 'deadline'];
    protected array $allowedIncludes = ['client', 'tasks', 'tasks.assignee'];
    protected array $defaultSort = ['created_at' => 'desc'];
}

Client usage then stays uniform across every resource in the app:

GET /api/projects?filter[status]=active&include=client,tasks&sort=-deadline&perPage=50

Controller-per-resource, resource-class-per-shape. Keep the controller thin and move presentation into a resource/transformer so the same model can be served differently to a table view (flat, row-oriented) versus a detail view (nested relations). Follow whatever toArray() contract the package defines rather than inventing your own envelope — the Liberu frontend packages (tables, forms) deserialize the standard { data, meta, links } shape and will silently render empty tables if you deviate.

Lean on index for the Liberu table component. The most common day-to-day integration is: a Liberu table in the UI hits your index endpoint, passing its column/sort/filter state straight through. That means your $allowedSorts must contain exactly the column names the table component emits, or sorting will appear to work in the UI and do nothing on the server.

Authorization belongs in the controller, not the query. Add an explicit gate/policy check inside each action — an allowlisted filter is not an authorization boundary. A scoped endpoint (e.g. "my projects only") should constrain the base query and validate that client_id filters cannot escape the user's scope:

protected function query(): Builder
{
    return parent::query()->where('tenant_id', auth()->user()->tenant_id);
}

Write paths use FormRequests. Let the package handle read serialization and keep validation in dedicated FormRequest classes so store/update failures return the standard 422 payload the frontend already knows how to render.

Compose with the rest of Liberu. This package is a transport layer, not an application layer — put business rules in actions/services and call them from the controller so the same logic is reusable from queued jobs and CLI commands.

Gotchas and Tips

  • N+1 will bite immediately. include= params must resolve to eager loads, not lazy relation access in the transformer. If the resource class touches $this->client->name without client being in $allowedIncludes and actually loaded, you get one query per row. Enable DB::listen or Laravel Telescope on a 100-row page and count queries before shipping.
  • Sorting joined columns needs a table prefix. sort=client.name typically fails or sorts wrong unless your query builder joins and you allow clients.name. Prefer sorting on the base table and sorting relations separately.
  • config:cache after editing the config. Liberu packages often read config in a service provider's register(); a stale cached config produces "why is my change ignored" for an hour of your life. php artisan optimize:clear when in doubt.
  • Version skew across laravel-liberu/*. Because these packages assume a shared core (helpers, structure, actions), a mismatch shows up as a Class not found or a signature error deep in a trait, not in your code. Check composer.lock for the whole family before debugging your own controller.
  • The base controller's property names are the API. Guessing between $allowedFilters / $filters / filters() is the single most common first-hour stumble. Read the abstract class, don't infer from another Liberu package's README — forks drift.
  • Response envelope changes break the UI silently. A missing meta.current_page or a data key renamed to items will not throw; tables just render empty. Assert the JSON structure in a feature test (assertJsonStructure) rather than eyeballing Postman.
  • Soft deletes and route model binding. If the package resolves models itself, withTrashed() and onlyTrashed() behaviour is not automatic. Check whether a trashed filter exists before promising restore endpoints.
  • Debugging extension points: the usual seams are (a) override the resource/transformer class, (b) override query() in your controller, (c) bind a custom implementation in a service provider if the package ships an interface. Reach for (a) and (b) first; (c) is the escape hatch when you need to change pagination or envelope shape globally.
  • Zero stars means zero community answers. Budget time for reading source. Every behavioural question — parameter names, default page size, error format — is a two-minute grep in vendor/laravel-liberu/recordsapi/src, and that is faster and more reliable than any search engine result you will find.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
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
cgv/localized-resource