10 Commits
v2.2.0 ... main

Author SHA1 Message Date
Jean-Marc Strauven
98b8ff236b Merge pull request #23 from Grazulex/feat/laravel-13-upgrade
feat!: upgrade to Laravel 13 compatibility
2026-03-30 18:03:04 +02:00
Jean-Marc Strauven
53913c1596 fix(ci): set platform PHP to 8.3 for CI compatibility
The platform PHP was set to 8.4.5 which caused Symfony to resolve
to v8.0 requiring PHP 8.4+, breaking the PHP 8.3 CI job.
2026-03-30 18:02:08 +02:00
Jean-Marc Strauven
f2dcd0059a feat!: upgrade to Laravel 13 compatibility
- Update laravel/framework to ^13.0, tinker to ^3.0, query-builder to ^7.0
- Migrate User model to #[Fillable] and #[Hidden] attributes (Laravel 13 pattern)
- Add LARAVEL_130 ruleset to Rector configuration
- Add PHP 8.4 to CI test matrix
- Update README badges and description for Laravel 13

BREAKING CHANGE: requires Laravel 13.x, drops Laravel 12 support
2026-03-30 17:59:00 +02:00
Jean-Marc Strauven
c72b740749 Merge pull request #21 from Grazulex/docs/suggest-optional-packages
docs: add idempotency and throttle-smart as suggested packages
2026-02-05 05:32:52 +01:00
Jean-Marc Strauven
2791415401 docs: add laravel-api-idempotency and laravel-api-throttle-smart as suggested packages
- Add both packages to composer.json suggest section
- Document usage, installation and attention points in README
- Add to Features list and Credits section
2026-02-05 05:32:14 +01:00
Jean-Marc Strauven
ada996848a Merge pull request #20 from Grazulex/chore/update-dependencies
chore(deps): update Composer dependencies
2026-02-02 09:49:43 +01:00
Jean-Marc Strauven
43a36e4913 chore(deps): update Composer dependencies
Update all dependencies to their latest PHP 8.3 compatible versions:
- laravel/framework v12.46.0 → v12.49.0
- laravel/sanctum v4.2.2 → v4.3.0
- grazulex/laravel-apiroute v2.0.3 → v2.0.5
- spatie/laravel-data 4.18.0 → 4.19.1
- spatie/laravel-query-builder 6.3.6 → 6.4.1
- phpstan/phpstan 2.1.35 → 2.1.38
- pestphp/pest v4.3.1 → v4.3.2
- rector/rector 2.3.2 → 2.3.5

Added platform PHP 8.3 constraint to prevent Symfony 8.x packages
from being installed (requires PHP 8.4).
2026-02-02 09:48:37 +01:00
Jean-Marc Strauven
8b0b57808b Merge pull request #19 from Grazulex/Grazulex-patch-1
Update funding information in FUNDING.yml
2026-02-02 05:22:31 +01:00
Jean-Marc Strauven
5cad524908 Update funding information in FUNDING.yml 2026-02-02 05:22:17 +01:00
Jean-Marc Strauven
84a094666d Merge pull request #18 from Grazulex/release/v2.2.0
chore(release): 2.2.0
2026-01-29 04:21:56 +01:00
7 changed files with 681 additions and 573 deletions

4
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,4 @@
# These are supported funding model platforms
github: Grazulex
buy_me_a_coffee: Grazulex
custom: ["https://paypal.me/strauven"]

View File

@@ -12,6 +12,10 @@ jobs:
ci:
runs-on: ubuntu-latest
strategy:
matrix:
php-version: ['8.3', '8.4']
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -19,7 +23,7 @@ jobs:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.3
php-version: ${{ matrix.php-version }}
tools: composer:v2
coverage: xdebug

View File

@@ -1,9 +1,9 @@
# Laravel API Kit
A production-ready, API-only Laravel 12 starter kit following the 2024-2025 REST API ecosystem best practices. No frontend dependencies - purely headless API for mobile apps, SPAs, or microservices.
A production-ready, API-only Laravel 13 starter kit following the 2025-2026 REST API ecosystem best practices. No frontend dependencies - purely headless API for mobile apps, SPAs, or microservices.
[![PHP Version](https://img.shields.io/badge/PHP-8.3%2B-blue)](https://php.net)
[![Laravel Version](https://img.shields.io/badge/Laravel-12.x-red)](https://laravel.com)
[![Laravel Version](https://img.shields.io/badge/Laravel-13.x-red)](https://laravel.com)
[![License](https://img.shields.io/badge/License-MIT-green)](LICENSE)
## Features
@@ -21,6 +21,8 @@ A production-ready, API-only Laravel 12 starter kit following the 2024-2025 REST
- **Rate Limiting** - Configurable per-route rate limiters
- **Reusable Middleware** - ForceJsonResponse, LogApiRequests, EnsureEmailVerified
- **Standardized Responses** - Consistent JSON response format
- **Optional: API Idempotency** - RFC-compliant idempotency via [grazulex/laravel-api-idempotency](https://github.com/Grazulex/laravel-api-idempotency)
- **Optional: Smart Rate Limiting** - Plan-aware throttling with quotas via [grazulex/laravel-api-throttle-smart](https://github.com/Grazulex/laravel-api-throttle-smart)
## Requirements
@@ -465,6 +467,83 @@ X-RateLimit-Remaining: 59
Retry-After: 60 # When limit exceeded
```
## Optional Packages
The following packages are **suggested** (not required) and can be installed individually to extend the kit's capabilities. They are fully opt-in and will not affect existing behavior.
### API Idempotency
[grazulex/laravel-api-idempotency](https://github.com/Grazulex/laravel-api-idempotency) provides RFC-compliant idempotency for your API endpoints. It prevents duplicate operations when clients retry requests (critical for payments, order creation, etc.).
**Install:**
```bash
composer require grazulex/laravel-api-idempotency
```
**Publish config (optional):**
```bash
php artisan vendor:publish --tag="api-idempotency-config"
```
**Usage — apply the middleware to mutation routes:**
```php
// routes/api/v1.php
Route::middleware(['auth:sanctum', 'throttle:authenticated'])->group(function () {
Route::post('orders', [OrderController::class, 'store'])
->middleware('idempotent');
Route::post('payments', [PaymentController::class, 'store'])
->middleware('idempotent:required'); // Require Idempotency-Key header
});
```
**Client-side — include the `Idempotency-Key` header:**
```bash
curl -X POST http://localhost:8080/api/v1/orders \
-H "Authorization: Bearer 1|abc123..." \
-H "Idempotency-Key: order_unique_key_123" \
-H "Content-Type: application/json" \
-d '{"product_id": 1, "quantity": 2}'
```
> **Attention:**
> - Only apply the `idempotent` middleware to mutation routes (POST, PUT, PATCH). GET requests are naturally idempotent.
> - The default storage driver is `cache`. For production with multiple servers, use the `redis` or `database` driver.
> - Keys are scoped per user by default. Two different users can use the same key without conflict.
---
### Smart Rate Limiting
[grazulex/laravel-api-throttle-smart](https://github.com/Grazulex/laravel-api-throttle-smart) provides plan-aware rate limiting with quotas, multiple algorithms (fixed window, sliding window, token bucket), and multi-tenant support. Ideal for SaaS APIs with subscription tiers.
**Install:**
```bash
composer require grazulex/laravel-api-throttle-smart
```
**Publish config:**
```bash
php artisan vendor:publish --tag="throttle-smart-config"
```
**Usage — apply to routes where plan-based limiting is needed:**
```php
// routes/api/v1.php
Route::middleware(['auth:sanctum', 'throttle.smart'])->group(function () {
Route::apiResource('posts', PostController::class);
});
```
> **Attention:**
> - This package **coexists** with Laravel's built-in `throttle:` middleware. You do not need to remove the existing rate limiters.
> - If you want to **replace** the native throttle on specific routes, swap `throttle:authenticated` with `throttle.smart` on those routes only.
> - Do **not** apply both `throttle:authenticated` and `throttle.smart` on the same route group — choose one per group to avoid double rate limiting.
> - The default driver is `cache`. For production, `redis` is recommended for performance and distributed consistency.
> - Configure your subscription plans in `config/throttle-smart.php` to match your business model (Free, Pro, Enterprise, etc.).
---
## Middleware
The kit includes three production-ready middleware patterns that you can apply to your routes as needed.
@@ -814,6 +893,8 @@ This project is open-sourced software licensed under the [MIT license](LICENSE).
- [spatie/laravel-query-builder](https://github.com/spatie/laravel-query-builder) - Query Building
- [spatie/laravel-data](https://github.com/spatie/laravel-data) - Data Transfer Objects
- [dedoc/scramble](https://github.com/dedoc/scramble) - API Documentation
- [grazulex/laravel-api-idempotency](https://github.com/Grazulex/laravel-api-idempotency) - API Idempotency (optional)
- [grazulex/laravel-api-throttle-smart](https://github.com/Grazulex/laravel-api-throttle-smart) - Smart Rate Limiting (optional)
- [Pest PHP](https://pestphp.com) - Testing Framework
## Support

View File

@@ -6,6 +6,8 @@ namespace App\Models;
use Database\Factories\UserFactory;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Hidden;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
@@ -21,6 +23,15 @@ use Laravel\Sanctum\HasApiTokens;
* @property Carbon|null $created_at
* @property Carbon|null $updated_at
*/
#[Fillable([
'name',
'email',
'password',
])]
#[Hidden([
'password',
'remember_token',
])]
final class User extends Authenticatable implements MustVerifyEmail
{
use HasApiTokens;
@@ -30,27 +41,6 @@ final class User extends Authenticatable implements MustVerifyEmail
use Notifiable;
/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* @var list<string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* Get the attributes that should be cast.
*

View File

@@ -7,13 +7,13 @@
"license": "MIT",
"require": {
"php": "^8.3",
"dedoc/scramble": "^0.12",
"dedoc/scramble": "^0.12|^0.13",
"grazulex/laravel-apiroute": "^2.0",
"laravel/framework": "^12.0",
"laravel/framework": "^13.0",
"laravel/sanctum": "^4.0",
"laravel/tinker": "^2.10.1",
"laravel/tinker": "^3.0",
"spatie/laravel-data": "^4.0",
"spatie/laravel-query-builder": "^6.0"
"spatie/laravel-query-builder": "^7.0"
},
"require-dev": {
"driftingly/rector-laravel": "^2.0",
@@ -27,6 +27,10 @@
"pestphp/pest-plugin-laravel": "^4.0",
"rector/rector": "^2.2"
},
"suggest": {
"grazulex/laravel-api-idempotency": "RFC-compliant API idempotency with response caching and multiple storage drivers",
"grazulex/laravel-api-throttle-smart": "Plan-aware smart rate limiting with quotas, multiple algorithms and multi-tenant support"
},
"autoload": {
"psr-4": {
"App\\": "app/",
@@ -88,6 +92,9 @@
"allow-plugins": {
"pestphp/pest-plugin": true,
"php-http/discovery": true
},
"platform": {
"php": "8.3.0"
}
},
"minimum-stability": "stable",

1111
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -21,6 +21,7 @@ return RectorConfig::configure()
LaravelSetList::LARAVEL_FACTORIES,
LaravelSetList::LARAVEL_IF_HELPERS,
LaravelSetList::LARAVEL_LEGACY_FACTORIES_TO_CLASSES,
LaravelSetList::LARAVEL_130,
])
->withImportNames(
removeUnusedImports: true,