Additionally/Extensions/A set of traits for creating an API

Set of traits for creating API

To implement API in the HLEB2 framework, a set of traits is provided to simplify validation and data processing in controllers (where these traits are applied).

The use of traits in PHP is a matter of various opinions, which is why this module is provided as a separate library, which you may choose to use; there is quite a number of validators available for development in PHP, and this is just a simple working alternative.

Installation of the library github.com/phphleb/api-multitool using Composer:

$composer require phphleb/api-multitool

or download and unpack the library archive into the folder /vendor/phphleb/api-multitool.


#Connecting the BaseApiTrait (set of traits)

First, you need to create a parent class BaseApiActions (or another name) for controllers with API:

<?php
// File /app/Controllers/Api/BaseApiActions.php

namespace App\Controllers\Api;

use 
Hleb\Base\Controller;
use 
Phphleb\ApiMultitool\BaseApiTrait;

class 
BaseApiActions extends Controller
{
    
// Adding a set of traits for the API.
    
use BaseApiTrait;

    function 
__construct(array $config = [])
    {
        
parent::__construct($config);

        
// Passing the debug mode value to the API constructor.
        
$this->setApiBoxDebug($this->container->settings()->isDebug());
    }
}

All auxiliary traits are collected in BaseApiTrait as a set. Therefore, it is enough to connect it to the controller and get the full implementation. If a different set of these traits is required, then either use them as a group or combine them into your own set.

After this, in all controllers inherited from this class, methods from each trait in the set will appear:


#ApiHandlerTrait

The trait ApiHandlerTrait contains several methods that may be useful for processing returned API data. This does not mean that its methods 'present' and 'error' form the final response, they return named arrays, which can be used in your own more complex standard. An example in the controller method:

<?php
// Файл /app/Controllers/Api/UserController.php

namespace App\Controllers\Api;
use 
App\Models\UserModel;
class 
UserController extends BaseApiActions
{
    public function 
actionGetOne(): array
    {
        
$id $this->container->request()->get('id')->asInt();
        if (!
$id) {
            return 
$this->error('Invalid request data: id'400);
        }
        
$data UserModel::getOne($id);
        return 
array_merge(
            
$this->present($data ?: []),
            [
'error_cells' => $this->getErrorCells()]
        );
    }
}

In the HLEB framework, when returning an array from a controller, it is automatically converted into JSON. When displaying the formatted array, a value 'error_cells' is added with a list of fields where validation errors occurred (if any).


#ApiMethodWrapperTrait

Intercepts system errors and provides output to the 'error' method of the previous trait ApiHandlersTrait or another designated for this purpose (if the mentioned trait is not used). If a controller method is called, for proper error handling, you need to add the prefix 'action' in the controller, and in the route, leave it without the prefix. For example, for the previous controller example, the routing would be approximately like this:

Route::get('/api/users/{id}')->controller(UserController::class, 'getOne');

Here it should be noted that originally the call goes to the controller method 'getOne', and in the controller itself, the method is 'actionGetOne'.


#ApiPageManagerTrait

Implements the often necessary function of pagination for displayed data. Adds a method 'getPageInterval', which transforms pagination data into a more convenient format. This calculates the initial value of the selection, which is convenient for working with the database.


#ApiRequestDataManagerTrait

Adds a method 'check' that allows checking data in one array against conditions from another. Using this trait provides the ability to verify any incoming data that has been transformed into an array, whether they are POST request parameters or JSON Body. There is a list of possible conditions by which you can verify the data, composed by the developer. For example (Request::input() for the HLEB2 framework returns a JSON Body array):

use Hleb\Static\Request;

$data Request::input();
// $result - a boolean value indicating whether the checks were successful or not.
$result $this->check($data,
    [
        
'id' => 'required|type:int|min:1'// Required field, type integer, minimum value 1.
        
'email' => 'required|type:string'// Required field, type string.
        
'name' => 'type:string,null'// Optional field, but will check for type string or NULL if found.
        
'password' => 'required|type:string|minlength:6' // Required field, type string, minimum number of characters 6.
    
]);
$errorCells $this->getErrorCells(); // An array with a list of fields that did not pass the check.
$errorMessage $this->getErrorMessage(); // An array with messages about validation errors that occurred.

required - a required field, always located at the beginning.

List of possible types ('type' - must be in the first position or directly after required):
string - checks for the presence of a string value, constraints can be minlength and maxlength.
float - checks for the float(double) type, constraints can be max and min.
int - checks for the int(integer) type, constraints can be max and min.
regex - checks against a regular expression, for example 'regex:[0-9]+'.
fullregex - checks against a full regular expression, similar to 'fullregex:/^[0-9]+$/i', must be enclosed with slashes and can contain the characters : and |, unlike the simpler regex.
bool - checks for a boolean value, only true or false.
null - checks for null as a valid value.
void - checks for an empty string as a valid value.

Type for enumerations:
enum - searches among possible values, for example 'enum:1,2,3,4,south,east,north,west'.
The check for equality is not strict, so both 4 and '4' are correct; for exact matching, it is better to accompany it with a type check.

You can add two or more types, and they will be checked against all common conditions inclusively, for example, 'type:string,null,void|minlen:5' - this means that the string should be checked, at least 5 characters long, or empty, or null value. In all other cases, it returns false as a result of a failed validation check.

You can also check an array of fields with a list of standard array fields (they will be checked according to a unified template):

$result $this->check($data,
    [
        
// Optional field, array with enumeration (two fields are checked in each).
        
'users' => ['id' => 'required|type:int''name' => 'required|type:string'],
        
// Required field, array with enumeration (three fields are checked in each).
        
'images' => ['required', ['id' => 'required|type:int''width' => 'required|type:int''height' => 'required|type:int']]
    ]);

To check values of nested arrays in the check array, the name is specified in square brackets.

$result $this->check(
    [
        [
'name1' => ['name2' => ['name3' => 'text']]],// Data.
        
['[name1][name2][name3]' => 'required|type:string'// Array with conditions.
    
]);

The above condition will return a successful check considering the nesting.


#Testing

The API traits were tested using github.com/phphleb/api-tests

Page translated: chatgpt 4-o
Back to top