yunusbek / adaptive-api
Adaptive API package for Yii2 projects
Installs: 29
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/yunusbek/adaptive-api
Requires
- greenlion/php-sql-parser: ^4.7
- vlucas/phpdotenv: ^5.6
- yiisoft/yii2: ^2.0
This package is auto-updated.
Last update: 2025-10-23 10:04:03 UTC
README
Adaptive API package features
✅ Dynamically generate custom API structures based on client requirements
✅ Allow clients to fetch data with dynamic filtering options
✅ Retrieve only the required tables and columns from the database
✅ Access all database tables through a single API endpoint (one unified URL).
– Clients send the desired table structures in the request body, and the API returns exactly what is requested
Installation
Either run
composer require yunusbek/adaptive-api
or add
"yunusbek/adaptive-api": "^1.0",
to the require section of your composer.json.
Installation
- Create
.envfile in the root of your application:
API_DB_ROLE=api_reader API_DB_USER=api_user_api API_DB_PASSWORD=_@p!_reaDer_ #API_DB_HOST=localhost #API_DB_NAME=your-dbname #API_DB_PORT=5432 UPLOAD_FOLDER_PATH=/uploads/
- Load
.envinsideweb/index.phpand rootyiifile:
#... $dotenv = Dotenv\Dotenv::createUnsafeMutable(dirname(__DIR__.'/../.env')); $dotenv->load(); #...
- Run migration to create the
api_userdatabase user and apply permissions:
php yii migrate --migrationPath=@vendor/yunusbek/adaptive-api/src/migrations
# Add the following code to controllerMap [ #... 'controllerMap' => [ 'api-schema-migration' => 'Yunusbek\AdaptiveApi\commands\Migrations', ], #... ]
The next thing you need to do is updating your database schema by applying the migration of table client_api_schema_permissions:
php yii api-schema-migration
Example to permission schema
table - client_api_schema_permissions
column - schema:jsonb
{
"{user}": {
"username": "",
"email": "",
"phone": "",
"address": ""
},
"{company}": {
"company_name": "",
"email": "",
"phone": "",
"address": ""
}
}
Usage
Example to api request structure
{
"customer": {
"personal_info": {
"person": "{user}.username",
"email": "{user}.email",
"gender": "{user}.gender",
"age": "TO_CHAR(TO_TIMESTAMP({user}.age), 'DD.MM.YYYY')",
"personal_phone": "{user}.phone",
"personal_address": "{user}.address"
},
"company_info": {
"company": "{company}.company_name",
"company_email": "{company}.email",
"company_phone": "{company}.phone",
"company_address": "{company}.address"
},
"position_info": {
"user_department": "{position}.department",
"user_position": "{position}.name",
"product_info": {
"product_name": "{product}.name",
"product_type": "{product}.type",
"product_cost": "{product}.cost"
}
}
}
}
result
{
"customer": {
"personal_info": {
"person": "John Doe",
"email": "johndoe@example.com",
"gender": "male",
"personal_phone": "+9989********",
"personal_address": "Some address data"
},
"company_info": {
"company": "Example LLC",
"company_email": "example@example.com",
"company_phone": "+9989********",
"company_address": "Some address data"
},
"position_info": {
"user_department": "Sales department",
"user_position": "seller",
"product_info": {
"product_name": "Bicycle",
"product_type": "Sport",
"product_cost": "$33.5"
}
}
}
}
$root = [ 'unique_number' => 'user_id', 'select' => [ "user_id", "position_id", "company_id", "product_id" => "product.id", "started_date", "status", ], 'class' => UserRelCompany::class, // or by table name 'table' => 'user_rel_company' 'join' => [ ['JOIN', "products AS product", 'on' => ["user_id" => "user_id"], 'condition' => ['status' => 'ACTIVE']] ], 'where' => [ 'current_company' => true, 'product.type' => ['building', 'food', 'sport'] ], 'filter' => [ 'product_type' => "product.type", ] ]; $relations = [ 'user' => [ 'on' => ["id" => "user_id"], 'class' => Users::class // or users_table_name, 'select' => [ "username", "email", "gender", "phone", "address", ], 'where' => [ 'status' => 'ACTIVE' ] ], 'company' => [ 'on' => ["id" => "company_id"], 'class' => Companies::class // or companies_table_name, 'select' => [ "company_name" => 'name', "email", "phone", "address", ], 'where' => [ 'status' => 'ACTIVE' ] ], 'position' => [ 'on' => ["id" => "position_id"], 'class' => UserStaffPosition::class, 'select' => [ "name", "department", ], 'where' => [ 'status' => 'ACTIVE' ] ], 'product' => [ 'on' => ["id" => "product_id"], 'class' => Products::class // or products_table_name, 'select' => [ "name", "type", "cost", ], 'where' => [ 'status' => 'ACTIVE' ] ], #... other relations tables ]; $response = CteBuilder::root($root) // root table ->relation($relations) // relation tables ->with($with) // if you need with cte ->queryParams($params) // GET query string params (client request) ->template($sendTemplate) // body params (client request structure) // ->setCallback(function (string $text, string $lang) use ($params) { // this is optional if you want to add some callback function // if ($lang === 'en') { $lang = 'ru'; } // return KirillToLatin::widget(['text' => $text, 'lang' => $lang]); // }, '/^\{(uz|ru|en)\}(.*)/') ->getApi(); // finish
📘 /reference API
Method: POST
Description:
This endpoint returns reference data from related tables using dynamic field selection and alias-based filtering.
It supports both pagination (limit) and relation field filters (e.g. <department>code=av).
🧩 Request Parameters
🔹 Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
limit |
integer |
❌ | The number of records to return. Example: 4 |
<department>code |
string |
❌ | Filter applied to the related table department.code. Example: av |
📝 Note:
The<department>prefix indicates that the field belongs to a related (joined) table or alias.
🔹 Request Body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
users |
string |
✅ | Pattern for selecting fields from the users CTE/table. {users}.* means “select all columns.” |
department |
string |
✅ | Pattern for including all fields from the related department table or CTE. <{department}>.* means “include all columns.” |
Example:
{
"users": "{users}.*",
"department": "<{department}>.*"
}
🧾 Example Request
GET /reference?limit=4&<department>code=av