Skip to content

ApiExposable

Viames Marino edited this page Feb 23, 2026 · 2 revisions

Pair framework: ApiExposable

Pair\Api\ApiExposable is a trait for ActiveRecord models used by CrudController.

It defines API behavior such as filtering, sorting, searchable fields, includes, pagination limits, and validation rules.

When to use

Use this trait on ActiveRecord models that must be exposed through auto-CRUD endpoints with strict, explicit query/output policies.

Main methods

apiConfig(): array

Override this in your model to define API configuration.

getApiConfig(): array

Returns merged config (apiConfig() + framework defaults).

isFilterable(string $property): bool

isSortable(string $property): bool

isSearchable(string $property): bool

isIncludable(string $relation): bool

Convenience checks against merged configuration.

Full implementation example

<?php

namespace App\Models;

use Pair\Orm\ActiveRecord;
use Pair\Api\ApiExposable;
use App\Api\Resources\FaqResource;

class Faq extends ActiveRecord {

    use ApiExposable;

    public const TABLE_NAME = 'faqs';

    public static function apiConfig(): array
    {
        return [
            'resource' => FaqResource::class,
            'searchable' => ['question', 'answer'],
            'sortable' => ['createdAt', 'position'],
            'filterable' => ['category', 'isPublished'],
            'includes' => ['author'],
            'perPage' => 20,
            'maxPerPage' => 100,
            'defaultSort' => '-createdAt',
            'rules' => [
                'create' => [
                    'question' => 'required|string|min:3',
                    'answer' => 'required|string|min:3',
                ],
                'update' => [
                    'question' => 'string|min:3',
                    'answer' => 'string|min:3',
                ]
            ]
        ];
    }

}

Query behavior enabled by this config

Example request:

GET /api/faqs?search=payment&sort=-createdAt&filter[isPublished]=1&page=2&perPage=20

CrudController + QueryFilter will enforce only declared searchable/sortable/filterable fields.

Frequent usage recipes

Lock down query surface

public static function apiConfig(): array
{
    return [
        'filterable' => ['status', 'customerId'],
        'sortable' => ['id', 'createdAt'],
        'searchable' => ['reference'],
    ];
}

Separate create/update validation strictness

'rules' => [
    'create' => [
        'email' => 'required|email',
        'name' => 'required|string|max:120',
    ],
    'update' => [
        'email' => 'email',
        'name' => 'string|max:120',
    ],
]

Common pitfalls

  • Exposing internal fields in filterable/sortable.
  • Forgetting to cap maxPerPage.
  • Returning unstable output shape by skipping a dedicated resource class.

See also: CrudController, QueryFilter, Resource.

Clone this wiki locally