Installation Add the package via Composer:
composer require dbstudios/php-rest
Publish the default configuration (if needed):
php artisan vendor:publish --provider="Dbstudios\Rest\RestServiceProvider" --tag="config"
Basic REST Controller
Extend Dbstudios\Rest\RestController to leverage built-in CRUD methods:
use Dbstudios\Rest\RestController;
class UserController extends RestController
{
protected $model = \App\Models\User::class; // Auto-injects Eloquent model
}
Define routes in routes/api.php:
Route::apiResource('users', \App\Http\Controllers\UserController::class);
First API Call
Test with GET /api/users (returns paginated list) or POST /api/users (create record).
RestController (base controller with CRUD methods)RestServiceProvider (bootstraps middleware, formatters)config/rest.php (API versioning, default responses, pagination)ApiVersionMiddleware (handles versioning)ApiResponseFormatter (standardizes JSON responses)Override a single method (e.g., show()) while keeping default behavior for others:
public function show($id)
{
$user = $this->model->findOrFail($id);
return $this->respondWithItem($user, 'User retrieved');
}
$model in your controller to auto-generate CRUD endpoints.getModel() to modify the query builder:
protected function getModel()
{
return $this->model->with('roles')->where('active', 1);
}
Route::apiResource('v1/users', ...) and rely on ApiVersionMiddleware.Accept: application/vnd.api.v1+json in requests.api_versions in config/rest.php.return $this->respondWithSuccess('Data fetched', ['key' => 'value']);
Output:
{
"success": true,
"message": "Data fetched",
"data": { "key": "value" }
}
return $this->respondWithError('Not found', 404);
paginate() (configurable in config/rest.php).protected $paginate = 20; // Override per controller
FormRequest. Extend Dbstudios\Rest\Requests\RestRequest:
use Dbstudios\Rest\Requests\RestRequest;
class StoreUserRequest extends RestRequest
{
public function rules()
{
return ['email' => 'required|email'];
}
}
public function store(StoreUserRequest $request)
{
// Validated automatically
}
RestServiceProvider:
protected $middleware = [
\App\Http\Middleware\CheckApiKey::class,
];
middleware() in controllers:
public function __construct()
{
$this->middleware('auth:api')->except(['index', 'show']);
}
Model Not Found
$model or using a non-Eloquent class.$model points to a valid Eloquent model.Versioning Conflicts
ApiVersionMiddleware is registered in RestServiceProvider and routes use apiResource.Pagination Overrides
$paginate not being respected.config/rest.php or controller overrides.Validation Errors
RestRequest and are properly annotated in controller methods.CORS Headers
fruitcake/laravel-cors or manually add headers in middleware.Log Responses
Temporarily modify ApiResponseFormatter to log payloads:
Log::debug('Response:', $responseData);
Check Middleware Order
Use php artisan route:list to verify middleware is applied correctly.
Validate Config Dump the merged config:
dd(config('rest'));
Override Defaults
Extend core classes (e.g., RestController) to debug behavior:
class CustomRestController extends RestController
{
public function __construct()
{
parent::__construct();
Log::info('Controller initialized');
}
}
Custom Formatters
Extend Dbstudios\Rest\Formatters\ApiResponseFormatter to modify response structure:
class CustomFormatter extends ApiResponseFormatter
{
protected function customizeResponse(array $data, string $message, int $status)
{
$data['custom_field'] = 'value';
return parent::customizeResponse($data, $message, $status);
}
}
Register in RestServiceProvider:
$this->app->bind(
ApiResponseFormatter::class,
CustomFormatter::class
);
Add Custom Methods
Extend RestController to add domain-specific actions:
public function softDelete($id)
{
$item = $this->model->findOrFail($id);
$item->delete();
return $this->respondWithSuccess('Item soft-deleted');
}
Hooks for Pre/Post Actions
Override beforeAction() or afterAction() in controllers:
protected function beforeAction()
{
Log::info('Before action hook');
}
Event Listeners
Listen to rest.before or rest.after events in EventServiceProvider:
protected $listen = [
'rest.before' => [
\App\Listeners\LogRequest::class,
],
];
Default API Version
Set in config/rest.php:
'default_version' => 'v1',
Override per route with Route::apiResource('v2/users', ...).
Response Wrapping Disable with:
'wrap_responses' => false,
Pagination Links Disable in config:
'paginate_links' => false,
Eager Loading
Use with() in getModel() to avoid N+1 queries:
protected function getModel()
{
return $this->model->with('posts');
}
Caching Responses
Cache frequent queries in beforeAction():
$data = Cache::remember("users_{$id}", now()->addHours(1), function() use ($id) {
return $this->model->find($id);
});
Batch Processing Use chunking for large datasets:
$this->model->chunk(100, function ($items) {
// Process batch
});
How can I help you explore Laravel packages today?