| Package Data | |
|---|---|
| Maintainer Username: | brunocmoreira |
| Maintainer Contact: | bruno@startsoft.com.br (Bruno Cipolla) |
| Package Create Date: | 2026-02-07 |
| Package Last Update: | 2026-02-09 |
| Language: | PHP |
| License: | MIT |
| Last Refreshed: | 2026-02-10 03:00:03 |
| Package Statistics | |
|---|---|
| Total Downloads: | 1 |
| Monthly Downloads: | 1 |
| Daily Downloads: | 1 |
| Total Stars: | 0 |
| Total Watchers: | 0 |
| Total Forks: | 0 |
| Total Open Issues: | 0 |
Automatic REST API generation for Laravel Eloquent models with built-in security, validation, and advanced querying.
composer require lumina/laravel-api
php artisan lumina:publish
Edit config/lumina.php:
return [
'models' => [
'posts' => \App\Models\Post::class,
],
];
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Lumina\LaravelApi\Traits\HasValidation;
class Post extends Model
{
use HasValidation;
protected $fillable = ['title', 'content', 'user_id'];
// Validation rules
protected $validationRules = [
'title' => 'string|max:255',
'content' => 'string',
'user_id' => 'exists:users,id',
];
protected $validationRulesStore = [
'title' => 'required',
'content' => 'required',
'user_id' => 'required',
];
protected $validationRulesUpdate = [
'title' => 'sometimes',
'content' => 'sometimes',
];
// Query Builder configuration
public static $allowedFilters = ['title', 'user_id'];
public static $allowedSorts = ['created_at', 'title'];
public static $defaultSort = '-created_at';
public static $allowedIncludes = ['user'];
}
php artisan make:policy PostPolicy --model=Post
<?php
namespace App\Policies;
use App\Models\User;
use App\Models\Post;
use Lumina\LaravelApi\Policies\ResourcePolicy;
class PostPolicy extends ResourcePolicy
{
public function viewAny(?User $user) { return true; }
public function view(?User $user, Post $post) { return true; }
public function create(?User $user) { return $user !== null; }
public function update(?User $user, Post $post) {
return $user && $user->id === $post->user_id;
}
public function delete(?User $user, Post $post) {
return $user && $user->id === $post->user_id;
}
}
Your API endpoints are now available:
GET /api/posts # List posts
POST /api/posts # Create post
GET /api/posts/{id} # Show post
PUT /api/posts/{id} # Update post
DELETE /api/posts/{id} # Delete post
| Feature | Documentation | |---------|---------------| | ๐ Authentication | Authentication Guide - Login, logout, password recovery | | ๐ก๏ธ Authorization | Authorization Guide - Permissions and policies | | โ Validation | Validation Guide - Role-based validation | | ๐ Query Builder | Query Builder Guide - Filtering, sorting, includes | | ๐ Pagination | Pagination Guide - Header-based pagination | | ๐๏ธ Soft Deletes | Soft Deletes Guide - Trash and restore | | ๐ Audit Trail | Audit Trail Guide - Change tracking | | ๐ Nested Operations | Nested Operations Guide - Multi-model transactions | | ๐ข Multi-Tenancy | Multi-Tenancy Guide - Organization isolation | | ๐ง Invitations | Invitations Guide - User invitation system |
Register a model and get full REST API endpoints with zero controller code:
// config/lumina.php
'models' => [
'posts' => \App\Models\Post::class,
],
All routes are explicitly registered and visible via php artisan route:list.
Use Laravel policies with convention-based permissions stored in JSON:
// Permission format: {slug}.{action}
'permissions' => [
'posts.index', // Can list posts
'posts.store', // Can create posts
'posts.*', // All post actions
'*', // All permissions
]
Built on Spatie Query Builder with include authorization:
# Complex query in single request
GET /api/posts?filter[status]=published&include=user,comments&sort=-created_at&per_page=20
# Include authorization - returns 403 if user cannot view comments
GET /api/posts?include=comments
Different validation rules per user role:
protected $validationRulesStore = [
'admin' => [
'title' => 'required',
'content' => 'required',
'is_published' => 'nullable', // Admins can publish
],
'contributor' => [
'title' => 'required',
'content' => 'required',
// Contributors cannot set is_published
],
];
Execute multiple operations atomically:
POST /api/nested
{
"operations": [
{
"model": "blogs",
"action": "create",
"data": {"title": "My Blog"}
},
{
"model": "posts",
"action": "create",
"data": {"blog_id": 1, "title": "First Post"}
}
]
}
Automatic change tracking:
use Lumina\LaravelApi\Traits\HasAuditTrail;
class Post extends Model
{
use HasAuditTrail;
}
// Automatically logs:
// - Created, updated, deleted, restored events
// - Old and new values
// - User, organization, IP, user agent
class Post extends Model
{
use HasValidation;
// Query Builder
public static $allowedFilters = ['title', 'status', 'user_id'];
public static $allowedSorts = ['created_at', 'updated_at', 'title'];
public static $defaultSort = '-created_at';
public static $allowedFields = ['id', 'title', 'content'];
public static $allowedIncludes = ['user', 'comments'];
public static $allowedSearch = ['title', 'content'];
// Pagination
public static bool $paginationEnabled = true;
protected $perPage = 25;
// Middleware
public static array $middleware = ['throttle:60,1'];
public static array $middlewareActions = [
'store' => ['verified'],
'update' => ['verified'],
];
// Exclude actions
public static array $exceptActions = ['destroy'];
}
Edit config/lumina.php:
return [
// Model registration
'models' => [
'posts' => \App\Models\Post::class,
'comments' => \App\Models\Comment::class,
],
// Public endpoints (no auth required)
'public' => ['posts'],
// Nested operations
'nested_operations' => [
'enabled' => true,
'max_operations' => 10,
'allowed_models' => ['blogs', 'posts', 'comments'],
],
// Authentication
'auth' => [
'login_route' => 'api/auth/login',
'logout_route' => 'api/auth/logout',
'password_recovery_enabled' => true,
'registration_enabled' => true,
],
];
# Single filter
GET /api/posts?filter[is_published]=true
# Multiple filters (AND)
GET /api/posts?filter[is_published]=true&filter[user_id]=1
# Multiple values (OR)
GET /api/posts?filter[status]=draft,published
# Ascending
GET /api/posts?sort=title
# Descending
GET /api/posts?sort=-created_at
# Multiple sorts
GET /api/posts?sort=-is_published,created_at
# Single relationship
GET /api/posts?include=user
# Multiple relationships
GET /api/posts?include=user,comments,tags
# Nested relationships
GET /api/posts?include=comments.user
# On-demand pagination
GET /api/posts?per_page=20&page=2
# With other query features
GET /api/posts?filter[status]=published&sort=-created_at&include=user&per_page=20
Pagination metadata in headers:
X-Current-Page: 2
X-Last-Page: 10
X-Per-Page: 20
X-Total: 195
# Select specific fields
GET /api/posts?fields[posts]=id,title,created_at
# With relationships
GET /api/posts?include=user&fields[posts]=id,title&fields[users]=id,name
# Full-text search
GET /api/posts?search=laravel
# Search with filters
GET /api/posts?search=tutorial&filter[is_published]=true
1. Request โ Middleware (auth, organization context)
โ
2. GlobalController resolves model
โ
3. Policy authorization check
โ
4. Query Builder applies filters/sorts/includes
โ
5. Include authorization (per relationship)
โ
6. Model validation (create/update)
โ
7. Database operation
โ
8. Audit logging (if enabled)
โ
9. Response with data + pagination headers
All endpoints are protected by Laravel policies:
// Automatically checks:
// - viewAny() for index
// - view() for show
// - create() for store
// - update() for update
// - delete() for delete/destroy
All create/update requests validated:
// Prevents invalid data from reaching database
// Role-based rules for different user types
// Custom error messages
Add automatic filtering:
protected static function booted()
{
static::addGlobalScope(new OrganizationScope);
}
Per-model rate limiting:
public static array $middleware = ['throttle:60,1'];
use Tests\TestCase;
class PostApiTest extends TestCase
{
public function test_can_list_posts()
{
Post::factory()->count(5)->create();
$response = $this->getJson('/api/posts');
$response->assertOk()
->assertJsonCount(5);
}
public function test_can_filter_posts()
{
Post::factory()->create(['is_published' => true]);
Post::factory()->create(['is_published' => false]);
$response = $this->getJson('/api/posts?filter[is_published]=true');
$response->assertOk()
->assertJsonCount(1);
}
public function test_cannot_create_post_without_auth()
{
$response = $this->postJson('/api/posts', [
'title' => 'Test',
'content' => 'Content',
]);
$response->assertStatus(401);
}
public function test_can_include_relationships()
{
$post = Post::factory()->create();
$response = $this->getJson('/api/posts?include=user');
$response->assertOk()
->assertJsonStructure([
'*' => ['id', 'title', 'user' => ['id', 'name']]
]);
}
}
$allowedIncludes for explicit relationshipsAdd caching to expensive queries:
public function index(Request $request)
{
$cacheKey = 'posts_' . md5($request->fullUrl());
return Cache::remember($cacheKey, 60, function () use ($request) {
return Post::query()
->allowedFilters(['title', 'status'])
->paginate(20);
});
}
Contributions are welcome! Please feel free to submit a Pull Request.
# Clone repository
git clone https://github.com/lumina/laravel-api.git
# Install dependencies
composer install
# Run tests
php artisan test
This package is open-sourced software licensed under the MIT license.
Made with โค๏ธ by Startsoft