wakeapp / api-platform-bundle
Extends Symfony HttpFoundation and provides encapsulated area for work with REST API
Installs: 22 705
Dependents: 0
Suggesters: 0
Security: 0
Stars: 8
Watchers: 7
Forks: 0
Open Issues: 0
Type:symfony-bundle
Requires
- php: ~7.1||~8.0
- ext-json: *
- psr/log: ^1.0
- symfony/config: ~3.4||~4.0||~5.0
- symfony/dependency-injection: ~3.4||~4.0||~5.0
- symfony/http-foundation: ~3.4||~4.0||~5.0
- symfony/http-kernel: ~3.4||~4.0||~5.0
- symfony/translation-contracts: ^1.1||^2.2
- wakeapp/dto-resolver: ^1.1
- wakeapp/swagger-resolver-bundle: ^0.4.10
Suggests
- symfony/monolog-bundle: Provides possibility for log information into separate channel
- symfony/translation: Provides possibility for translate response codes
Conflicts
- nelmio/api-doc-bundle: <3.0
This package is auto-updated.
Last update: 2021-11-17 15:41:10 UTC
README
Введение
Бандл расширяет компонет Symfony http-foundation позволя выделить работу с API в отдельную инкапсулированную зону.
Предоставляется работа с контентом запроса в формате JSON
посредством ParameterBag
.
Архитектура бандла не допускает фатального падения в зоне API и всегда возвращает валидный ответ
с соответствующем кодом ошибки. Полный список кодов ошибок доступен в виде констант в классе
ApiException.
Для описания спецификации API обязательно использование Swagger 2 в одном из форматов:
- NelmioApiDocBundle.
- swagger-php.
- Использование файла конфигурации в формате
json
илиyaml
(yml
).
Установка
Шаг 1: Загрузка бандла
Откройте консоль и, перейдя в директорию проекта, выполните следующую команду для загрузки наиболее подходящей стабильной версии этого бандла:
composer require wakeapp/api-platform-bundle
Эта команда подразумевает что Composer установлен и доступен глобально.
Шаг 2: Подключение бандла
После включите бандл добавив его в список зарегистрированных бандлов в app/AppKernel.php
файл вашего проекта:
<?php declare(strict_types=1); // app/AppKernel.php class AppKernel extends Kernel { // ... public function registerBundles() { $bundles = [ // ... new Linkin\Bundle\SwaggerResolverBundle\LinkinSwaggerResolverBundle(), new Wakeapp\Bundle\ApiPlatformBundle\WakeappApiPlatformBundle(), ]; return $bundles; } // ... }
Конфигурация
Чтобы начать использовать бандл требуется определить создать и определить guesser
- объект содержащий правила
определения зоны API вашего проекта.
<?php declare(strict_types=1); namespace App\Guesser\ApiAreaGuesser; use Symfony\Component\HttpFoundation\Request; use Wakeapp\Bundle\ApiPlatformBundle\Guesser\ApiAreaGuesserInterface; class ApiAreaGuesser implements ApiAreaGuesserInterface { /** * {@inheritDoc} */ public function getApiVersion(Request $request): ?int { $apiVersionMatch = []; preg_match('/^\/v([\d]+)\//i', $request->getPathInfo(), $apiVersionMatch); if (empty($apiVersionMatch)) { return null; } $apiVersion = (int) end($apiVersionMatch); return $apiVersion; } /** * {@inheritdoc} */ public function isApiRequest(Request $request): bool { return strpos($request->getPathInfo(), '/api') === 0; } }
Примечание: Если вы не используете autowire
то вам необходимо зарегистрировать ApiAreaGuesser
как сервис.
# app/config.yml wakeapp_api_platform: api_area_guesser_service: App\Guesser\ApiAreaGuesser
Полный набор параметров
# app/config.yml wakeapp_api_platform: # полное имя класса DTO для стандартизации ответа api_result_dto_class: Wakeapp\Bundle\ApiPlatformBundle\Dto\ApiResultDto # идентификатор сервиса для определения зоны API api_area_guesser_service: App\Guesser\ApiAreaGuesser # идентификатор сервиса для глобального отлавливания ошибок и выдачи специализированных сообщений вместо 500 error_code_guesser_service: Wakeapp\Bundle\ApiPlatformBundle\Guesser\ApiErrorCodeGuesser # Минимально допустимая версия API. minimal_api_version: 1 # флаг для отладки ошибок - если установлен в true - ответ ошибки содержит trace. response_debug: false
Использование
Использование функционала бандла начинается с создание контроллера и первого метода в указанной зоне API. В качестве примера рассмотрим возвращение простейшего профиля пользователя.
Для начала нам необходимо создать DTO возвращаемых данных:
<?php declare(strict_types=1); namespace App\Dto; use Swagger\Annotations as SWG; use Wakeapp\Component\DtoResolver\Dto\DtoResolverTrait; use Wakeapp\Component\DtoResolver\Dto\DtoResolverInterface; /** * @SWG\Definition( * type="object", * description="Profile info", * required={"email", "firstName", "lastName"}, * ) */ class ProfileResultDto implements DtoResolverInterface { use DtoResolverTrait; /** * @var string * * @SWG\Property(description="Profile email", example="test@gmail.com") */ protected $email; /** * @var string * * @SWG\Property(description="User's first name", example="John") */ protected $firstName; /** * @var string * * @SWG\Property(description="User's last name", example="Doe") */ protected $lastName; /** * @return string */ public function getEmail(): string { return $this->email; } /** * @return string */ public function getFirstName(): string { return $this->firstName; } /** * @return string */ public function getLastName(): string { return $this->lastName; } }
Теперь добавим контроллер с соответствующим методом. Примечание: в качестве примера реализации используется подключение NelmioApiDocBundle.
<?php declare(strict_types=1); namespace App\Controller; use App\Dto\ProfileResultDto; use Nelmio\ApiDocBundle\Annotation\Model; use Swagger\Annotations as SWG; use Symfony\Component\Routing\Annotation\Route; use Wakeapp\Bundle\ApiPlatformBundle\Factory\ApiDtoFactory; use Wakeapp\Bundle\ApiPlatformBundle\HttpFoundation\ApiResponse; /** * @Route("/api/profile") */ class ProfileController { /** * Returns user profile * * @Route(methods={"GET"}) * * @SWG\Response( * response=ApiResponse::HTTP_OK, * description="Successful result in 'data' offset", * @Model(type=ProfileResultDto::class) * ) * * @param ApiDtoFactory $factory * * @return ApiResponse */ public function getProfile(ApiDtoFactory $factory): ApiResponse { // обработка данных $resultDto = $factory->createApiDto(ProfileResultDto::class, [ 'email' => 'test-user@mail.ru', 'firstName' => 'Test', 'lastName' => 'User', ]); return new ApiResponse($resultDto); } }
Дополнительно
Как комбинировать body параметры с query и/или path
Объект на DTO:
<?php declare(strict_types=1); namespace App\Dto; use Swagger\Annotations as SWG; use Wakeapp\Bundle\ApiPlatformBundle\Dto\MagicAwareDtoResolverTrait; use Wakeapp\Component\DtoResolver\Dto\DtoResolverInterface; /** * @SWG\Definition( * type="object", * description="Update profile info", * required={"firstName", "lastName"}, * ) * * @method getEmail(): string */ class UpdateProfileEntryDto implements DtoResolverInterface { use MagicAwareDtoResolverTrait; /** * @var string */ protected $email; /** * @var string * * @SWG\Property(description="User's first name", example="John") */ protected $firstName; /** * @var string * * @SWG\Property(description="User's last name", example="Doe") */ protected $lastName; /** * @return string */ public function getFirstName(): string { return $this->firstName; } /** * @return string */ public function getLastName(): string { return $this->lastName; } }
Контроллер:
<?php declare(strict_types=1); namespace App\Controller; use App\Dto\UpdateProfileEntryDto; use Nelmio\ApiDocBundle\Annotation\Model; use Swagger\Annotations as SWG; use Symfony\Component\Routing\Annotation\Route; use Wakeapp\Bundle\ApiPlatformBundle\HttpFoundation\ApiResponse; /** * @Route("/api/profile") */ class ProfileController { /** * Update user password * * @Route("/{email}", methods={"PATCH"}) * * @SWG\Parameter(name="email", in="path", type="string", required=true, description="User email") * @SWG\Parameter(name="body", in="body", @Model(type=UpdateProfileEntryDto::class), required=true) * * @param UpdateProfileEntryDto $entryDto * * @return ApiResponse */ public function getProfile(UpdateProfileEntryDto $entryDto): ApiResponse { return new ApiResponse($entryDto); } }
Как описать в формат обертки ответа в аннотациях
Чтобы описать формат обертки ответа Wakeapp\Bundle\ApiPlatformBundle\Dto\ApiResultDto
при помощи аннотаций
можно использовать следующий подход:
Шаг 1 Создайте собственный ответ сервера:
<?php declare(strict_types=1); namespace App\Dto; use Swagger\Annotations as SWG; use Wakeapp\Bundle\ApiPlatformBundle\Dto\ApiResultDto as BaseApiResultDto; use Wakeapp\Component\DtoResolver\Dto\DtoResolverInterface; /** * @SWG\Definition( * type="object", * description="Common API response object template", * required={"code", "message"}, * ) */ class ApiResultDto extends BaseApiResultDto { /** * @var int * * @SWG\Property(description="Response api code", example=0, default=0) */ protected $code = 0; /** * @var string * * @SWG\Property(description="Localized human readable text", example="Successfully") */ protected $message; /** * @var DtoResolverInterface|null * * @SWG\Property(type="object", description="Some specific response data or null") */ protected $data = null; }
Шаг 2 Добавьте в конфигурацию:
# app/config.yml wakeapp_api_platform: api_result_dto_class: App\Dto\MyApiResultDto
Шаг 3 Добавьте описание к вашему методу:
<?php declare(strict_types=1); use Nelmio\ApiDocBundle\Annotation\Model; use Swagger\Annotations as SWG; use Wakeapp\Bundle\ApiPlatformBundle\HttpFoundation\ApiRequest; use Wakeapp\Bundle\ApiPlatformBundle\HttpFoundation\ApiResponse; use Wakeapp\Bundle\ApiPlatformBundle\Factory\ApiDtoFactory; class ProfileController { /** * ... * * @SWG\Parameter(name="username", in="query", type="string", required=true, description="User login") * @SWG\Response( * response=ApiResponse::HTTP_OK, * description="Successful result in 'data' offset", * @Model(type=ProfileResultDto::class) * ) * @SWG\Response(response="default", @Model(type=ApiResultDto::class), description="Response wrapper") * * @param ApiRequest $apiRequest * @param ApiDtoFactory $factory * * @return ApiResponse */ public function getProfile(ApiRequest $apiRequest, ApiDtoFactory $factory): ApiResponse { return new ApiResponse(); } }