Getting started
Install storageitsolutions/api-tables and add your first control table
This guide walks you through your first working table from zero. No prior ApiTables experience required. If you already know Laravel, you can finish in under an hour.
Read first
New to the concept? Spend 10 minutes on Key concepts so terms like structure, query, and table name are clear before you copy-paste config.
What you will build
By the end of this guide you will have:
- The package installed and configured
- A
UsersTableclass with two columns - A working
load-tableandquery-tableresponse - A curl command you can run to verify everything
The frontend team can then point their ApiTables page at your endpoints.
Prerequisites
| Requirement | Why |
|---|---|
| Laravel app (10+) | Package uses service provider, routes, Eloquent |
| PHP 8.1+ | Match your app's PHP version |
| Laravel Sanctum | Default auth middleware is auth:sanctum |
api guard in config/auth.php | Routes register under {guard}/api-table/... |
| Valid API token for testing | Unauthenticated requests return 401 |
Optional later:
- Queue worker — only needed for email report bulk actions
- Published lang files — for translated column headers
Install the package
composer require storageitsolutions/api-tablesThe service provider registers automatically — you do not add it to config/app.php manually.
Publish files into your app:
php artisan vendor:publish --tag=config # → config/api-tables-config.php
php artisan vendor:publish --tag=lang # → lang files for column labels
php artisan vendor:publish --tag=views # → email templates for reportsPackage identifiers
| What | Value |
|---|---|
| Composer | storageitsolutions/api-tables |
| Namespace | Storageitsolutions\ApisTables |
| Config key | api-tables-config (file: config/api-tables-config.php) |
Register your first table
Open config/api-tables-config.php. Think of the tables array as a phone book: the key is the public table name used in URLs; the value tells the package which model and class to use.
'guards' => ['api'],
'default_middlewares' => ['auth:sanctum'],
'tables' => [
'users' => [
'model' => App\Models\User::class,
'tableClass' => App\ApiTables\UsersTable::class,
// 'middlewares' => ['admin'], // uncomment when you need extra auth
],
],
'user_model' => App\Models\User::class,Rules to remember:
- The config key (
users) must matchTABLENAMEin your table class modelmust be a valid Eloquent model classtableClassmust extendTableAbstract
Generate the table class
php artisan make:api-table UsersTableThis creates app/ApiTables/UsersTable.php from the package stub. You will edit three things minimum:
const TABLENAME = 'users'$TBLColumns— what columns appearsetInitialBuilder()— base Eloquent query
Complete minimal example
<?php
namespace App\ApiTables;
use Storageitsolutions\ApisTables\Abstracts\TableAbstract;
use Storageitsolutions\ApisTables\Interfaces\APITableInterface;
class UsersTable extends TableAbstract implements APITableInterface
{
const TABLENAME = 'users';
protected array $TBLColumns = [
[
'type' => 'text',
'label' => 'name',
'data_src' => 'name',
'sortable' => true,
'attributes' => ['showable' => true],
],
[
'type' => 'text',
'label' => 'email',
'data_src' => 'email',
'sortable' => true,
'attributes' => ['showable' => true],
],
];
public function __construct(...$args)
{
parent::__construct(self::TABLENAME);
}
protected function setInitialBuilder(): void
{
// Start from the model defined in config
$this->builder = $this->model::query();
}
public function filters(bool $api_array = true): array
{
return []; // add filters later — see /docs/filters
}
}What each part does
| Piece | Purpose |
|---|---|
TABLENAME | Links this class to config tables.users and URL /load-table/users |
$TBLColumns | Becomes the columns array in structure JSON |
setInitialBuilder() | Defines which rows are eligible (add where, with, policies here) |
filters() | Returns filter definitions — empty array means no filter UI |
Verify it works
Route paths
With guards => ['api'] and Laravel's default RouteServiceProvider prefix:
| Action | Method & path |
|---|---|
| Load structure | GET /api/api-table/control-tables/load-table/users |
| Query data | POST /api/api-table/control-tables/query-table/users |
Test structure (GET)
export TOKEN="your-sanctum-token"
curl -s -H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json" \
https://your-app.test/api/api-table/control-tables/load-table/users | jq .Expected: "success": true and a columns array with name and email.
Test query (POST)
curl -s -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"page":1,"perPage":10,"filters":[],"sorts":[]}' \
https://your-app.test/api/api-table/control-tables/query-table/users | jq .Expected: "success": true, items array, and pagination object.
Tip for juniors
If GET fails, fix auth and config before touching column code. If GET works but POST returns empty items, check your database has rows and setInitialBuilder() is not over-filtering.
Add column labels (optional but recommended)
Column label values are translated via:
lang/{locale}/api-table.php → "users.name" => "Full name"After publishing lang files, add:
// lang/en/api-table.php
return [
'users' => [
'name' => 'Name',
'email' => 'Email',
],
];Without this, the raw label key may appear in the UI.
Hand off to frontend
Share with the frontend developer:
| Item | Value |
|---|---|
| Table name | users |
| Structure path | /api-table/control-tables/load-table/users (or full URL) |
Sample load-table JSON | Paste your curl output |
They wire this into useTableStructure — see the frontend docs.
What to learn next
| Goal | Read |
|---|---|
| Understand request flow | Architecture overview, Data flow |
| Add search/filter | Filters |
| Add row buttons | Row actions |
| Add export | Bulk actions |
| Restrict who sees the table | Guards and middleware |
| JSON field reference | Table structure |
| Something broke | Troubleshooting |
Checklist before opening a PR
- Table registered in
api-tables-config.php -
TABLENAMEmatches config key -
load-tablereturns expected columns -
query-tablereturns paginated data - Translation keys added for new column labels
- Tested with authenticated token (not just locally without auth)