Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98b8ff236b | ||
|
|
53913c1596 | ||
|
|
f2dcd0059a | ||
|
|
c72b740749 | ||
|
|
2791415401 | ||
|
|
ada996848a | ||
|
|
43a36e4913 | ||
|
|
8b0b57808b | ||
|
|
5cad524908 | ||
|
|
84a094666d |
4
.github/FUNDING.yml
vendored
Normal file
4
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
github: Grazulex
|
||||
buy_me_a_coffee: Grazulex
|
||||
custom: ["https://paypal.me/strauven"]
|
||||
6
.github/workflows/tests.yml
vendored
6
.github/workflows/tests.yml
vendored
@@ -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
|
||||
|
||||
|
||||
85
README.md
85
README.md
@@ -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.
|
||||
|
||||
[](https://php.net)
|
||||
[](https://laravel.com)
|
||||
[](https://laravel.com)
|
||||
[](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
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
1111
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user