phpsoftbox / api
API description, error catalog and request version negotiation for PhpSoftBox
Requires
- php: ^8.5
- psr/http-message: ^2.0
- psr/http-server-handler: ^1.0
- psr/http-server-middleware: ^1.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.93
- phpsoftbox/application: dev-master
- phpsoftbox/cli-app: dev-master
- phpsoftbox/cs-fixer: ^1.1.0
- phpsoftbox/http-message: dev-master
- phpunit/phpunit: ^11.2
Suggests
- phpsoftbox/application: Provides CodedHttpException and ExceptionMapper integration for API errors.
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-08-31 18:14:10 UTC
README
Компонент описывает HTTP API, его публичные ошибки и правила выбора опубликованной версии запроса. Он не извлекает версию из URL и не зависит от структуры routes проекта.
Версии
Проект объявляет опубликованные версии enum-ом:
enum CatalogApiVersionEnum: string implements ApiVersionEnumInterface { case VERSION_1_0_0 = '1.0.0'; case VERSION_1_1_0 = '1.1.0'; public function version(): string { return $this->value; } }
Policy содержит точный список и default:
$policy = new EnumApiVersionPolicy( supportedVersions: CatalogApiVersionEnum::cases(), defaultVersion: CatalogApiVersionEnum::VERSION_1_1_0, );
Отсутствующий или пустой header выбирает default. Синтаксически корректная, но неопубликованная версия отклоняется: промежуточный диапазон не поддерживается.
$middleware = new ApiVersionMiddleware( resolver: new HeaderApiVersionResolver('X-CATALOG-API-VERSION'), factory: new DefaultApiRequestVersionFactory($policy), headers: new ApiVersionResponseHeaders( selected: 'X-CATALOG-API-VERSION', minimum: 'X-CATALOG-API-VERSION-MIN', latest: 'X-CATALOG-API-VERSION-LATEST', ), );
Middleware сохраняет ApiRequestVersionInterface в request attributes и
добавляет selected/minimum/latest headers и Vary в response.
Ошибки
ApiErrorCatalog объединяет общие и специфичные определения и отклоняет
конфликтующие codes:
$description = ApiDescription::create('catalog') ->withCommonErrors(CommonApiErrorEnum::cases()) ->withErrors(CatalogApiErrorEnum::cases()) ->withVersionPolicy($policy) ->build();
Endpoint может ссылаться только на зарегистрированные определения через
#[ApiErrors(...)]. Перед генерацией документации ссылки следует проверить через
ApiErrorCatalog::requireAll().
Для JSON runtime responses phpsoftbox/application предоставляет
CodedHttpException. Предметные исключения преобразуются в него через
ExceptionMapperRegistry; публичные status, code, title и message берутся из
ApiErrorDefinition.
Если phpsoftbox/application установлен, готовый
ApiVersionExceptionMapper преобразует ошибки negotiation в
CodedHttpException, добавляя minimum/latest headers и Vary. Application
указан как optional integration dependency: core versioning остаётся PSR-only.
Подключение в проекте
- Объявите enum опубликованных версий и policy.
- Соберите
ApiDescription, зарегистрировав common и project-specific errors. - Добавьте
ApiVersionMiddlewareтолько на versioned route group. - Зарегистрируйте
ApiVersionExceptionMapperв applicationExceptionMapperRegistry. - Передавайте выбранную версию в Action как
ApiRequestVersionInterfaceлибо проектный наследникAbstractApiRequestVersionс именованными feature gates.
Major в URL не входит в этот контракт. /v1, namespace контроллеров и набор
маршрутов остаются проектным routing-соглашением; опубликованную полную версию
определяет только policy подключённого API.
Auth audience
Если приложение выпускает отдельные credentials для нескольких API, стабильный
ApiDescription::id следует использовать как credential audience. Например,
credential с audience catalog принимается route group API catalog, но не API
warehouse.
API version и major в URL в audience не входят. Компонент Api только задаёт
идентификатор; выдача, хранение и проверка credentials остаются ответственностью
phpsoftbox/auth и проектного middleware.
Внешнему проекту после обновления также нужно учесть framework-изменения:
- JSON-ошибки Application получили обязательный
code; - Auth credential storage переименован и использует
subjectId/purpose/audience; X-RateLimit-Resetстал абсолютным Unix timestamp;- production rate limit следует переключить с
SimpleCacheRateLimiterна атомарный backend.