laravel-api-tool-kit
Laravel API tool kit
Laravel api tool kit is a set of tools that will help you to build a fast and well-organized API using laravel best practices.
Contents
Installation
Api response
Dynamic Pagination
Filters
Api Generator
Actions
Media Helper
Enum
General tips
composer require essa/api-tool-kit
to publish config
php artisan vendor:publish --provider="EssaAPIToolKitAPIToolKitServiceProvider" --tag="config"
use exception handler to standardize the error response Error Response
in AppExceptionsHandler class extend the APIHandler class
namespace AppExceptions; use EssaAPIToolKitExceptionsHandler as APIHandler; class Handler extends APIHandler { }
use API Response Trait in Controller
AppHttpControllersController.php
:
use EssaAPIToolKitApiApiResponse; class Controller extends BaseController { use ApiResponse; }
check : API response
🔝 Back to contents
it is used to format your response to standard format and status codes
for success responses, it will be
{ "message": "your message", "data": "your date" }
{ "errors": [ { "status": 403, "title": "unauthenticated!", "detail": "Unauthenticated." } ] }
usage:
you can use the trait inside the class you want to return the response form
and use it like this
$this->responseSuccess('car created successfully' , $car);
Available Methods
responseSuccess($message , $data) // returns a 200 HTTP status code responseCreated($message,$data) // returns a 201 HTTP status code responseDeleted() // returns empty response with a 204 HTTP status code responseNotFound($error_details,$error_title) // returns a 404 HTTP status code responseBadRequest($error_details,$error_title) // returns a 400 HTTP status code responseUnAuthorized($error_details,$error_title) // returns a 403 HTTP status code responseConflictError($error_details,$error_title) // returns a 409 HTTP status code responseUnprocessable($error_details,$error_title) // returns a 422 HTTP status code responseUnAuthenticated ($error_details,$error_title) // returns a 401 HTTP status code responseWithCustomError($error_title, $error_details, $status_code) //send custom error
use pagination dynamically
usage
to use dynamic pagination to get all users :
$users = User::dynamicPaginate();
to get all users without pagination :
users?pagination='none'
to get all users paginated 10 users per page:
users?per_page=10
by default pagination is 20 element per page you can change the default value from config/api-tool-kit
usage:
to create a filter class:
php artisan make:filter CarFilters
to set default filters to the Car model , in Car model you will add
protected $default_filters = CarFilters::class;
to use it
Car::useFilters()->get();
if you want to override the default filters
Car::useFilters(SpecialCaseCarFilters::class)->get();
options in Filter class
//to add the attributes to filter by =>> /cars?color=red&model_id=1 protected array $allowedFilters = ['color' , 'model_id']; //to add the attributes to filter by : // desc : ?sorts=created_at // asc : ?sorts=-created_at protected array $allowedSorts= ['created_at']; // allowed relationships to be loaded // ?includes=model protected array $allowedIncludes = ['model']; //column that will be included in search =>> ?search=tesla protected array $columnSearch= ['name','descriptions']; //relation that will be included in search =>> ?search=ahmed protected array $relationSearch = [ 'user' => ['first_name', 'last_name'] ];
to create a custom query you will just create a new function in the class and add your query
example filter by year:
public function year($term) { $this->builder->whereYear('created_At', $term); } //usage : /cars?year=2020
filter by relationship :
public function option($term) { $this->builder->whereHas('options', fn($query) => $query->where('option_id', $term)); } //usage : /cars?option=1
Usage :
php artisan api:generate Car
when you type the command it will ask you whether you want default options :
- (N) it will ask you which files you want to generate .
- (Y) it will generate files for all options that exists in config/api-tool-kit
options :
** by default it will create a model :
-app/Models/Car.php
** controller :
-app/Http/Controllers/API/CarController.php
** resource :
-app/Http/Resources/CarResource.php
** request :
-app/Http/Requests/Car/CreateCarRequest.php
-app/Http/Requests/Car/UpdateCarRequest.php
** filter :
-app/Filters/CarFilters.php
** seeder :
-database/seeders/CarSeeder.php
** factory :
-database/factories/CarFactory.php
** test :
-Tests/Feature/CarTest.php
** migration :
-database/migrations/x_x_x_x_create_cars_table.php
in addition, the routes will be created and added in routes/api.php files
🔝 Back to contents
action is a laravel implementation of command design pattern which create a class where you can add your business logic in
https://en.wikipedia.org/wiki/Command_pattern
usage:
php artisan make:action CreateCar
<?php namespace AppActions; class CreateCar { public function execute($data) { //add business logic to create a car } }
The best practice to use the action class is to use dependency injection
you have many options
1-use laravel application container
app(CreateCar::class)->execute($data);
2-inject it in the class in constructor
private $create_car_action ; public function __construct(CreateCar $create_car_action) { $this->create_car_action=$create_car_action; } public function doSomething() { $this->create_car_action->execute($data); }
3-inject the class in laravel controller function
public function doSomething(CreateCar $create_car_action) { $create_car_action->execute($data); }
it is used to upload and delete files to storage
// to upload file $file_path = MediaHelper::uploadFile($file ,$path); //to delete an file MediaHelper::deleteFile($path); //upload multiple files $files_paths = MediaHelper::uploadMultiple($files ,$path); //upload base64 image $image_path = MediaHelper::uploadBase64Image($encoded_image ,$path);
**Enum
bad practice :
if I have two types of users (admin ,student) instead of hard coding the name of user type every time using it you can simply use the enum class
usage :
php artisan make:enum UserTypes
it will generate classes like this
namespace AppEnums; class UserTypes extends Enum { public const ADMIN = 'admin'; public const STUDENT = 'student'; }
methods:
UserTypes::getAll() //get all types UserTypes::isValid($value) //to check if this value exist in the enum UserTypes::toArray() //to get all enums as key and value
Bad:
public function index() { if (auth()->user()->not_active ) { $this->responseUnAuthorized('you can not preform this action'); } }
good
public function index() { if (auth()->user()->not_active ) { throw new AuthorizationException('you can not preform this action'); } }